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
44 static int run = 1;
45
46 static int run2 = 1;
47
48
49 static uint64_t loops;
50
51 static time_t start;
52
53
54 static void
new_session_callback(void * cls,struct SPDY_Session * session)55 new_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
96 static void
session_closed_handler(void * cls,struct SPDY_Session * session,int by_client)97 session_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
120 static void
response_done_callback(void * cls,struct SPDY_Response * response,struct SPDY_Request * request,enum SPDY_RESPONSE_RESULT status,bool streamopened)121 response_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 /*
148 static int
149 print_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 /*
160 void
161 new_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
179 static int
append_headers_to_data(void * cls,const char * name,const char * const * value,int num_values)180 append_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
200 static void
standard_request_handler(void * cls,struct SPDY_Request * request,uint8_t priority,const char * method,const char * path,const char * version,const char * host,const char * scheme,struct SPDY_NameValue * headers,bool more)201 standard_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
272 static int
new_post_data_cb(void * cls,struct SPDY_Request * request,const void * buf,size_t size,bool more)273 new_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
290 static void
sig_handler(int signo)291 sig_handler(int signo)
292 {
293 (void)signo;
294
295 printf("received signal\n");
296 }
297
298
299 int
main(int argc,char * const * argv)300 main (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