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 session_timeout.c
     21  * @brief  tests closing sessions after set timeout. Openssl is used for
     22  * 			client
     23  * @author Andrey Uzunov
     24  */
     25 
     26 #include "platform.h"
     27 #include "microspdy.h"
     28 #include "stdio.h"
     29 #include <sys/wait.h>
     30 #include <ctype.h>
     31 #include "common.h"
     32 #include <sys/time.h>
     33 #include <sys/stat.h>
     34 #include "../microspdy/internal.h"
     35 
     36 #define TIMEOUT 2
     37 #define SELECT_MS_TIMEOUT 20
     38 
     39 int port;
     40 
     41 pid_t parent;
     42 pid_t child;
     43 
     44 int run = 1;
     45 int chunk_size=1;
     46 int new_session;
     47 int closed_session;
     48 int do_sleep;
     49 
     50 
     51 
     52 static unsigned long long
     53 monotonic_time (void)
     54 {
     55 #ifdef HAVE_CLOCK_GETTIME
     56 #ifdef CLOCK_MONOTONIC
     57   struct timespec ts;
     58   if (0 == clock_gettime (CLOCK_MONOTONIC, &ts))
     59     return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
     60 #endif
     61 #endif
     62   return time (NULL) * 1000;
     63 }
     64 
     65 
     66 static void
     67 killchild(char *msg)
     68 {
     69 	printf("%s\n",msg);
     70 	kill(child, SIGKILL);
     71 	exit(1);
     72 }
     73 
     74 
     75 static void
     76 killparent(char *msg)
     77 {
     78 	printf("%s\n",msg);
     79 	kill(parent, SIGKILL);
     80 	_exit(1);
     81 }
     82 
     83 
     84 static void
     85 new_session_cb (void *cls,
     86                 struct SPDY_Session * session)
     87 {
     88   (void)cls;
     89   (void)session;
     90 
     91 	if(!new_session)do_sleep = 1;
     92 	new_session = 1;
     93 	printf("new session\n");
     94 }
     95 
     96 
     97 static void
     98 closed_session_cb (void *cls,
     99                    struct SPDY_Session * session,
    100                    int by_client)
    101 {
    102   (void)cls;
    103   (void)session;
    104 
    105 	printf("closed_session_cb called\n");
    106 
    107 	if(SPDY_YES == by_client)
    108 	{
    109 		killchild("closed by the client");
    110 	}
    111 	if(closed_session)
    112 	{
    113 		killchild("closed_session_cb called twice");
    114 	}
    115 
    116 	closed_session = 1;
    117 }
    118 
    119 
    120 static int
    121 parentproc()
    122 {
    123 	int childstatus;
    124 	unsigned long long timeoutlong=0;
    125 	struct timeval timeout;
    126 	int ret;
    127 	fd_set read_fd_set;
    128 	fd_set write_fd_set;
    129 	fd_set except_fd_set;
    130 	int maxfd = -1;
    131 	struct SPDY_Daemon *daemon;
    132   unsigned long long  beginning = 0;
    133 	unsigned long long now;
    134 
    135 	SPDY_init();
    136 
    137 	daemon = SPDY_start_daemon(port,
    138 								DATA_DIR "cert-and-key.pem",
    139 								DATA_DIR "cert-and-key.pem",
    140 								&new_session_cb,
    141 								&closed_session_cb,
    142 								NULL,
    143 								NULL,
    144 								NULL,
    145 								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
    146 								TIMEOUT,
    147 								SPDY_DAEMON_OPTION_END);
    148 
    149 	if(NULL==daemon){
    150 		printf("no daemon\n");
    151 		return 1;
    152 	}
    153 
    154 	do
    155 	{
    156 		do_sleep=0;
    157 		FD_ZERO(&read_fd_set);
    158 		FD_ZERO(&write_fd_set);
    159 		FD_ZERO(&except_fd_set);
    160 
    161 		ret = SPDY_get_timeout(daemon, &timeoutlong);
    162 
    163 		if(new_session && !closed_session)
    164 		{
    165 			if(SPDY_NO == ret)
    166 			{
    167 				killchild("SPDY_get_timeout returned wrong SPDY_NO");
    168 			}
    169 			/*if(timeoutlong)
    170 			{
    171 				killchild("SPDY_get_timeout returned wrong timeout");
    172 			}*/
    173 			now = monotonic_time ();
    174       if(now - beginning > TIMEOUT*1000 + SELECT_MS_TIMEOUT)
    175       {
    176         printf("Started at: %llums\n",beginning);
    177         printf("Now is: %llums\n",now);
    178         printf("Timeout is: %i\n",TIMEOUT);
    179         printf("Select Timeout is: %ims\n",SELECT_MS_TIMEOUT);
    180         printf("SPDY_get_timeout gave: %llums\n",timeoutlong);
    181 				killchild("Timeout passed but session was not closed");
    182       }
    183       if(timeoutlong > beginning + TIMEOUT *1000)
    184       {
    185         printf("Started at: %llums\n",beginning);
    186         printf("Now is: %llums\n",now);
    187         printf("Timeout is: %i\n",TIMEOUT);
    188         printf("Select Timeout is: %ims\n",SELECT_MS_TIMEOUT);
    189         printf("SPDY_get_timeout gave: %llums\n",timeoutlong);
    190 				killchild("SPDY_get_timeout returned wrong timeout");
    191       }
    192 		}
    193 		else
    194 		{
    195 			if(SPDY_YES == ret)
    196 			{
    197 				killchild("SPDY_get_timeout returned wrong SPDY_YES");
    198 			}
    199 		}
    200 
    201 		if(SPDY_NO == ret || timeoutlong >= 1000)
    202 		{
    203 			timeout.tv_sec = 1;
    204       timeout.tv_usec = 0;
    205 		}
    206 		else
    207 		{
    208 			timeout.tv_sec = timeoutlong / 1000;
    209       timeout.tv_usec = (timeoutlong % 1000) * 1000;
    210 		}
    211 
    212     //ignore values
    213     timeout.tv_sec = 0;
    214     timeout.tv_usec = SELECT_MS_TIMEOUT * 1000;
    215 
    216 		maxfd = SPDY_get_fdset (daemon,
    217 								&read_fd_set,
    218 								&write_fd_set,
    219 								&except_fd_set);
    220 
    221 		ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
    222 
    223 		switch(ret) {
    224 			case -1:
    225 				printf("select error: %i\n", errno);
    226 				break;
    227 			case 0:
    228 				/*if(new_session)
    229 				{
    230 					killchild("select returned wrong number");
    231 				}*/
    232 				break;
    233 			default:
    234 				SPDY_run(daemon);
    235         if(0 == beginning)
    236         {
    237 	  beginning = monotonic_time ();
    238         }
    239 				/*if(do_sleep)
    240 				{
    241 					sleep(TIMEOUT);
    242 					do_sleep = 0;
    243 				}*/
    244 			break;
    245 		}
    246 	}
    247 	while(waitpid(child,&childstatus,WNOHANG) != child);
    248 
    249 	if(!new_session || !closed_session)
    250 	{
    251 		killchild("child is dead, callback wasn't called");
    252 	}
    253 
    254 	ret = SPDY_get_timeout(daemon, &timeoutlong);
    255 
    256 	if(SPDY_YES == ret)
    257 	{
    258 		killchild("SPDY_get_timeout returned wrong SPDY_YES after child died");
    259 	}
    260 
    261 	SPDY_stop_daemon(daemon);
    262 
    263 	SPDY_deinit();
    264 
    265 	return 0;
    266 }
    267 
    268 
    269 static int
    270 childproc()
    271 {
    272 	pid_t devnull;
    273 	int out;
    274 
    275 	out=dup(1);
    276         if (-1 == out)
    277           abort();
    278 	//close(0);
    279 	close(1);
    280 	close(2);
    281 	/*devnull = open("/dev/null", O_RDONLY);
    282 	if (0 != devnull)
    283 	{
    284 		dup2(devnull, 0);
    285 		close(devnull);
    286 	}*/
    287 	devnull = open("/dev/null", O_WRONLY);
    288         if (-1 == devnull)
    289           abort ();
    290 	if (1 != devnull)
    291 	{
    292 		dup2(devnull, 1);
    293 		close(devnull);
    294 	}
    295 	devnull = open("/dev/null", O_WRONLY);
    296         if (-1 == devnull)
    297           abort ();
    298 	if (2 != devnull)
    299 	{
    300 		dup2(devnull, 2);
    301 		close(devnull);
    302 	}
    303 	char *uri;
    304 	asprintf (&uri, "127.0.0.1:%i", port);
    305 	execlp ("openssl", "openssl", "s_client", "-connect", uri, NULL);
    306 	close(1);
    307 	dup2(out,1);
    308 	close(out);
    309 	killparent ("executing openssl failed");
    310 	return 1;
    311 }
    312 
    313 
    314 int
    315 main()
    316 {
    317 	port = get_port(11123);
    318 	parent = getpid();
    319 
    320 	child = fork();
    321 	if (-1 == child)
    322 	{
    323 		fprintf(stderr, "can't fork, error %d\n", errno);
    324 		exit(EXIT_FAILURE);
    325 	}
    326 
    327 	if (child == 0)
    328 	{
    329 		int ret = childproc();
    330 		_exit(ret);
    331 	}
    332 	else
    333 	{
    334 		int ret = parentproc();
    335 		exit(ret);
    336 	}
    337 	return 1;
    338 }
    339