Home | History | Annotate | Download | only in examples
      1 /*
      2     This file is part of libmicrospdy
      3     Copyright Copyright (C) 2012 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 event_loop.c
     21  * @brief  shows how to use the daemon. THIS IS MAINLY A TEST AND DEBUG
     22  * 		 PROGRAM
     23  * @author Andrey Uzunov
     24  */
     25 
     26 #include "platform.h"
     27 #include <unistd.h>
     28 #include <stdlib.h>
     29 #include <stdint.h>
     30 #include <stdbool.h>
     31 #include <string.h>
     32 #include <stdio.h>
     33 #include <ctype.h>
     34 #include <errno.h>
     35 #include "microspdy.h"
     36 #include <sys/time.h>
     37 #include <time.h>
     38 #ifndef MINGW
     39 #include <arpa/inet.h>
     40 #endif
     41 //#include "../framinglayer/structures.h"
     42 //#include "../applicationlayer/alstructures.h"
     43 
     44 static int run = 1;
     45 
     46 static int run2 = 1;
     47 
     48 
     49 static uint64_t loops;
     50 
     51 static time_t start;
     52 
     53 
     54 static void
     55 new_session_callback (void *cls,
     56 						struct SPDY_Session * session)
     57 {
     58   (void)cls;
     59 
     60 	char ipstr[1024];
     61 
     62 	struct sockaddr *addr;
     63 	socklen_t addr_len = SPDY_get_remote_addr(session, &addr);
     64 
     65 	if(!addr_len)
     66 	{
     67 		printf("SPDY_get_remote_addr");
     68 		abort();
     69 	}
     70 
     71 	if(AF_INET == addr->sa_family)
     72 	{
     73 		struct sockaddr_in * addr4 = (struct sockaddr_in *) addr;
     74 		if(NULL == inet_ntop(AF_INET, &(addr4->sin_addr), ipstr, sizeof(ipstr)))
     75 		{
     76 			printf("inet_ntop");
     77 			abort();
     78 		}
     79 		printf("New connection from: %s:%i\n", ipstr, ntohs(addr4->sin_port));
     80 
     81 	}
     82 	else if(AF_INET6 == addr->sa_family)
     83 	{
     84 		struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *) addr;
     85 		if(NULL == inet_ntop(AF_INET6, &(addr6->sin6_addr), ipstr, sizeof(ipstr)))
     86 		{
     87 			printf("inet_ntop");
     88 			abort();
     89 		}
     90 		printf("New connection from: %s:%i\n", ipstr, ntohs(addr6->sin6_port));
     91 
     92 	}
     93 }
     94 
     95 
     96 static void
     97 session_closed_handler (void *cls,
     98 						struct SPDY_Session * session,
     99 						int by_client)
    100 {
    101   (void)cls;
    102   (void)session;
    103 
    104 	//printf("session_closed_handler called\n");
    105 
    106 	if(SPDY_YES != by_client)
    107 	{
    108 		//killchild(child,"wrong by_client");
    109 		printf("session closed by server\n");
    110 	}
    111 	else
    112 	{
    113 		printf("session closed by client\n");
    114 	}
    115 
    116 	//session_closed_called = 1;
    117 }
    118 
    119 
    120 static void
    121 response_done_callback(void *cls,
    122 						struct SPDY_Response *response,
    123 						struct SPDY_Request *request,
    124 						enum SPDY_RESPONSE_RESULT status,
    125 						bool streamopened)
    126 {
    127 	(void)streamopened;
    128 	if(strcmp(cls, "/close (daemon1)") == 0)
    129 		run = 0;
    130 	else {
    131 		if(strcmp(cls, "/close (daemon2)") == 0) run2 = 0;
    132 		loops = 0;
    133 		start = time(NULL);
    134 	}
    135 	if(SPDY_RESPONSE_RESULT_SUCCESS != status)
    136 	{
    137 		printf("not sent frame cause %i", status);
    138 	}
    139 	printf("answer for %s was sent\n", (char*)cls);
    140 	//printf("raw sent headers %s\n", (char *)(response->headers)+8);
    141 
    142 	SPDY_destroy_request(request);
    143 	SPDY_destroy_response(response);
    144 	free(cls);
    145 }
    146 
    147 /*
    148 static int
    149 print_headers (void *cls,
    150                            const char *name, const char *value)
    151 {
    152 	(void)cls;
    153 	printf("%s: %s\n",name,value);
    154 	return SPDY_YES;
    155 }
    156  */
    157 
    158 
    159 /*
    160 void
    161 new_request_cb (void *cls,
    162 						struct SPDY_Request * request,
    163 						uint8_t priority,
    164                         const char *method,
    165                         const char *path,
    166                         const char *version,
    167                         const char *host,
    168                         const char *scheme,
    169 						struct SPDY_NameValue * headers)
    170 {
    171 	(void)cls;
    172 	(void)request;
    173 	printf("Priority: %i\nHTTP headers, scheme: %s\n\n%s %s %s\nHost: %s\n", priority,scheme,method,path,version,host);
    174 	SPDY_name_value_iterate(headers, &print_headers, NULL);
    175 }
    176 */
    177 
    178 
    179 static int
    180 append_headers_to_data (void *cls,
    181                            const char *name, const char * const *value, int num_values)
    182 {
    183 	char **data = cls;
    184 	void *tofree = *data;
    185 	int i;
    186 
    187 	if(num_values)
    188 	for(i=0;i<num_values;++i)
    189 	{
    190 	asprintf(data,"%s%s: %s\n", *data,name,value[i]);
    191 	}
    192 	else
    193 	asprintf(data,"%s%s: \n", *data,name);
    194 
    195 	free(tofree);
    196 	return SPDY_YES;
    197 }
    198 
    199 
    200 static void
    201 standard_request_handler(void *cls,
    202 						struct SPDY_Request * request,
    203 						uint8_t priority,
    204                         const char *method,
    205                         const char *path,
    206                         const char *version,
    207                         const char *host,
    208                         const char *scheme,
    209 						struct SPDY_NameValue * headers,
    210             bool more)
    211 {
    212   (void)more;
    213 
    214 	char *html;
    215 	char *data;
    216 	struct SPDY_Response *response=NULL;
    217 
    218 	printf("received request for '%s %s %s'\n", method, path, version);
    219 	if(strcmp(path,"/main.css")==0)
    220 	{
    221 		if(NULL != cls)
    222 			asprintf(&html,"body{color:green;}");
    223 		else
    224 			asprintf(&html,"body{color:red;}");
    225 
    226 		//struct SPDY_NameValue *headers=SPDY_name_value_create();
    227 		//SPDY_name_value_add(headers,"content-type","text/css");
    228 
    229 		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
    230 		free(html);
    231 	}
    232 	else
    233 	{
    234 		asprintf(&data,"Priority: %i\nHTTP headers, scheme: %s\n\n%s %s %s\nHost: %s\n", priority,scheme,method,path,version,host);
    235 
    236 		SPDY_name_value_iterate(headers, &append_headers_to_data, &data);
    237 
    238 		if(strcmp(path,"/close")==0)
    239 		{
    240 			asprintf(&html,"<html>"
    241 		"<body><b>Closing now!<br>This is an answer to the following "
    242 		"request:</b><br><br><pre>%s</pre></body></html>",data);
    243 		}
    244 		else
    245 		{
    246 			asprintf(&html,"<html><link href=\"main.css\" rel=\"stylesheet\" type=\"text/css\" />"
    247 		"<body><b>This is an answer to the following "
    248 		"request:</b><br><br><pre>%s</pre></body></html>",data);
    249 		}
    250 
    251 		free(data);
    252 
    253 		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
    254 		free(html);
    255 	}
    256 
    257 	if(NULL==response){
    258 		fprintf(stdout,"no response obj\n");
    259 		abort();
    260 	}
    261 
    262 	char *pathcls;
    263 	asprintf(&pathcls, "%s (daemon%i)",path,NULL==cls ? 1 : 2);
    264 	if(SPDY_queue_response(request,response,true,false,&response_done_callback,pathcls)!=SPDY_YES)
    265 	{
    266 		fprintf(stdout,"queue\n");
    267 		abort();
    268 	}
    269 }
    270 
    271 
    272 static int
    273 new_post_data_cb (void * cls,
    274 					 struct SPDY_Request *request,
    275 					 const void * buf,
    276 					 size_t size,
    277 					 bool more)
    278 {
    279   (void)cls;
    280   (void)request;
    281   (void)more;
    282 
    283 	printf("DATA:\n===============================\n");
    284   write(0, buf, size);
    285 	printf("\n===============================\n");
    286   return SPDY_YES;
    287 }
    288 
    289 
    290 static void
    291 sig_handler(int signo)
    292 {
    293   (void)signo;
    294 
    295   printf("received signal\n");
    296 }
    297 
    298 
    299 int
    300 main (int argc, char *const *argv)
    301 {
    302 	if(argc != 2) return 1;
    303 
    304 	#ifndef MINGW
    305 	if (signal(SIGPIPE, sig_handler) == SIG_ERR)
    306 		printf("\ncan't catch SIGPIPE\n");
    307 	#endif
    308 
    309 	SPDY_init();
    310 
    311 	/*
    312   struct sockaddr_in addr4;
    313 	struct in_addr inaddr4;
    314 	inaddr4.s_addr = htonl(INADDR_ANY);
    315 	addr4.sin_family = AF_INET;
    316 	addr4.sin_addr = inaddr4;
    317 	addr4.sin_port = htons(atoi(argv[1]));
    318 	*/
    319 
    320 	struct SPDY_Daemon *daemon = SPDY_start_daemon(atoi(argv[1]),
    321 	 DATA_DIR "cert-and-key.pem",
    322 	 DATA_DIR "cert-and-key.pem",
    323 	&new_session_callback,&session_closed_handler,&standard_request_handler,&new_post_data_cb,NULL,
    324 	SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 10,
    325 	//SPDY_DAEMON_OPTION_SOCK_ADDR,  (struct sockaddr *)&addr4,
    326 	SPDY_DAEMON_OPTION_END);
    327 
    328 	if(NULL==daemon){
    329 		printf("no daemon\n");
    330 		return 1;
    331 	}
    332 
    333   /*
    334 	struct sockaddr_in6 addr6;
    335 	addr6.sin6_family = AF_INET6;
    336 	addr6.sin6_addr = in6addr_any;
    337 	addr6.sin6_port = htons(atoi(argv[1]) + 1);
    338 	*/
    339 
    340 	struct SPDY_Daemon *daemon2 = SPDY_start_daemon(atoi(argv[1]) + 1,
    341 	 DATA_DIR "cert-and-key.pem",
    342 	 DATA_DIR "cert-and-key.pem",
    343 	&new_session_callback,NULL,&standard_request_handler,&new_post_data_cb,&main,
    344 	//SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 0,
    345 	//SPDY_DAEMON_OPTION_SOCK_ADDR,  (struct sockaddr *)&addr6,
    346 	//SPDY_DAEMON_OPTION_FLAGS, SPDY_DAEMON_FLAG_ONLY_IPV6,
    347 	SPDY_DAEMON_OPTION_END);
    348 
    349 	if(NULL==daemon2){
    350 		printf("no daemon\n");
    351 		return 1;
    352 	}
    353 
    354 	do
    355 	{
    356 	unsigned long long timeoutlong=0;
    357 	struct timeval timeout;
    358 	volatile int rc; /* select() return code */
    359 	volatile int ret;
    360 
    361 	fd_set read_fd_set;
    362 	fd_set write_fd_set;
    363 	fd_set except_fd_set;
    364 	int maxfd = -1;
    365 
    366 	if(run && daemon != NULL)
    367 	{
    368 		loops++;
    369 		FD_ZERO(&read_fd_set);
    370 		FD_ZERO(&write_fd_set);
    371 		FD_ZERO(&except_fd_set);
    372 
    373 		ret = SPDY_get_timeout(daemon, &timeoutlong);
    374 		if(SPDY_NO == ret || timeoutlong > 1000)
    375 		{
    376 			timeout.tv_sec = 1;
    377       timeout.tv_usec = 0;
    378 		}
    379 		else
    380 		{
    381 			timeout.tv_sec = timeoutlong / 1000;
    382 			timeout.tv_usec = (timeoutlong % 1000) * 1000;
    383 		}
    384 
    385 		printf("ret=%i; timeoutlong=%llu; sec=%llu; usec=%llu\n", ret, timeoutlong, (long long unsigned)timeout.tv_sec, (long long unsigned)timeout.tv_usec);
    386 		//raise(SIGINT);
    387 
    388 		/* get file descriptors from the transfers */
    389 		maxfd = SPDY_get_fdset (daemon,
    390 		&read_fd_set,
    391 		&write_fd_set,
    392 		&except_fd_set);
    393 
    394 //struct timeval ts1,ts2;
    395     //gettimeofday(&ts1, NULL);
    396 		rc = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
    397     //gettimeofday(&ts2, NULL);
    398     printf("rc %i\n",rc);
    399    // printf("time for select %i\n",ts2.tv_usec - ts1.tv_usec);
    400    // printf("%i %i %i %i\n",ts1.tv_sec, ts1.tv_usec,ts2.tv_sec, ts2.tv_usec);
    401 
    402 		switch(rc) {
    403 			case -1:
    404 				/* select error */
    405 				break;
    406 			case 0:
    407 
    408 				break;
    409 			default:
    410 				SPDY_run(daemon);
    411 
    412 			break;
    413 		}
    414 	}
    415 	else if(daemon != NULL){
    416 
    417 	printf("%lu loops in %llu secs\n", loops, (long long unsigned)(time(NULL) - start));
    418 		SPDY_stop_daemon(daemon);
    419 		daemon=NULL;
    420 	}
    421 
    422 	if(run2)
    423 	{
    424 		FD_ZERO(&read_fd_set);
    425 		FD_ZERO(&write_fd_set);
    426 		FD_ZERO(&except_fd_set);
    427 
    428 		ret = SPDY_get_timeout(daemon2, &timeoutlong);
    429 		//printf("tout %i\n",timeoutlong);
    430 		if(SPDY_NO == ret || timeoutlong > 1)
    431 		{
    432 			//do sth else
    433 			//sleep(1);
    434 
    435 			//try new connection
    436 			timeout.tv_sec = 1;
    437 			timeout.tv_usec = 0;
    438 		}
    439 		else
    440 		{
    441 			timeout.tv_sec = timeoutlong;
    442 			timeout.tv_usec = 0;//(timeoutlong % 1000) * 1000;
    443 		}
    444 
    445 		//printf("ret=%i; timeoutlong=%i; sec=%i; usec=%i\n", ret, timeoutlong, timeout.tv_sec, timeout.tv_usec);
    446 		//raise(SIGINT);
    447 
    448 		/* get file descriptors from the transfers */
    449 		maxfd = SPDY_get_fdset (daemon2,
    450 		&read_fd_set,
    451 		&write_fd_set,
    452 		&except_fd_set);
    453 
    454 		rc = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
    455 
    456 		switch(rc) {
    457 			case -1:
    458 				/* select error */
    459 				break;
    460 			case 0:
    461 
    462 				break;
    463 			default:
    464 				SPDY_run(daemon2);
    465 
    466 				break;
    467 		}
    468 	}
    469 	else if(daemon2 != NULL){
    470 		SPDY_stop_daemon(daemon2);
    471 		daemon2=NULL;
    472 	}
    473 	}
    474 	while(run || run2);
    475 
    476 	if(daemon != NULL){
    477 		SPDY_stop_daemon(daemon);
    478 	}
    479 	if(daemon2 != NULL){
    480 		SPDY_stop_daemon(daemon2);
    481 	}
    482 
    483 	SPDY_deinit();
    484 
    485 	return 0;
    486 }
    487 
    488