/* This file is part of libmicrospdy Copyright Copyright (C) 2013 Andrey Uzunov This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * @file misc.c * @brief tests a lot of small calls and callbacks. TODO mention what * @author Andrey Uzunov */ #include "platform.h" #include "microspdy.h" #include "stdio.h" #include <sys/wait.h> #include "common.h" int port; #define HTML "<html><head>\ <link href=\"main.css\" rel=\"stylesheet\" type=\"text/css\" />\ </head><body>This is libmicrospdy</body></html>" #define CSS "body{font-size:15px}" #define SESSION_CLS "1234567890" #define REQUEST_CLS "1234567890REQ" pid_t parent; pid_t child; struct SPDY_Session *session1; struct SPDY_Session *session2; void killchild() { kill(child, SIGKILL); exit(1); } void killparent() { kill(parent, SIGKILL); _exit(1); } void create_child() { parent = getpid(); child = fork(); if (-1 == child) { fprintf(stderr, "can't fork, error %d\n", errno); exit(EXIT_FAILURE); } if (child == 0) { int devnull; char *uri; fflush(stdout); devnull = open("/dev/null", O_WRONLY); if (-1 == devnull) abort (); if (1 != devnull) { dup2(devnull, 1); close(devnull); } asprintf(&uri,"https://127.0.0.1:%i/",port); execlp("spdycat", "spdycat","-anv",uri,NULL ); printf("execlp failed\n"); killparent(); } } void response_done_callback(void *cls, struct SPDY_Response * response, struct SPDY_Request * request, enum SPDY_RESPONSE_RESULT status, bool streamopened) { (void)status; (void)streamopened; if(strcmp(cls,"/main.css")) { session1 = SPDY_get_session_for_request(request); if(NULL == session1) { printf("SPDY_get_session_for_request failed\n"); killchild(); } char *session_cls = strdup(SESSION_CLS); SPDY_set_cls_to_session(session1,session_cls); } else { session2 = SPDY_get_session_for_request(request); if(session1 != session2) { printf("SPDY_get_session_for_request failed the second time\n"); killchild(); } printf("SPDY_get_session_for_request tested...\n"); void *session_cls = SPDY_get_cls_from_session(session2); if(NULL == session_cls || strcmp(session_cls, SESSION_CLS)) { printf("SPDY_get_cls_from_session failed\n"); killchild(); } printf("SPDY_set_cls_to_session tested...\n"); printf("SPDY_get_cls_from_session tested...\n"); void *request_cls = SPDY_get_cls_from_request(request); if(NULL == request_cls || strcmp(request_cls, REQUEST_CLS)) { printf("SPDY_get_cls_from_request failed\n"); killchild(); } printf("SPDY_set_cls_to_request tested...\n"); printf("SPDY_get_cls_from_request tested...\n"); } SPDY_destroy_request(request); SPDY_destroy_response(response); free(cls); } void standard_request_handler(void *cls, struct SPDY_Request * request, uint8_t priority, const char *method, const char *path, const char *version, const char *host, const char *scheme, struct SPDY_NameValue * headers, bool more) { (void)cls; (void)request; (void)priority; (void)host; (void)scheme; (void)headers; (void)method; (void)version; (void)more; struct SPDY_Response *response=NULL; char *cls_path = strdup(path); if(strcmp(path,"/main.css")==0) { char *request_cls = strdup(REQUEST_CLS); SPDY_set_cls_to_request(request,request_cls); response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,CSS,strlen(CSS)); } else { response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,HTML,strlen(HTML)); } if(NULL==response){ fprintf(stdout,"no response obj\n"); killchild(); } if(SPDY_queue_response(request,response,true,false,&response_done_callback,cls_path)!=SPDY_YES) { fprintf(stdout,"queue\n"); killchild(); } } int parentproc() { int childstatus; unsigned long long timeoutlong=0; struct timeval timeout; int ret; fd_set read_fd_set; fd_set write_fd_set; fd_set except_fd_set; int maxfd = -1; struct SPDY_Daemon *daemon; daemon = SPDY_start_daemon(port, DATA_DIR "cert-and-key.pem", DATA_DIR "cert-and-key.pem", NULL, NULL, &standard_request_handler, NULL, NULL, SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 1800, SPDY_DAEMON_OPTION_END); if(NULL==daemon){ printf("no daemon\n"); return 1; } create_child(); do { FD_ZERO(&read_fd_set); FD_ZERO(&write_fd_set); FD_ZERO(&except_fd_set); ret = SPDY_get_timeout(daemon, &timeoutlong); if(SPDY_NO == ret || timeoutlong > 1000) { timeout.tv_sec = 1; timeout.tv_usec = 0; } else { timeout.tv_sec = timeoutlong / 1000; timeout.tv_usec = (timeoutlong % 1000) * 1000; } maxfd = SPDY_get_fdset (daemon, &read_fd_set, &write_fd_set, &except_fd_set); ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout); switch(ret) { case -1: printf("select error: %i\n", errno); break; case 0: break; default: SPDY_run(daemon); break; } } while(waitpid(child,&childstatus,WNOHANG) != child); SPDY_stop_daemon(daemon); return WEXITSTATUS(childstatus); } int main() { port = get_port(13123); SPDY_init(); int ret = parentproc(); SPDY_deinit(); return ret; }