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