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