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