diff options
Diffstat (limited to 'src/spdy2http')
-rw-r--r-- | src/spdy2http/Makefile.am | 35 | ||||
-rw-r--r-- | src/spdy2http/proxy.c | 625 |
2 files changed, 660 insertions, 0 deletions
diff --git a/src/spdy2http/Makefile.am b/src/spdy2http/Makefile.am new file mode 100644 index 00000000..a8f2536f --- /dev/null +++ b/src/spdy2http/Makefile.am | |||
@@ -0,0 +1,35 @@ | |||
1 | SUBDIRS = . | ||
2 | |||
3 | AM_CFLAGS = -DDATADIR=\"$(top_srcdir)/src/datadir/\" | ||
4 | |||
5 | if USE_COVERAGE | ||
6 | AM_CFLAGS += -fprofile-arcs -ftest-coverage | ||
7 | endif | ||
8 | |||
9 | if USE_PRIVATE_PLIBC_H | ||
10 | PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc | ||
11 | endif | ||
12 | |||
13 | AM_CPPFLAGS = \ | ||
14 | $(PLIBC_INCLUDE) \ | ||
15 | -I$(top_srcdir) \ | ||
16 | -I$(top_srcdir)/src/include \ | ||
17 | -I$(top_srcdir)/src/applicationlayer \ | ||
18 | $(LIBCURL_CPPFLAGS) | ||
19 | |||
20 | if !HAVE_W32 | ||
21 | PERF_GET_CONCURRENT=perf_get_concurrent | ||
22 | endif | ||
23 | |||
24 | bin_PROGRAMS = \ | ||
25 | microspdy2http | ||
26 | |||
27 | microspdy2http_SOURCES = \ | ||
28 | proxy.c | ||
29 | microspdy2http_LDADD = \ | ||
30 | $(top_builddir)/src/microspdy/libmicrospdy.la \ | ||
31 | -lssl \ | ||
32 | -lcrypto \ | ||
33 | -lz \ | ||
34 | -ldl \ | ||
35 | -lcurl | ||
diff --git a/src/spdy2http/proxy.c b/src/spdy2http/proxy.c new file mode 100644 index 00000000..f1513680 --- /dev/null +++ b/src/spdy2http/proxy.c | |||
@@ -0,0 +1,625 @@ | |||
1 | /* | ||
2 | This file is part of libmicrospdy | ||
3 | 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 proxy.c | ||
21 | * @brief Translates incoming SPDY requests to http server on localhost. | ||
22 | * Uses libcurl. | ||
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 <curl/curl.h> | ||
37 | #include <assert.h> | ||
38 | |||
39 | |||
40 | #define PRINT_INFO(msg) do{\ | ||
41 | printf("%i:%s\n", __LINE__, msg);\ | ||
42 | fflush(stdout);\ | ||
43 | }\ | ||
44 | while(0) | ||
45 | |||
46 | |||
47 | #define PRINT_INFO2(fmt, ...) do{\ | ||
48 | printf("%i\n", __LINE__);\ | ||
49 | printf(fmt,##__VA_ARGS__);\ | ||
50 | printf("\n");\ | ||
51 | fflush(stdout);\ | ||
52 | }\ | ||
53 | while(0) | ||
54 | |||
55 | |||
56 | #define CURL_SETOPT(handle, opt, val) do{\ | ||
57 | int ret; \ | ||
58 | if(CURLE_OK != (ret = curl_easy_setopt(handle, opt, val))) \ | ||
59 | { \ | ||
60 | PRINT_INFO2("curl_easy_setopt failed (%i = %i)", opt, ret); \ | ||
61 | abort(); \ | ||
62 | } \ | ||
63 | }\ | ||
64 | while(0) | ||
65 | |||
66 | |||
67 | int run = 1; | ||
68 | char* http_host; | ||
69 | CURLM *multi_handle; | ||
70 | int still_running = 0; /* keep number of running handles */ | ||
71 | int http10=0; | ||
72 | |||
73 | struct Proxy | ||
74 | { | ||
75 | char *path; | ||
76 | struct SPDY_Request *request; | ||
77 | struct SPDY_Response *response; | ||
78 | CURL *curl_handle; | ||
79 | struct curl_slist *curl_headers; | ||
80 | struct SPDY_NameValue *headers; | ||
81 | char *version; | ||
82 | char *status_msg; | ||
83 | void *http_body; | ||
84 | size_t http_body_size; | ||
85 | ssize_t length; | ||
86 | int status; | ||
87 | }; | ||
88 | |||
89 | |||
90 | ssize_t | ||
91 | response_callback (void *cls, | ||
92 | void *buffer, | ||
93 | size_t max, | ||
94 | bool *more) | ||
95 | { | ||
96 | int ret; | ||
97 | struct Proxy *proxy = (struct Proxy *)cls; | ||
98 | void *newbody; | ||
99 | |||
100 | //printf("response_callback\n"); | ||
101 | |||
102 | assert(0 != proxy->length); | ||
103 | |||
104 | *more = true; | ||
105 | if(!proxy->http_body_size)//nothing to write now | ||
106 | return 0; | ||
107 | |||
108 | if(max >= proxy->http_body_size) | ||
109 | { | ||
110 | ret = proxy->http_body_size; | ||
111 | newbody = NULL; | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | ret = max; | ||
116 | if(NULL == (newbody = malloc(proxy->http_body_size - max))) | ||
117 | { | ||
118 | PRINT_INFO("no memory"); | ||
119 | return -1; | ||
120 | } | ||
121 | memcpy(newbody, proxy->http_body + max, proxy->http_body_size - max); | ||
122 | } | ||
123 | memcpy(buffer, proxy->http_body, ret); | ||
124 | free(proxy->http_body); | ||
125 | proxy->http_body = newbody; | ||
126 | proxy->http_body_size -= ret; | ||
127 | |||
128 | if(proxy->length >= 0) | ||
129 | { | ||
130 | proxy->length -= ret; | ||
131 | //printf("pr len %i", proxy->length); | ||
132 | if(proxy->length <= 0) | ||
133 | { | ||
134 | *more = false; | ||
135 | //last frame | ||
136 | proxy->length = 0; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | |||
144 | void | ||
145 | response_done_callback(void *cls, | ||
146 | struct SPDY_Response *response, | ||
147 | struct SPDY_Request *request, | ||
148 | enum SPDY_RESPONSE_RESULT status, | ||
149 | bool streamopened) | ||
150 | { | ||
151 | (void)streamopened; | ||
152 | struct Proxy *proxy = (struct Proxy *)cls; | ||
153 | int ret; | ||
154 | |||
155 | //printf("response_done_callback\n"); | ||
156 | |||
157 | //printf("answer for %s was sent\n", (char *)cls); | ||
158 | |||
159 | if(SPDY_RESPONSE_RESULT_SUCCESS != status) | ||
160 | { | ||
161 | printf("answer was NOT sent, %i\n",status); | ||
162 | } | ||
163 | if(CURLM_OK != (ret = curl_multi_remove_handle(multi_handle, proxy->curl_handle))) | ||
164 | { | ||
165 | PRINT_INFO2("curl_multi_remove_handle failed (%i)", ret); | ||
166 | } | ||
167 | curl_slist_free_all(proxy->curl_headers); | ||
168 | curl_easy_cleanup(proxy->curl_handle); | ||
169 | |||
170 | SPDY_destroy_request(request); | ||
171 | SPDY_destroy_response(response); | ||
172 | if(!strcmp("/close",proxy->path)) run = 0; | ||
173 | free(proxy->path); | ||
174 | free(proxy); | ||
175 | } | ||
176 | |||
177 | |||
178 | static size_t | ||
179 | curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | ||
180 | { | ||
181 | size_t realsize = size * nmemb; | ||
182 | struct Proxy *proxy = (struct Proxy *)userp; | ||
183 | char *line = (char *)ptr; | ||
184 | char *name; | ||
185 | char *value; | ||
186 | char *status; | ||
187 | const char *const*length; | ||
188 | int i; | ||
189 | int pos; | ||
190 | |||
191 | //printf("curl_header_cb\n"); | ||
192 | |||
193 | if('\r' == line[0]) | ||
194 | { | ||
195 | //all headers were already handled; prepare spdy frames | ||
196 | if(NULL == (proxy->response = SPDY_build_response_with_callback(proxy->status, | ||
197 | proxy->status_msg, | ||
198 | proxy->version, | ||
199 | proxy->headers, | ||
200 | &response_callback, | ||
201 | proxy, | ||
202 | 0))) | ||
203 | { | ||
204 | PRINT_INFO("no response"); | ||
205 | abort(); | ||
206 | } | ||
207 | if(NULL != (length = SPDY_name_value_lookup(proxy->headers, | ||
208 | SPDY_HTTP_HEADER_CONTENT_LENGTH, | ||
209 | &i))) | ||
210 | proxy->length = atoi(length[0]); | ||
211 | else | ||
212 | proxy->length = -1; | ||
213 | SPDY_name_value_destroy(proxy->headers); | ||
214 | free(proxy->status_msg); | ||
215 | free(proxy->version); | ||
216 | |||
217 | if(SPDY_YES != SPDY_queue_response(proxy->request, | ||
218 | proxy->response, | ||
219 | true, | ||
220 | false, | ||
221 | &response_done_callback, | ||
222 | proxy)) | ||
223 | { | ||
224 | PRINT_INFO("no queue"); | ||
225 | abort(); | ||
226 | } | ||
227 | //printf("spdy headers queued %i\n"); | ||
228 | |||
229 | return realsize; | ||
230 | } | ||
231 | |||
232 | pos = 0; | ||
233 | if(NULL == proxy->version) | ||
234 | { | ||
235 | //first line from headers | ||
236 | //version | ||
237 | for(i=pos; i<realsize && ' '!=line[i]; ++i); | ||
238 | if(i == realsize) | ||
239 | { | ||
240 | PRINT_INFO("error on parsing headers"); | ||
241 | abort(); | ||
242 | } | ||
243 | if(NULL == (proxy->version = strndup(line, i - pos))) | ||
244 | { | ||
245 | PRINT_INFO("no memory"); | ||
246 | abort(); | ||
247 | } | ||
248 | pos = i+1; | ||
249 | |||
250 | //status (number) | ||
251 | for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i]; ++i); | ||
252 | if(NULL == (status = strndup(&(line[pos]), i - pos))) | ||
253 | { | ||
254 | PRINT_INFO("no memory"); | ||
255 | abort(); | ||
256 | } | ||
257 | proxy->status = atoi(status); | ||
258 | free(status); | ||
259 | if(i<realsize && '\r'!=line[i]) | ||
260 | { | ||
261 | //status (message) | ||
262 | pos = i+1; | ||
263 | for(i=pos; i<realsize && '\r'!=line[i]; ++i); | ||
264 | if(NULL == (proxy->status_msg = strndup(&(line[pos]), i - pos))) | ||
265 | { | ||
266 | PRINT_INFO("no memory"); | ||
267 | abort(); | ||
268 | } | ||
269 | } | ||
270 | return realsize; | ||
271 | } | ||
272 | |||
273 | //other lines | ||
274 | //header name | ||
275 | for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i]; ++i) | ||
276 | line[i] = tolower(line[i]); //spdy requires lower case | ||
277 | if(NULL == (name = strndup(line, i - pos))) | ||
278 | { | ||
279 | PRINT_INFO("no memory"); | ||
280 | abort(); | ||
281 | } | ||
282 | if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name) | ||
283 | || 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name)) | ||
284 | { | ||
285 | //forbidden in spdy, ignore | ||
286 | free(name); | ||
287 | return realsize; | ||
288 | } | ||
289 | if(i == realsize || '\r'==line[i]) | ||
290 | { | ||
291 | //no value. is it possible? | ||
292 | if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, "")) | ||
293 | { | ||
294 | PRINT_INFO("SPDY_name_value_add failed"); | ||
295 | abort(); | ||
296 | } | ||
297 | return realsize; | ||
298 | } | ||
299 | |||
300 | //header value | ||
301 | pos = i+1; | ||
302 | while(pos<realsize && isspace(line[pos])) ++pos; //remove leading space | ||
303 | for(i=pos; i<realsize && '\r'!=line[i]; ++i); | ||
304 | if(NULL == (value = strndup(&(line[pos]), i - pos))) | ||
305 | { | ||
306 | PRINT_INFO("no memory"); | ||
307 | abort(); | ||
308 | } | ||
309 | if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, value)) | ||
310 | { | ||
311 | PRINT_INFO("SPDY_name_value_add failed"); | ||
312 | abort(); | ||
313 | } | ||
314 | free(name); | ||
315 | free(value); | ||
316 | |||
317 | return realsize; | ||
318 | } | ||
319 | |||
320 | |||
321 | static size_t | ||
322 | curl_write_cb(void *contents, size_t size, size_t nmemb, void *userp) | ||
323 | { | ||
324 | size_t realsize = size * nmemb; | ||
325 | struct Proxy *proxy = (struct Proxy *)userp; | ||
326 | |||
327 | //printf("curl_write_cb %i\n", realsize); | ||
328 | |||
329 | if(NULL == proxy->http_body) | ||
330 | proxy->http_body = malloc(realsize); | ||
331 | else | ||
332 | proxy->http_body = realloc(proxy->http_body, proxy->http_body_size + realsize); | ||
333 | if(NULL == proxy->http_body) | ||
334 | { | ||
335 | PRINT_INFO("not enough memory (realloc returned NULL)"); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | memcpy(proxy->http_body + proxy->http_body_size, contents, realsize); | ||
340 | proxy->http_body_size += realsize; | ||
341 | |||
342 | return realsize; | ||
343 | } | ||
344 | |||
345 | |||
346 | int | ||
347 | iterate_cb (void *cls, const char *name, const char * const * value, int num_values) | ||
348 | { | ||
349 | struct Proxy *proxy = (struct Proxy *)cls; | ||
350 | struct curl_slist **curl_headers = (&(proxy->curl_headers)); | ||
351 | char *line; | ||
352 | int line_len = strlen(name) + 3; //+ ": \0" | ||
353 | int i; | ||
354 | |||
355 | for(i=0; i<num_values; ++i) | ||
356 | { | ||
357 | if(i) line_len += 2; //", " | ||
358 | line_len += strlen(value[i]); | ||
359 | } | ||
360 | |||
361 | if(NULL == (line = malloc(line_len))) | ||
362 | { | ||
363 | //no recovory | ||
364 | PRINT_INFO("no memory"); | ||
365 | abort(); | ||
366 | } | ||
367 | line[0] = 0; | ||
368 | |||
369 | strcat(line, name); | ||
370 | strcat(line, ": "); | ||
371 | //all spdy header names are lower case; | ||
372 | //for simplicity here we just capitalize the first letter | ||
373 | line[0] = toupper(line[0]); | ||
374 | |||
375 | for(i=0; i<num_values; ++i) | ||
376 | { | ||
377 | if(i) strcat(line, ", "); | ||
378 | strcat(line, value[i]); | ||
379 | } | ||
380 | if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line))) | ||
381 | { | ||
382 | PRINT_INFO("curl_slist_append failed"); | ||
383 | abort(); | ||
384 | } | ||
385 | free(line); | ||
386 | |||
387 | return SPDY_YES; | ||
388 | } | ||
389 | |||
390 | |||
391 | void | ||
392 | standard_request_handler(void *cls, | ||
393 | struct SPDY_Request * request, | ||
394 | uint8_t priority, | ||
395 | const char *method, | ||
396 | const char *path, | ||
397 | const char *version, | ||
398 | const char *host, | ||
399 | const char *scheme, | ||
400 | struct SPDY_NameValue * headers) | ||
401 | { | ||
402 | (void)cls; | ||
403 | (void)priority; | ||
404 | (void)host; | ||
405 | (void)scheme; | ||
406 | |||
407 | char *url; | ||
408 | struct Proxy *proxy; | ||
409 | int ret; | ||
410 | |||
411 | //printf("received request for '%s %s %s'\n", method, path, version); | ||
412 | if(NULL == (proxy = malloc(sizeof(struct Proxy)))) | ||
413 | { | ||
414 | PRINT_INFO("No memory"); | ||
415 | abort(); | ||
416 | } | ||
417 | memset(proxy, 0, sizeof(struct Proxy)); | ||
418 | proxy->request = request; | ||
419 | if(NULL == (proxy->headers = SPDY_name_value_create())) | ||
420 | { | ||
421 | PRINT_INFO("No memory"); | ||
422 | abort(); | ||
423 | } | ||
424 | |||
425 | if(-1 == asprintf(&url,"%s%s%s","http://", http_host, path)) | ||
426 | { | ||
427 | PRINT_INFO("No memory"); | ||
428 | abort(); | ||
429 | } | ||
430 | |||
431 | if(NULL == (proxy->path = strdup(path))) | ||
432 | { | ||
433 | PRINT_INFO("No memory"); | ||
434 | abort(); | ||
435 | } | ||
436 | |||
437 | SPDY_name_value_iterate(headers, &iterate_cb, proxy); | ||
438 | |||
439 | if(NULL == (proxy->curl_handle = curl_easy_init())) | ||
440 | { | ||
441 | PRINT_INFO("curl_easy_init failed"); | ||
442 | abort(); | ||
443 | } | ||
444 | |||
445 | //CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1); | ||
446 | CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, url); | ||
447 | free(url); | ||
448 | if(http10) | ||
449 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
450 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb); | ||
451 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy); | ||
452 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERFUNCTION, curl_header_cb); | ||
453 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERDATA, proxy); | ||
454 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTPHEADER, proxy->curl_headers); | ||
455 | CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); | ||
456 | CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); | ||
457 | |||
458 | if(CURLM_OK != (ret = curl_multi_add_handle(multi_handle, proxy->curl_handle))) | ||
459 | { | ||
460 | PRINT_INFO2("curl_multi_add_handle failed (%i)", ret); | ||
461 | abort(); | ||
462 | } | ||
463 | |||
464 | if(CURLM_OK != (ret = curl_multi_perform(multi_handle, &still_running)) | ||
465 | && CURLM_CALL_MULTI_PERFORM != ret) | ||
466 | { | ||
467 | PRINT_INFO2("curl_multi_perform failed (%i)", ret); | ||
468 | abort(); | ||
469 | } | ||
470 | } | ||
471 | |||
472 | int | ||
473 | main (int argc, char *const *argv) | ||
474 | { | ||
475 | unsigned long long timeoutlong=0; | ||
476 | long curl_timeo = -1; | ||
477 | struct timeval timeout; | ||
478 | int ret; | ||
479 | fd_set rs; | ||
480 | fd_set ws; | ||
481 | fd_set es; | ||
482 | fd_set curl_rs; | ||
483 | fd_set curl_ws; | ||
484 | fd_set curl_es; | ||
485 | int maxfd = -1; | ||
486 | struct SPDY_Daemon *daemon; | ||
487 | |||
488 | //signal(SIGPIPE, SIG_IGN); | ||
489 | |||
490 | if(argc != 6) | ||
491 | { | ||
492 | printf("Usage: %s cert-file key-file host port http/1.0(yes/no)\n", argv[0]); | ||
493 | return 1; | ||
494 | } | ||
495 | |||
496 | SPDY_init(); | ||
497 | |||
498 | daemon = SPDY_start_daemon(atoi(argv[4]), | ||
499 | argv[1], | ||
500 | argv[2], | ||
501 | NULL, | ||
502 | NULL, | ||
503 | &standard_request_handler, | ||
504 | NULL, | ||
505 | NULL, | ||
506 | SPDY_DAEMON_OPTION_SESSION_TIMEOUT, | ||
507 | 1800, | ||
508 | SPDY_DAEMON_OPTION_END); | ||
509 | |||
510 | if(NULL==daemon){ | ||
511 | printf("no daemon\n"); | ||
512 | return 1; | ||
513 | } | ||
514 | |||
515 | multi_handle = curl_multi_init(); | ||
516 | |||
517 | if(NULL==multi_handle){ | ||
518 | PRINT_INFO("no multi_handle"); | ||
519 | abort(); | ||
520 | } | ||
521 | |||
522 | if(!strcmp("yes", argv[5])) | ||
523 | http10 = 1; | ||
524 | |||
525 | http_host = argv[3]; | ||
526 | timeout.tv_usec = 0; | ||
527 | |||
528 | do | ||
529 | { | ||
530 | //printf("still %i\n", still_running); | ||
531 | FD_ZERO(&rs); | ||
532 | FD_ZERO(&ws); | ||
533 | FD_ZERO(&es); | ||
534 | FD_ZERO(&curl_rs); | ||
535 | FD_ZERO(&curl_ws); | ||
536 | FD_ZERO(&curl_es); | ||
537 | |||
538 | if(still_running > 0) | ||
539 | timeout.tv_sec = 0; //return immediately | ||
540 | else | ||
541 | { | ||
542 | ret = SPDY_get_timeout(daemon, &timeoutlong); | ||
543 | if(SPDY_NO == ret) | ||
544 | timeout.tv_sec = 1; | ||
545 | else | ||
546 | timeout.tv_sec = timeoutlong; | ||
547 | } | ||
548 | timeout.tv_usec = 0; | ||
549 | |||
550 | maxfd = SPDY_get_fdset (daemon, | ||
551 | &rs, | ||
552 | &ws, | ||
553 | &es); | ||
554 | assert(-1 != maxfd); | ||
555 | |||
556 | ret = select(maxfd+1, &rs, &ws, &es, &timeout); | ||
557 | |||
558 | switch(ret) { | ||
559 | case -1: | ||
560 | PRINT_INFO2("select error: %i", errno); | ||
561 | break; | ||
562 | case 0: | ||
563 | break; | ||
564 | default: | ||
565 | SPDY_run(daemon); | ||
566 | break; | ||
567 | } | ||
568 | |||
569 | timeout.tv_sec = 0; | ||
570 | if(still_running > 0) | ||
571 | { | ||
572 | if(CURLM_OK != (ret = curl_multi_timeout(multi_handle, &curl_timeo))) | ||
573 | { | ||
574 | PRINT_INFO2("curl_multi_timeout failed (%i)", ret); | ||
575 | abort(); | ||
576 | } | ||
577 | if(curl_timeo >= 0 && curl_timeo < 500) | ||
578 | timeout.tv_usec = curl_timeo * 1000; | ||
579 | else | ||
580 | timeout.tv_usec = 500000; | ||
581 | } | ||
582 | else continue; | ||
583 | //else timeout.tv_usec = 500000; | ||
584 | |||
585 | if(CURLM_OK != (ret = curl_multi_fdset(multi_handle, &curl_rs, &curl_ws, &curl_es, &maxfd))) | ||
586 | { | ||
587 | PRINT_INFO2("curl_multi_fdset failed (%i)", ret); | ||
588 | abort(); | ||
589 | } | ||
590 | if(-1 == maxfd) | ||
591 | { | ||
592 | PRINT_INFO("maxfd is -1"); | ||
593 | //continue; | ||
594 | ret = 0; | ||
595 | } | ||
596 | else | ||
597 | ret = select(maxfd+1, &curl_rs, &curl_ws, &curl_es, &timeout); | ||
598 | |||
599 | switch(ret) { | ||
600 | case -1: | ||
601 | PRINT_INFO2("select error: %i", errno); | ||
602 | break; | ||
603 | case 0: /* timeout */ | ||
604 | //break or not | ||
605 | default: /* action */ | ||
606 | if(CURLM_OK != (ret = curl_multi_perform(multi_handle, &still_running)) | ||
607 | && CURLM_CALL_MULTI_PERFORM != ret) | ||
608 | { | ||
609 | PRINT_INFO2("curl_multi_perform failed (%i)", ret); | ||
610 | abort(); | ||
611 | } | ||
612 | break; | ||
613 | } | ||
614 | } | ||
615 | while(run); | ||
616 | |||
617 | curl_multi_cleanup(multi_handle); | ||
618 | |||
619 | SPDY_stop_daemon(daemon); | ||
620 | |||
621 | SPDY_deinit(); | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||