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 44static int run = 1; 45 46static int run2 = 1; 47 48 49static uint64_t loops; 50 51static time_t start; 52 53 54static void 55new_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 96static void 97session_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 120static void 121response_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/* 148static int 149print_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/* 160void 161new_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 179static int 180append_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 200static void 201standard_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 272static int 273new_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 290static void 291sig_handler(int signo) 292{ 293 (void)signo; 294 295 printf("received signal\n"); 296} 297 298 299int 300main (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