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 misc.c
21 * @brief  tests a lot of small calls and callbacks. TODO mention what
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "microspdy.h"
27#include "stdio.h"
28#include <sys/wait.h>
29#include "common.h"
30
31int port;
32
33#define HTML "<html><head>\
34<link href=\"main.css\" rel=\"stylesheet\" type=\"text/css\" />\
35</head><body>This is libmicrospdy</body></html>"
36
37#define CSS "body{font-size:15px}"
38
39#define SESSION_CLS "1234567890"
40
41#define REQUEST_CLS "1234567890REQ"
42
43pid_t parent;
44pid_t child;
45
46struct SPDY_Session *session1;
47struct SPDY_Session *session2;
48
49void
50killchild()
51{
52	kill(child, SIGKILL);
53	exit(1);
54}
55
56void
57killparent()
58{
59	kill(parent, SIGKILL);
60	_exit(1);
61}
62
63
64void
65create_child()
66{
67	parent = getpid();
68
69	child = fork();
70	if (-1 == child)
71	{
72		fprintf(stderr, "can't fork, error %d\n", errno);
73		exit(EXIT_FAILURE);
74	}
75
76	if (child == 0)
77	{
78		int devnull;
79		char *uri;
80		fflush(stdout);
81		devnull = open("/dev/null", O_WRONLY);
82                if (-1 == devnull)
83                  abort ();
84		if (1 != devnull)
85		{
86			dup2(devnull, 1);
87			close(devnull);
88		}
89		asprintf(&uri,"https://127.0.0.1:%i/",port);
90		execlp("spdycat", "spdycat","-anv",uri,NULL );
91		printf("execlp failed\n");
92		killparent();
93	}
94}
95
96void
97response_done_callback(void *cls,
98								struct SPDY_Response * response,
99								struct SPDY_Request * request,
100								enum SPDY_RESPONSE_RESULT status,
101						bool streamopened)
102{
103  (void)status;
104  (void)streamopened;
105
106	if(strcmp(cls,"/main.css"))
107	{
108		session1 = SPDY_get_session_for_request(request);
109		if(NULL == session1)
110		{
111			printf("SPDY_get_session_for_request failed\n");
112			killchild();
113		}
114
115		char *session_cls = strdup(SESSION_CLS);
116		SPDY_set_cls_to_session(session1,session_cls);
117	}
118	else
119	{
120		session2 = SPDY_get_session_for_request(request);
121		if(session1 != session2)
122		{
123			printf("SPDY_get_session_for_request failed the second time\n");
124			killchild();
125		}
126		printf("SPDY_get_session_for_request tested...\n");
127
128		void *session_cls = SPDY_get_cls_from_session(session2);
129		if(NULL == session_cls || strcmp(session_cls, SESSION_CLS))
130		{
131			printf("SPDY_get_cls_from_session failed\n");
132			killchild();
133		}
134		printf("SPDY_set_cls_to_session tested...\n");
135		printf("SPDY_get_cls_from_session tested...\n");
136
137		void *request_cls = SPDY_get_cls_from_request(request);
138		if(NULL == request_cls || strcmp(request_cls, REQUEST_CLS))
139		{
140			printf("SPDY_get_cls_from_request failed\n");
141			killchild();
142		}
143		printf("SPDY_set_cls_to_request tested...\n");
144		printf("SPDY_get_cls_from_request tested...\n");
145	}
146
147	SPDY_destroy_request(request);
148	SPDY_destroy_response(response);
149	free(cls);
150}
151
152void
153standard_request_handler(void *cls,
154						struct SPDY_Request * request,
155						uint8_t priority,
156                        const char *method,
157                        const char *path,
158                        const char *version,
159                        const char *host,
160                        const char *scheme,
161						struct SPDY_NameValue * headers,
162            bool more)
163{
164	(void)cls;
165	(void)request;
166	(void)priority;
167	(void)host;
168	(void)scheme;
169	(void)headers;
170	(void)method;
171	(void)version;
172	(void)more;
173
174	struct SPDY_Response *response=NULL;
175	char *cls_path = strdup(path);
176
177	if(strcmp(path,"/main.css")==0)
178	{
179		char *request_cls = strdup(REQUEST_CLS);
180		SPDY_set_cls_to_request(request,request_cls);
181		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,CSS,strlen(CSS));
182	}
183	else
184	{
185		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,HTML,strlen(HTML));
186	}
187
188	if(NULL==response){
189		fprintf(stdout,"no response obj\n");
190		killchild();
191	}
192
193	if(SPDY_queue_response(request,response,true,false,&response_done_callback,cls_path)!=SPDY_YES)
194	{
195		fprintf(stdout,"queue\n");
196		killchild();
197	}
198}
199
200int
201parentproc()
202{
203	int childstatus;
204	unsigned long long timeoutlong=0;
205	struct timeval timeout;
206	int ret;
207	fd_set read_fd_set;
208	fd_set write_fd_set;
209	fd_set except_fd_set;
210	int maxfd = -1;
211	struct SPDY_Daemon *daemon;
212
213	daemon = SPDY_start_daemon(port,
214								DATA_DIR "cert-and-key.pem",
215								DATA_DIR "cert-and-key.pem",
216								NULL,
217								NULL,
218								&standard_request_handler,
219								NULL,
220								NULL,
221								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
222								1800,
223								SPDY_DAEMON_OPTION_END);
224
225	if(NULL==daemon){
226		printf("no daemon\n");
227		return 1;
228	}
229
230	create_child();
231
232	do
233	{
234		FD_ZERO(&read_fd_set);
235		FD_ZERO(&write_fd_set);
236		FD_ZERO(&except_fd_set);
237
238		ret = SPDY_get_timeout(daemon, &timeoutlong);
239		if(SPDY_NO == ret || timeoutlong > 1000)
240		{
241			timeout.tv_sec = 1;
242      timeout.tv_usec = 0;
243		}
244		else
245		{
246			timeout.tv_sec = timeoutlong / 1000;
247			timeout.tv_usec = (timeoutlong % 1000) * 1000;
248		}
249
250		maxfd = SPDY_get_fdset (daemon,
251								&read_fd_set,
252								&write_fd_set,
253								&except_fd_set);
254
255		ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
256
257		switch(ret) {
258			case -1:
259				printf("select error: %i\n", errno);
260				break;
261			case 0:
262
263				break;
264			default:
265				SPDY_run(daemon);
266
267			break;
268		}
269	}
270	while(waitpid(child,&childstatus,WNOHANG) != child);
271
272	SPDY_stop_daemon(daemon);
273
274	return WEXITSTATUS(childstatus);
275}
276
277
278int
279main()
280{
281	port = get_port(13123);
282	SPDY_init();
283
284	int ret = parentproc();
285
286	SPDY_deinit();
287
288	return ret;
289}
290