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 39int port; 40 41pid_t parent; 42pid_t child; 43 44int run = 1; 45int chunk_size=1; 46int new_session; 47int closed_session; 48int do_sleep; 49 50 51 52static unsigned long long 53monotonic_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 66static void 67killchild(char *msg) 68{ 69 printf("%s\n",msg); 70 kill(child, SIGKILL); 71 exit(1); 72} 73 74 75static void 76killparent(char *msg) 77{ 78 printf("%s\n",msg); 79 kill(parent, SIGKILL); 80 _exit(1); 81} 82 83 84static void 85new_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 97static void 98closed_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 120static int 121parentproc() 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 269static int 270childproc() 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 314int 315main() 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