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 request_response_with_callback.c
21 * @brief tests responses with callbacks
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 <ctype.h>
30 #include "common.h"
31 #include <sys/time.h>
32 #include <sys/stat.h>
33
34 int port;
35
36 pid_t parent;
37 pid_t child;
38
39 int run = 1;
40 int chunk_size=1;
41
42 void
killchild()43 killchild()
44 {
45 kill(child, SIGKILL);
46 exit(1);
47 }
48
49 void
killparent()50 killparent()
51 {
52 kill(parent, SIGKILL);
53 _exit(1);
54 }
55
56 ssize_t
response_callback(void * cls,void * buffer,size_t max,bool * more)57 response_callback (void *cls,
58 void *buffer,
59 size_t max,
60 bool *more)
61 {
62 FILE *fd =(FILE*)cls;
63
64 size_t n;
65 if(chunk_size % 2)
66 n = chunk_size;
67 else
68 n = max - chunk_size;
69
70 if(n < 1) n = 1;
71 else if (n > max) n=max;
72 chunk_size++;
73
74 int ret = fread(buffer,1,n,fd);
75 *more = feof(fd) == 0;
76
77 //printf("more is %i\n",*more);
78
79 if(!(*more))
80 fclose(fd);
81
82 return ret;
83 }
84
85
86 void
response_done_callback(void * cls,struct SPDY_Response * response,struct SPDY_Request * request,enum SPDY_RESPONSE_RESULT status,bool streamopened)87 response_done_callback(void *cls,
88 struct SPDY_Response * response,
89 struct SPDY_Request * request,
90 enum SPDY_RESPONSE_RESULT status,
91 bool streamopened)
92 {
93 (void)status;
94 (void)streamopened;
95
96 printf("answer for %s was sent\n", (char*)cls);
97
98 SPDY_destroy_request(request);
99 SPDY_destroy_response(response);
100 free(cls);
101
102 run = 0;
103 }
104
105 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)106 standard_request_handler(void *cls,
107 struct SPDY_Request * request,
108 uint8_t priority,
109 const char *method,
110 const char *path,
111 const char *version,
112 const char *host,
113 const char *scheme,
114 struct SPDY_NameValue * headers,
115 bool more)
116 {
117 (void)cls;
118 (void)request;
119 (void)priority;
120 (void)host;
121 (void)scheme;
122 (void)headers;
123 (void)method;
124 (void)version;
125 (void)more;
126
127 struct SPDY_Response *response=NULL;
128 struct SPDY_NameValue *resp_headers;
129
130 printf("received request for '%s %s %s'\n", method, path, version);
131
132 FILE *fd = fopen(DATA_DIR "spdy-draft.txt","r");
133
134 if(NULL == (resp_headers = SPDY_name_value_create()))
135 {
136 fprintf(stdout,"SPDY_name_value_create failed\n");
137 killchild();
138 }
139 if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,"text/plain"))
140 {
141 fprintf(stdout,"SPDY_name_value_add failed\n");
142 killchild();
143 }
144
145 response = SPDY_build_response_with_callback(200,NULL,
146 SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
147 SPDY_name_value_destroy(resp_headers);
148
149 if(NULL==response){
150 fprintf(stdout,"no response obj\n");
151 killchild();
152 }
153
154 void *clspath = strdup(path);
155
156 if(SPDY_queue_response(request,response,true,false,&response_done_callback,clspath)!=SPDY_YES)
157 {
158 fprintf(stdout,"queue\n");
159 killchild();
160 }
161 }
162
163 int
parentproc()164 parentproc()
165 {
166 int childstatus;
167 unsigned long long timeoutlong=0;
168 struct timeval timeout;
169 int ret;
170 fd_set read_fd_set;
171 fd_set write_fd_set;
172 fd_set except_fd_set;
173 int maxfd = -1;
174 struct SPDY_Daemon *daemon;
175
176 SPDY_init();
177
178 daemon = SPDY_start_daemon(port,
179 DATA_DIR "cert-and-key.pem",
180 DATA_DIR "cert-and-key.pem",
181 NULL,
182 NULL,
183 &standard_request_handler,
184 NULL,
185 NULL,
186 SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
187 1800,
188 SPDY_DAEMON_OPTION_END);
189
190 if(NULL==daemon){
191 printf("no daemon\n");
192 return 1;
193 }
194
195 do
196 {
197 FD_ZERO(&read_fd_set);
198 FD_ZERO(&write_fd_set);
199 FD_ZERO(&except_fd_set);
200
201 ret = SPDY_get_timeout(daemon, &timeoutlong);
202 if(SPDY_NO == ret || timeoutlong > 1000)
203 {
204 timeout.tv_sec = 1;
205 timeout.tv_usec = 0;
206 }
207 else
208 {
209 timeout.tv_sec = timeoutlong / 1000;
210 timeout.tv_usec = (timeoutlong % 1000) * 1000;
211 }
212
213 maxfd = SPDY_get_fdset (daemon,
214 &read_fd_set,
215 &write_fd_set,
216 &except_fd_set);
217
218 ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
219
220 switch(ret) {
221 case -1:
222 printf("select error: %i\n", errno);
223 break;
224 case 0:
225
226 break;
227 default:
228 SPDY_run(daemon);
229
230 break;
231 }
232 }
233 while(waitpid(child,&childstatus,WNOHANG) != child);
234
235 SPDY_stop_daemon(daemon);
236
237 SPDY_deinit();
238
239 return WEXITSTATUS(childstatus);
240 }
241
242 #define MD5_LEN 32
243
244 int
md5(char * cmd,char * md5_sum)245 md5(char *cmd, char *md5_sum)
246 {
247 FILE *p = popen(cmd, "r");
248 if (p == NULL) return 0;
249
250 int i, ch;
251 for (i = 0; i < MD5_LEN && isxdigit(ch = fgetc(p)); i++) {
252 *md5_sum++ = ch;
253 }
254
255 *md5_sum = '\0';
256 pclose(p);
257 return i == MD5_LEN;
258 }
259
260 int
childproc()261 childproc()
262 {
263 char *cmd1;
264 char *cmd2;
265 char md5_sum1[33];
266 char md5_sum2[33];
267 int ret;
268 struct timeval tv1;
269 struct timeval tv2;
270 struct stat st;
271 //int secs;
272 uint64_t usecs;
273
274 asprintf(&cmd1, "spdycat https://127.0.0.1:%i/ | md5sum",port);
275 asprintf(&cmd2, "md5sum " DATA_DIR "spdy-draft.txt");
276
277 gettimeofday(&tv1, NULL);
278 md5(cmd1,md5_sum1);
279 gettimeofday(&tv2, NULL);
280 md5(cmd2,md5_sum2);
281
282 printf("downloaded file md5: %s\n", md5_sum1);
283 printf("original file md5: %s\n", md5_sum2);
284 ret = strcmp(md5_sum1, md5_sum2);
285
286 if(0 == ret && 0 == stat(DATA_DIR "spdy-draft.txt", &st))
287 {
288 usecs = (uint64_t)1000000 * (uint64_t)(tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec;
289 printf("%lld bytes read in %llu usecs\n", (long long)st.st_size, (long long unsigned )usecs);
290 }
291
292 return ret;
293 }
294
295
296 int
main()297 main()
298 {
299 port = get_port(11123);
300 parent = getpid();
301
302 child = fork();
303 if (-1 == child)
304 {
305 fprintf(stderr, "can't fork, error %d\n", errno);
306 exit(EXIT_FAILURE);
307 }
308
309 if (child == 0)
310 {
311 int ret = childproc();
312 _exit(ret);
313 }
314 else
315 {
316 int ret = parentproc();
317 exit(ret);
318 }
319 return 1;
320 }
321