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 
31 int 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 
43 pid_t parent;
44 pid_t child;
45 
46 struct SPDY_Session *session1;
47 struct SPDY_Session *session2;
48 
49 void
killchild()50 killchild()
51 {
52 	kill(child, SIGKILL);
53 	exit(1);
54 }
55 
56 void
killparent()57 killparent()
58 {
59 	kill(parent, SIGKILL);
60 	_exit(1);
61 }
62 
63 
64 void
create_child()65 create_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 
96 void
response_done_callback(void * cls,struct SPDY_Response * response,struct SPDY_Request * request,enum SPDY_RESPONSE_RESULT status,bool streamopened)97 response_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 
152 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)153 standard_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 
200 int
parentproc()201 parentproc()
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 
278 int
main()279 main()
280 {
281 	port = get_port(13123);
282 	SPDY_init();
283 
284 	int ret = parentproc();
285 
286 	SPDY_deinit();
287 
288 	return ret;
289 }
290