Home | History | Annotate | Download | only in testspdy
      1 /*
      2     This file is part of libmicrospdy
      3     Copyright Copyright (C) 2013 Andrey Uzunov
      4 
      5     This program is free software: you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation, either version 3 of the License, or
      8     (at your option) any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 
     15     You should have received a copy of the GNU General Public License
     16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 */
     18 
     19 /**
     20  * @file request_response_with_callback.c
     21  * @brief  tests responses with callbacks
     22  * @author Andrey Uzunov
     23  */
     24 
     25 #include "platform.h"
     26 #include "microspdy.h"
     27 #include "stdio.h"
     28 #include <sys/wait.h>
     29 #include <ctype.h>
     30 #include "common.h"
     31 #include <sys/time.h>
     32 #include <sys/stat.h>
     33 
     34 int port;
     35 
     36 pid_t parent;
     37 pid_t child;
     38 
     39 int run = 1;
     40 int chunk_size=1;
     41 
     42 void
     43 killchild()
     44 {
     45 	kill(child, SIGKILL);
     46 	exit(1);
     47 }
     48 
     49 void
     50 killparent()
     51 {
     52 	kill(parent, SIGKILL);
     53 	_exit(1);
     54 }
     55 
     56 ssize_t
     57 response_callback (void *cls,
     58 						void *buffer,
     59 						size_t max,
     60 						bool *more)
     61 {
     62 	FILE *fd =(FILE*)cls;
     63 
     64 	size_t n;
     65 	if(chunk_size % 2)
     66 		n = chunk_size;
     67 	else
     68 		n = max - chunk_size;
     69 
     70 	if(n < 1) n = 1;
     71 	else if (n > max) n=max;
     72 	chunk_size++;
     73 
     74 	int ret = fread(buffer,1,n,fd);
     75 	*more = feof(fd) == 0;
     76 
     77 	//printf("more is %i\n",*more);
     78 
     79 	if(!(*more))
     80 		fclose(fd);
     81 
     82 	return ret;
     83 }
     84 
     85 
     86 void
     87 response_done_callback(void *cls,
     88 								struct SPDY_Response * response,
     89 								struct SPDY_Request * request,
     90 								enum SPDY_RESPONSE_RESULT status,
     91 						bool streamopened)
     92 {
     93   (void)status;
     94   (void)streamopened;
     95 
     96 	printf("answer for %s was sent\n", (char*)cls);
     97 
     98 	SPDY_destroy_request(request);
     99 	SPDY_destroy_response(response);
    100 	free(cls);
    101 
    102 	run = 0;
    103 }
    104 
    105 void
    106 standard_request_handler(void *cls,
    107 						struct SPDY_Request * request,
    108 						uint8_t priority,
    109                         const char *method,
    110                         const char *path,
    111                         const char *version,
    112                         const char *host,
    113                         const char *scheme,
    114 						struct SPDY_NameValue * headers,
    115             bool more)
    116 {
    117 	(void)cls;
    118 	(void)request;
    119 	(void)priority;
    120 	(void)host;
    121 	(void)scheme;
    122 	(void)headers;
    123 	(void)method;
    124 	(void)version;
    125 	(void)more;
    126 
    127 	struct SPDY_Response *response=NULL;
    128 	struct SPDY_NameValue *resp_headers;
    129 
    130 	printf("received request for '%s %s %s'\n", method, path, version);
    131 
    132 		FILE *fd = fopen(DATA_DIR "spdy-draft.txt","r");
    133 
    134 		if(NULL == (resp_headers = SPDY_name_value_create()))
    135 		{
    136 			fprintf(stdout,"SPDY_name_value_create failed\n");
    137 			killchild();
    138 		}
    139 		if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,"text/plain"))
    140 		{
    141 			fprintf(stdout,"SPDY_name_value_add failed\n");
    142 			killchild();
    143 		}
    144 
    145 		response = SPDY_build_response_with_callback(200,NULL,
    146 			SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
    147 		SPDY_name_value_destroy(resp_headers);
    148 
    149 	if(NULL==response){
    150 		fprintf(stdout,"no response obj\n");
    151 			killchild();
    152 	}
    153 
    154 	void *clspath = strdup(path);
    155 
    156 	if(SPDY_queue_response(request,response,true,false,&response_done_callback,clspath)!=SPDY_YES)
    157 	{
    158 		fprintf(stdout,"queue\n");
    159 			killchild();
    160 	}
    161 }
    162 
    163 int
    164 parentproc()
    165 {
    166 	int childstatus;
    167 	unsigned long long timeoutlong=0;
    168 	struct timeval timeout;
    169 	int ret;
    170 	fd_set read_fd_set;
    171 	fd_set write_fd_set;
    172 	fd_set except_fd_set;
    173 	int maxfd = -1;
    174 	struct SPDY_Daemon *daemon;
    175 
    176 	SPDY_init();
    177 
    178 	daemon = SPDY_start_daemon(port,
    179 								DATA_DIR "cert-and-key.pem",
    180 								DATA_DIR "cert-and-key.pem",
    181 								NULL,
    182 								NULL,
    183 								&standard_request_handler,
    184 								NULL,
    185 								NULL,
    186 								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
    187 								1800,
    188 								SPDY_DAEMON_OPTION_END);
    189 
    190 	if(NULL==daemon){
    191 		printf("no daemon\n");
    192 		return 1;
    193 	}
    194 
    195 	do
    196 	{
    197 		FD_ZERO(&read_fd_set);
    198 		FD_ZERO(&write_fd_set);
    199 		FD_ZERO(&except_fd_set);
    200 
    201 		ret = SPDY_get_timeout(daemon, &timeoutlong);
    202 		if(SPDY_NO == ret || timeoutlong > 1000)
    203 		{
    204 			timeout.tv_sec = 1;
    205       timeout.tv_usec = 0;
    206 		}
    207 		else
    208 		{
    209 			timeout.tv_sec = timeoutlong / 1000;
    210 			timeout.tv_usec = (timeoutlong % 1000) * 1000;
    211 		}
    212 
    213 		maxfd = SPDY_get_fdset (daemon,
    214 								&read_fd_set,
    215 								&write_fd_set,
    216 								&except_fd_set);
    217 
    218 		ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
    219 
    220 		switch(ret) {
    221 			case -1:
    222 				printf("select error: %i\n", errno);
    223 				break;
    224 			case 0:
    225 
    226 				break;
    227 			default:
    228 				SPDY_run(daemon);
    229 
    230 			break;
    231 		}
    232 	}
    233 	while(waitpid(child,&childstatus,WNOHANG) != child);
    234 
    235 	SPDY_stop_daemon(daemon);
    236 
    237 	SPDY_deinit();
    238 
    239 	return WEXITSTATUS(childstatus);
    240 }
    241 
    242 #define MD5_LEN 32
    243 
    244 int
    245 md5(char *cmd, char *md5_sum)
    246 {
    247     FILE *p = popen(cmd, "r");
    248     if (p == NULL) return 0;
    249 
    250     int i, ch;
    251     for (i = 0; i < MD5_LEN && isxdigit(ch = fgetc(p)); i++) {
    252         *md5_sum++ = ch;
    253     }
    254 
    255     *md5_sum = '\0';
    256     pclose(p);
    257     return i == MD5_LEN;
    258 }
    259 
    260 int
    261 childproc()
    262 {
    263 	char *cmd1;
    264 	char *cmd2;
    265 	char md5_sum1[33];
    266 	char md5_sum2[33];
    267 	int ret;
    268 	struct timeval tv1;
    269 	struct timeval tv2;
    270 	struct stat st;
    271 	//int secs;
    272 	uint64_t usecs;
    273 
    274 	asprintf(&cmd1, "spdycat https://127.0.0.1:%i/ | md5sum",port);
    275 	asprintf(&cmd2, "md5sum " DATA_DIR "spdy-draft.txt");
    276 
    277 	gettimeofday(&tv1, NULL);
    278 	md5(cmd1,md5_sum1);
    279 	gettimeofday(&tv2, NULL);
    280 	md5(cmd2,md5_sum2);
    281 
    282 	printf("downloaded file md5: %s\n", md5_sum1);
    283 	printf("original   file md5: %s\n", md5_sum2);
    284 	ret = strcmp(md5_sum1, md5_sum2);
    285 
    286 	if(0 == ret && 0 == stat(DATA_DIR "spdy-draft.txt", &st))
    287 	{
    288 		usecs = (uint64_t)1000000 * (uint64_t)(tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec;
    289 		printf("%lld bytes read in %llu usecs\n", (long long)st.st_size, (long long unsigned )usecs);
    290 	}
    291 
    292 	return ret;
    293 }
    294 
    295 
    296 int
    297 main()
    298 {
    299 	port = get_port(11123);
    300 	parent = getpid();
    301 
    302 	child = fork();
    303 	if (-1 == child)
    304 	{
    305 		fprintf(stderr, "can't fork, error %d\n", errno);
    306 		exit(EXIT_FAILURE);
    307 	}
    308 
    309 	if (child == 0)
    310 	{
    311 		int ret = childproc();
    312 		_exit(ret);
    313 	}
    314 	else
    315 	{
    316 		int ret = parentproc();
    317 		exit(ret);
    318 	}
    319 	return 1;
    320 }
    321