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