• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
monotonic_time(void)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
killchild(char * msg)67 killchild(char *msg)
68 {
69 	printf("%s\n",msg);
70 	kill(child, SIGKILL);
71 	exit(1);
72 }
73 
74 
75 static void
killparent(char * msg)76 killparent(char *msg)
77 {
78 	printf("%s\n",msg);
79 	kill(parent, SIGKILL);
80 	_exit(1);
81 }
82 
83 
84 static void
new_session_cb(void * cls,struct SPDY_Session * session)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
closed_session_cb(void * cls,struct SPDY_Session * session,int by_client)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
parentproc()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
childproc()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
main()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