diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-07-19 09:19:48 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-07-19 09:19:48 +0000 |
commit | 3b384315bcb2710490bfff676544b5872957f739 (patch) | |
tree | e4340910b0a8d413ed3e9bf588d601e1fc60acc3 | |
parent | 32d7b92ba70509405f78b80711ef142391b63bd6 (diff) | |
download | libmicrohttpd-3b384315bcb2710490bfff676544b5872957f739.tar.gz libmicrohttpd-3b384315bcb2710490bfff676544b5872957f739.zip |
-importing Andrey Uzunov's mhd2spdy code
-rw-r--r-- | src/examples/Makefile.am | 15 | ||||
-rw-r--r-- | src/examples/mhd2spdy.c | 323 | ||||
-rw-r--r-- | src/examples/mhd2spdy_http.c | 450 | ||||
-rw-r--r-- | src/examples/mhd2spdy_http.h | 43 | ||||
-rw-r--r-- | src/examples/mhd2spdy_spdy.c | 908 | ||||
-rw-r--r-- | src/examples/mhd2spdy_spdy.h | 67 | ||||
-rw-r--r-- | src/examples/mhd2spdy_structures.c | 149 | ||||
-rw-r--r-- | src/examples/mhd2spdy_structures.h | 265 | ||||
-rw-r--r-- | src/microhttpd/connection.c | 2 | ||||
-rw-r--r-- | src/microspdy/io_raw.c | 4 |
10 files changed, 2224 insertions, 2 deletions
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am index 070ccf94..0f4b3d6d 100644 --- a/src/examples/Makefile.am +++ b/src/examples/Makefile.am | |||
@@ -19,7 +19,11 @@ if ENABLE_SPDY | |||
19 | spdyex = \ | 19 | spdyex = \ |
20 | spdy_event_loop \ | 20 | spdy_event_loop \ |
21 | spdy_fileserver \ | 21 | spdy_fileserver \ |
22 | spdy_response_with_callback | 22 | spdy_response_with_callback |
23 | |||
24 | if HAVE_SPDYLAY | ||
25 | spdyex += mhd2spdy | ||
26 | endif | ||
23 | endif | 27 | endif |
24 | 28 | ||
25 | 29 | ||
@@ -74,6 +78,15 @@ demo_LDADD = \ | |||
74 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | 78 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ |
75 | -lmagic | 79 | -lmagic |
76 | 80 | ||
81 | mhd2spdy_SOURCES = \ | ||
82 | mhd2spdy.c \ | ||
83 | mhd2spdy_spdy.c mhd2spdy_spdy.h \ | ||
84 | mhd2spdy_http.c mhd2spdy_http.h \ | ||
85 | mhd2spdy_structures.c mhd2spdy_structures.h | ||
86 | mhd2spdy_LDADD = \ | ||
87 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | ||
88 | -lssl -lcrypto -lspdylay | ||
89 | |||
77 | benchmark_SOURCES = \ | 90 | benchmark_SOURCES = \ |
78 | benchmark.c | 91 | benchmark.c |
79 | benchmark_LDADD = \ | 92 | benchmark_LDADD = \ |
diff --git a/src/examples/mhd2spdy.c b/src/examples/mhd2spdy.c new file mode 100644 index 00000000..507641c2 --- /dev/null +++ b/src/examples/mhd2spdy.c | |||
@@ -0,0 +1,323 @@ | |||
1 | /* | ||
2 | Copyright (C) 2013 Andrey Uzunov | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file structures.h | ||
20 | * @author Andrey Uzunov | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * TODOs | ||
25 | * non blocking SSL connect | ||
26 | * check certificate | ||
27 | * | ||
28 | * | ||
29 | * | ||
30 | * | ||
31 | |||
32 | |||
33 | */ | ||
34 | |||
35 | #include "mhd2spdy_structures.h" | ||
36 | #include "mhd2spdy_spdy.h" | ||
37 | #include "mhd2spdy_http.h" | ||
38 | |||
39 | static int run = 1; | ||
40 | //static int spdy_close = 0; | ||
41 | |||
42 | static void catch_signal(int signal) | ||
43 | { | ||
44 | //spdy_close = 1; | ||
45 | run = 0; | ||
46 | } | ||
47 | |||
48 | int | ||
49 | run_everything () | ||
50 | { | ||
51 | unsigned long long timeoutlong=0; | ||
52 | struct timeval timeout; | ||
53 | int ret; | ||
54 | fd_set rs; | ||
55 | fd_set ws; | ||
56 | fd_set es; | ||
57 | int maxfd = -1; | ||
58 | int maxfd_s = -1; | ||
59 | struct MHD_Daemon *daemon; | ||
60 | nfds_t spdy_npollfds = 1; | ||
61 | //struct pollfd spdy_pollfds[MAX_SPDY_CONNECTIONS]; | ||
62 | struct URI * spdy2http_uri = NULL; | ||
63 | //int spdy_nfds; | ||
64 | //int spdylay_timeout = 0; | ||
65 | struct SPDY_Connection *connection; | ||
66 | struct SPDY_Connection *connections[MAX_SPDY_CONNECTIONS]; | ||
67 | struct SPDY_Connection *connection_for_delete; | ||
68 | |||
69 | if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) | ||
70 | PRINT_INFO("signal failed"); | ||
71 | |||
72 | if (signal(SIGINT, catch_signal) == SIG_ERR) | ||
73 | PRINT_INFO("signal failed"); | ||
74 | |||
75 | //spdy2http_url = argv[2]; | ||
76 | glob_opt.streams_opened = 0; | ||
77 | glob_opt.responses_pending = 0; | ||
78 | glob_opt.global_memory = 0; | ||
79 | //spdy_proto_version = 0; | ||
80 | |||
81 | srand(time(NULL)); | ||
82 | |||
83 | if(init_parse_uri(&glob_opt.uri_preg)) | ||
84 | DIE("Regexp compilation failed"); | ||
85 | |||
86 | |||
87 | if(NULL != glob_opt.spdy2http_str) | ||
88 | { | ||
89 | ret = parse_uri(&glob_opt.uri_preg, glob_opt.spdy2http_str, &spdy2http_uri); | ||
90 | if(ret != 0) | ||
91 | DIE("spdy_parse_uri failed"); | ||
92 | } | ||
93 | |||
94 | SSL_load_error_strings(); | ||
95 | SSL_library_init(); | ||
96 | glob_opt.ssl_ctx = SSL_CTX_new(SSLv23_client_method()); | ||
97 | if(glob_opt.ssl_ctx == NULL) { | ||
98 | PRINT_INFO2("SSL_CTX_new %s", ERR_error_string(ERR_get_error(), NULL)); | ||
99 | abort(); | ||
100 | } | ||
101 | spdy_ssl_init_ssl_ctx(glob_opt.ssl_ctx, &glob_opt.spdy_proto_version); | ||
102 | |||
103 | daemon = MHD_start_daemon ( | ||
104 | MHD_SUPPRESS_DATE_NO_CLOCK, | ||
105 | glob_opt.listen_port, | ||
106 | NULL, NULL, &http_cb_request, NULL, | ||
107 | MHD_OPTION_URI_LOG_CALLBACK, &http_log_cb, NULL, | ||
108 | MHD_OPTION_END); | ||
109 | if(NULL==daemon) | ||
110 | DIE("MHD_start_daemon failed"); | ||
111 | |||
112 | |||
113 | do | ||
114 | { | ||
115 | |||
116 | timeout.tv_sec = 0; | ||
117 | timeout.tv_usec = 0; | ||
118 | |||
119 | if(NULL == glob_opt.spdy_connection && NULL != glob_opt.spdy2http_str) | ||
120 | { | ||
121 | glob_opt.spdy_connection = spdy_connect(spdy2http_uri, spdy2http_uri->port, strcmp("https", spdy2http_uri->scheme)==0); | ||
122 | if(NULL == glob_opt.spdy_connection && glob_opt.only_proxy) | ||
123 | PRINT_INFO("cannot connect to the proxy"); | ||
124 | } | ||
125 | |||
126 | //PRINT_INFO("while1"); | ||
127 | FD_ZERO(&rs); | ||
128 | FD_ZERO(&ws); | ||
129 | FD_ZERO(&es); | ||
130 | |||
131 | /*if(glob_opt.spdy_data_received) | ||
132 | { | ||
133 | timeout.tv_sec = 0; | ||
134 | timeout.tv_usec = 0; | ||
135 | glob_opt.spdy_data_received = false; | ||
136 | } | ||
137 | else{*/ | ||
138 | /*if(glob_opt.responses_pending || glob_opt.streams_opened)// TODO only streams_opened true? | ||
139 | timeout.tv_usec = 0; //return immediately | ||
140 | else | ||
141 | {*/ | ||
142 | ret = MHD_get_timeout(daemon, &timeoutlong); | ||
143 | if(MHD_NO == ret || timeoutlong > 5000) | ||
144 | timeout.tv_sec = 5; | ||
145 | else | ||
146 | { | ||
147 | timeout.tv_sec = timeoutlong / 1000; | ||
148 | timeout.tv_usec = (timeoutlong % 1000) * 1000; | ||
149 | } | ||
150 | //} | ||
151 | //} | ||
152 | if(MHD_NO == MHD_get_fdset (daemon, | ||
153 | &rs, | ||
154 | &ws, | ||
155 | &es, | ||
156 | &maxfd)) | ||
157 | { | ||
158 | PRINT_INFO("MHD_get_fdset error"); | ||
159 | } | ||
160 | assert(-1 != maxfd); | ||
161 | |||
162 | maxfd_s = spdy_get_selectfdset( | ||
163 | &rs, | ||
164 | &ws, | ||
165 | &es, | ||
166 | connections, MAX_SPDY_CONNECTIONS, &spdy_npollfds); | ||
167 | if(maxfd_s > maxfd) maxfd = maxfd_s; | ||
168 | |||
169 | PRINT_INFO2("MHD timeout %i %i", timeout.tv_sec, timeout.tv_usec); | ||
170 | //TODO | ||
171 | //timeout.tv_sec = 0; | ||
172 | //timeout.tv_usec = 0; | ||
173 | |||
174 | glob_opt.spdy_data_received = false; | ||
175 | |||
176 | ret = select(maxfd+1, &rs, &ws, &es, &timeout); | ||
177 | PRINT_INFO2("timeout now %i %i", timeout.tv_sec, timeout.tv_usec); | ||
178 | |||
179 | switch(ret) { | ||
180 | case -1: | ||
181 | PRINT_INFO2("select error: %i", errno); | ||
182 | break; | ||
183 | case 0: | ||
184 | break; | ||
185 | default: | ||
186 | PRINT_INFO("run"); | ||
187 | MHD_run_from_select(daemon,&rs, &ws, &es); | ||
188 | spdy_run_select(&rs, &ws, &es, connections, spdy_npollfds); | ||
189 | if(glob_opt.spdy_data_received) | ||
190 | { | ||
191 | PRINT_INFO("MHD run again"); | ||
192 | MHD_run_from_select(daemon,&rs, &ws, &es); | ||
193 | } | ||
194 | break; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | //if(glob_opt.streams_opened) spdylay_timeout = 500; | ||
199 | //if(glob_opt.responses_pending || glob_opt.streams_opened) spdylay_timeout = 0; | ||
200 | //else spdylay_timeout = 0; | ||
201 | //else spdylay_timeout = 0; | ||
202 | |||
203 | spdy_get_pollfdset(spdy_pollfds, connections, MAX_SPDY_CONNECTIONS, &spdy_npollfds); | ||
204 | |||
205 | //TODO | ||
206 | //spdylay_timeout = 0; | ||
207 | |||
208 | PRINT_INFO2("spdylay timeout %i", spdylay_timeout); | ||
209 | ret = poll(spdy_pollfds, spdy_npollfds, spdylay_timeout); | ||
210 | if(ret == -1) | ||
211 | DIE("poll"); | ||
212 | if(ret > 0){ | ||
213 | PRINT_INFO("spdy_run"); | ||
214 | spdy_run(spdy_pollfds, connections, spdy_npollfds); | ||
215 | }*/ | ||
216 | } | ||
217 | while(run); | ||
218 | |||
219 | //TODO exit from loop and clean | ||
220 | |||
221 | MHD_stop_daemon (daemon); | ||
222 | |||
223 | //TODO SSL_free brakes | ||
224 | spdy_free_connection(glob_opt.spdy_connection); | ||
225 | |||
226 | connection = glob_opt.spdy_connections_head; | ||
227 | while(NULL != connection) | ||
228 | { | ||
229 | connection_for_delete = connection; | ||
230 | connection = connection_for_delete->next; | ||
231 | glob_opt.streams_opened -= connection_for_delete->streams_opened; | ||
232 | DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection_for_delete); | ||
233 | spdy_free_connection(connection_for_delete); | ||
234 | } | ||
235 | |||
236 | free_uri(spdy2http_uri); | ||
237 | |||
238 | deinit_parse_uri(&glob_opt.uri_preg); | ||
239 | |||
240 | SSL_CTX_free(glob_opt.ssl_ctx); | ||
241 | ERR_free_strings(); | ||
242 | EVP_cleanup(); | ||
243 | |||
244 | PRINT_INFO2("spdy streams: %i; http requests: %i", glob_opt.streams_opened, glob_opt.responses_pending); | ||
245 | PRINT_INFO2("memory allocated %zu bytes", glob_opt.global_memory); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | void | ||
251 | display_usage() | ||
252 | { | ||
253 | printf( | ||
254 | "Usage: http2spdy [-vo] [-b <SPDY2HTTP-PROXY>] -p <PORT>\n" | ||
255 | "TODO\n" | ||
256 | ); | ||
257 | } | ||
258 | |||
259 | |||
260 | int | ||
261 | main (int argc, | ||
262 | char *const *argv) | ||
263 | { | ||
264 | int getopt_ret; | ||
265 | int option_index; | ||
266 | struct option long_options[] = { | ||
267 | {"port", required_argument, 0, 'p'}, | ||
268 | {"backend-proxy", required_argument, 0, 'b'}, | ||
269 | {"verbose", no_argument, 0, 'v'}, | ||
270 | {"only-proxy", no_argument, 0, 'o'}, | ||
271 | {0, 0, 0, 0} | ||
272 | }; | ||
273 | |||
274 | while (1) | ||
275 | { | ||
276 | getopt_ret = getopt_long( argc, argv, "p:b:vo", long_options, &option_index); | ||
277 | if (getopt_ret == -1) | ||
278 | break; | ||
279 | |||
280 | switch(getopt_ret) | ||
281 | { | ||
282 | case 'p': | ||
283 | glob_opt.listen_port = atoi(optarg); | ||
284 | break; | ||
285 | |||
286 | case 'b': | ||
287 | glob_opt.spdy2http_str = strdup(optarg); | ||
288 | if(NULL == glob_opt.spdy2http_str) | ||
289 | return 1; | ||
290 | break; | ||
291 | |||
292 | case 'v': | ||
293 | glob_opt.verbose = true; | ||
294 | break; | ||
295 | |||
296 | case 'o': | ||
297 | glob_opt.only_proxy = true; | ||
298 | break; | ||
299 | |||
300 | case 0: | ||
301 | PRINT_INFO("0 from getopt"); | ||
302 | break; | ||
303 | |||
304 | case '?': | ||
305 | display_usage(); | ||
306 | return 1; | ||
307 | |||
308 | default: | ||
309 | DIE("default from getopt"); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | if( | ||
314 | 0 == glob_opt.listen_port | ||
315 | || (glob_opt.only_proxy && NULL == glob_opt.spdy2http_str) | ||
316 | ) | ||
317 | { | ||
318 | display_usage(); | ||
319 | return 1; | ||
320 | } | ||
321 | |||
322 | return run_everything(); | ||
323 | } | ||
diff --git a/src/examples/mhd2spdy_http.c b/src/examples/mhd2spdy_http.c new file mode 100644 index 00000000..5f788524 --- /dev/null +++ b/src/examples/mhd2spdy_http.c | |||
@@ -0,0 +1,450 @@ | |||
1 | /* | ||
2 | Copyright (C) 2013 Andrey Uzunov | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file structures.h | ||
20 | * @author Andrey Uzunov | ||
21 | */ | ||
22 | |||
23 | #include "mhd2spdy_structures.h" | ||
24 | #include "mhd2spdy_http.h" | ||
25 | #include "mhd2spdy_spdy.h" | ||
26 | |||
27 | |||
28 | void * http_log_cb(void * cls, const char * uri) | ||
29 | { | ||
30 | struct HTTP_URI * http_uri; | ||
31 | |||
32 | PRINT_INFO2("log uri '%s'\n", uri); | ||
33 | |||
34 | if(NULL == (http_uri = au_malloc(sizeof(struct HTTP_URI )))) | ||
35 | DIE("no memory"); | ||
36 | //memset(http_uri, 0 , sizeof(struct HTTP_URI)); | ||
37 | http_uri->uri = strdup(uri); | ||
38 | return http_uri; | ||
39 | } | ||
40 | |||
41 | |||
42 | /* | ||
43 | static int | ||
44 | http_query_iterate_cb(void *cls, | ||
45 | enum MHD_ValueKind kind, | ||
46 | const char *name, const char *value) | ||
47 | { | ||
48 | |||
49 | }*/ | ||
50 | |||
51 | |||
52 | static int | ||
53 | http_iterate_cb(void *cls, | ||
54 | enum MHD_ValueKind kind, | ||
55 | const char *name, const char *value) | ||
56 | { | ||
57 | static char * const forbidden[] = {"Transfer-Encoding", | ||
58 | "Proxy-Connection", | ||
59 | "Keep-Alive", | ||
60 | "Connection"}; | ||
61 | static int forbidden_size = 4; | ||
62 | int i; | ||
63 | struct SPDY_Headers *spdy_headers = (struct SPDY_Headers *)cls; | ||
64 | |||
65 | if(0 == strcasecmp(name, "Host")) | ||
66 | spdy_headers->nv[9] = (char *)value; | ||
67 | else | ||
68 | { | ||
69 | for(i=0; i<forbidden_size; ++i) | ||
70 | if(0 == strcasecmp(forbidden[i], name)) | ||
71 | return MHD_YES; | ||
72 | spdy_headers->nv[spdy_headers->cnt++] = (char *)name; | ||
73 | spdy_headers->nv[spdy_headers->cnt++] = (char *)value; | ||
74 | } | ||
75 | |||
76 | return MHD_YES; | ||
77 | } | ||
78 | |||
79 | |||
80 | static ssize_t | ||
81 | http_response_callback (void *cls, | ||
82 | uint64_t pos, | ||
83 | char *buffer, | ||
84 | size_t max) | ||
85 | { | ||
86 | int ret; | ||
87 | struct Proxy *proxy = (struct Proxy *)cls; | ||
88 | void *newbody; | ||
89 | const union MHD_ConnectionInfo *info; | ||
90 | int val = 1; | ||
91 | |||
92 | //max=16; | ||
93 | |||
94 | //PRINT_INFO2("response_callback, pos: %i, max is %i, len is %i",pos,max,proxy->length); | ||
95 | |||
96 | //assert(0 != proxy->length); | ||
97 | |||
98 | //if(MHD_CONTENT_READER_END_OF_STREAM == proxy->length) | ||
99 | // return MHD_CONTENT_READER_END_OF_STREAM; | ||
100 | |||
101 | PRINT_INFO2("http_response_callback for %s", proxy->url); | ||
102 | |||
103 | if(0 == proxy->http_body_size &&( proxy->done || !proxy->spdy_active)){ | ||
104 | PRINT_INFO("sent end of stream"); | ||
105 | return MHD_CONTENT_READER_END_OF_STREAM; | ||
106 | } | ||
107 | |||
108 | //*more = true; | ||
109 | if(!proxy->http_body_size)//nothing to write now | ||
110 | { | ||
111 | //flush data | ||
112 | info = MHD_get_connection_info (proxy->http_connection, | ||
113 | MHD_CONNECTION_INFO_CONNECTION_FD); | ||
114 | ret = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); | ||
115 | if(ret == -1) { | ||
116 | DIE("setsockopt"); | ||
117 | } | ||
118 | |||
119 | PRINT_INFO("FLUSH data"); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | if(max >= proxy->http_body_size) | ||
124 | { | ||
125 | ret = proxy->http_body_size; | ||
126 | newbody = NULL; | ||
127 | } | ||
128 | else | ||
129 | { | ||
130 | ret = max; | ||
131 | if(NULL == (newbody = au_malloc(proxy->http_body_size - max))) | ||
132 | { | ||
133 | PRINT_INFO("no memory"); | ||
134 | return -2; | ||
135 | } | ||
136 | memcpy(newbody, proxy->http_body + max, proxy->http_body_size - max); | ||
137 | } | ||
138 | memcpy(buffer, proxy->http_body, ret); | ||
139 | free(proxy->http_body); | ||
140 | proxy->http_body = newbody; | ||
141 | proxy->http_body_size -= ret; | ||
142 | |||
143 | if(proxy->length >= 0) | ||
144 | { | ||
145 | proxy->length -= ret; | ||
146 | //printf("pr len %i", proxy->length); | ||
147 | /*if(proxy->length <= 0) | ||
148 | { | ||
149 | // *more = false; | ||
150 | //last frame | ||
151 | proxy->length = MHD_CONTENT_READER_END_OF_STREAM; | ||
152 | }*/ | ||
153 | } | ||
154 | |||
155 | PRINT_INFO2("response_callback, size: %i",ret); | ||
156 | |||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | |||
161 | static void | ||
162 | http_response_done_callback(void *cls) | ||
163 | { | ||
164 | struct Proxy *proxy = (struct Proxy *)cls; | ||
165 | |||
166 | PRINT_INFO2("http_response_done_callback for %s", proxy->url); | ||
167 | //int ret; | ||
168 | |||
169 | //printf("response_done_callback\n"); | ||
170 | |||
171 | //printf("answer for %s was sent\n", (char *)cls); | ||
172 | |||
173 | /*if(SPDY_RESPONSE_RESULT_SUCCESS != status) | ||
174 | { | ||
175 | printf("answer was NOT sent, %i\n",status); | ||
176 | }*/ | ||
177 | /*if(CURLM_OK != (ret = curl_multi_remove_handle(multi_handle, proxy->curl_handle))) | ||
178 | { | ||
179 | PRINT_INFO2("curl_multi_remove_handle failed (%i)", ret); | ||
180 | } | ||
181 | curl_slist_free_all(proxy->curl_headers); | ||
182 | curl_easy_cleanup(proxy->curl_handle); | ||
183 | */ | ||
184 | //SPDY_destroy_request(request); | ||
185 | //SPDY_destroy_response(response); | ||
186 | MHD_destroy_response (proxy->http_response); | ||
187 | //if(!strcmp("/close",proxy->path)) run = 0; | ||
188 | //free(proxy->path); | ||
189 | if(proxy->spdy_active) | ||
190 | proxy->http_active = false; | ||
191 | else | ||
192 | free_proxy(proxy); | ||
193 | |||
194 | --glob_opt.responses_pending; | ||
195 | } | ||
196 | |||
197 | int | ||
198 | http_cb_request (void *cls, | ||
199 | struct MHD_Connection *connection, | ||
200 | const char *url, | ||
201 | const char *method, | ||
202 | const char *version, | ||
203 | const char *upload_data, | ||
204 | size_t *upload_data_size, | ||
205 | void **ptr) | ||
206 | { | ||
207 | //struct MHD_Response *response; | ||
208 | int ret; | ||
209 | struct Proxy *proxy; | ||
210 | //struct URI *spdy_uri; | ||
211 | //char **nv; | ||
212 | //int num_headers; | ||
213 | struct SPDY_Headers spdy_headers; | ||
214 | |||
215 | //PRINT_INFO2("request cb %i; %s", *ptr,url); | ||
216 | |||
217 | if (NULL == *ptr) | ||
218 | DIE("ptr is null"); | ||
219 | struct HTTP_URI *http_uri = (struct HTTP_URI *)*ptr; | ||
220 | |||
221 | if(NULL == http_uri->proxy) | ||
222 | { | ||
223 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) | ||
224 | { | ||
225 | free(http_uri->uri); | ||
226 | free(http_uri); | ||
227 | PRINT_INFO2("unexpected method %s", method); | ||
228 | return MHD_NO; /* unexpected method */ | ||
229 | } | ||
230 | |||
231 | if(NULL == (proxy = au_malloc(sizeof(struct Proxy)))) | ||
232 | { | ||
233 | PRINT_INFO("No memory"); | ||
234 | return MHD_NO; | ||
235 | } | ||
236 | |||
237 | ++glob_opt.responses_pending; | ||
238 | //memset(proxy, 0, sizeof(struct Proxy)); | ||
239 | proxy->id = rand(); | ||
240 | proxy->http_active = true; | ||
241 | //PRINT_INFO2("proxy obj with id %i created (%i)", proxy->id, proxy); | ||
242 | proxy->http_connection = connection; | ||
243 | http_uri->proxy = proxy; | ||
244 | return MHD_YES; | ||
245 | } | ||
246 | |||
247 | proxy = http_uri->proxy; | ||
248 | //*ptr = NULL; /* reset when done */ | ||
249 | |||
250 | if(proxy->spdy_active) | ||
251 | { | ||
252 | //already handled | ||
253 | PRINT_INFO("unnecessary call to http_cb_request"); | ||
254 | return MHD_YES; | ||
255 | } | ||
256 | |||
257 | PRINT_INFO2("received request for '%s %s %s'\n", method, http_uri->uri, version); | ||
258 | /* | ||
259 | proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
260 | 8096, | ||
261 | &http_response_callback, | ||
262 | proxy, | ||
263 | &http_response_done_callback); | ||
264 | |||
265 | if (proxy->http_response == NULL) | ||
266 | DIE("no response"); | ||
267 | */ | ||
268 | |||
269 | proxy->url = http_uri->uri; | ||
270 | //if(NULL == (proxy->url = strdup(http_uri->uri))) | ||
271 | // DIE("no memory"); | ||
272 | |||
273 | //TODO HTTP headers | ||
274 | /*MHD_get_connection_values (connection, | ||
275 | MHD_HEADER_KIND, | ||
276 | &http_iterate_cb, | ||
277 | proxy); | ||
278 | */ | ||
279 | //proxy->url = strdup(url); | ||
280 | //if(NULL == (spdy_uri = au_malloc(sizeof(struct URI)))) | ||
281 | // DIE("no memory"); | ||
282 | |||
283 | ret = parse_uri(&glob_opt.uri_preg, proxy->url, &proxy->uri); | ||
284 | if(ret != 0) | ||
285 | DIE("parse_uri failed"); | ||
286 | //proxy->uri = spdy_uri; | ||
287 | proxy->http_uri = http_uri; | ||
288 | proxy->spdy_active = true; | ||
289 | |||
290 | //proxy->spdy_request = au_malloc(sizeof(struct SPDY_Request)); | ||
291 | //if(NULL == proxy->spdy_request) | ||
292 | // DIE("no memory"); | ||
293 | //memset(proxy->spdy_request,0,sizeof(struct SPDY_Request)); | ||
294 | //spdy_request_init(proxy->spdy_request, &spdy_uri); | ||
295 | //spdy_submit_request(spdy_connection, proxy); | ||
296 | |||
297 | spdy_headers.num = MHD_get_connection_values (connection, | ||
298 | MHD_HEADER_KIND, | ||
299 | NULL, | ||
300 | NULL); | ||
301 | if(NULL == (spdy_headers.nv = au_malloc(((spdy_headers.num + 5) * 2 + 1) * sizeof(char *)))) | ||
302 | DIE("no memory"); | ||
303 | spdy_headers.nv[0] = ":method"; spdy_headers.nv[1] = "GET"; | ||
304 | spdy_headers.nv[2] = ":path"; spdy_headers.nv[3] = proxy->uri->path_and_more; | ||
305 | spdy_headers.nv[4] = ":version"; spdy_headers.nv[5] = (char *)version; | ||
306 | spdy_headers.nv[6] = ":scheme"; spdy_headers.nv[7] = proxy->uri->scheme; | ||
307 | spdy_headers.nv[8] = ":host"; spdy_headers.nv[9] = NULL; | ||
308 | //nv[14] = NULL; | ||
309 | spdy_headers.cnt = 10; | ||
310 | MHD_get_connection_values (connection, | ||
311 | MHD_HEADER_KIND, | ||
312 | &http_iterate_cb, | ||
313 | &spdy_headers); | ||
314 | |||
315 | spdy_headers.nv[spdy_headers.cnt] = NULL; | ||
316 | if(NULL == spdy_headers.nv[9]) | ||
317 | spdy_headers.nv[9] = proxy->uri->host_and_port; | ||
318 | |||
319 | /*int i; | ||
320 | for(i=0; i<spdy_headers.cnt; i+=2) | ||
321 | printf("%s: %s\n", spdy_headers.nv[i], spdy_headers.nv[i+1]); | ||
322 | */ | ||
323 | if(0 != spdy_request(spdy_headers.nv, proxy)) | ||
324 | { | ||
325 | //--glob_opt.responses_pending; | ||
326 | free(spdy_headers.nv); | ||
327 | //MHD_destroy_response (proxy->http_response); | ||
328 | free_proxy(proxy);//TODO call it here or in done_callback | ||
329 | |||
330 | return MHD_NO; | ||
331 | } | ||
332 | free(spdy_headers.nv); | ||
333 | |||
334 | proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
335 | 4096, | ||
336 | &http_response_callback, | ||
337 | proxy, | ||
338 | &http_response_done_callback); | ||
339 | |||
340 | if (proxy->http_response == NULL) | ||
341 | DIE("no response"); | ||
342 | |||
343 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
344 | "Proxy-Connection", "keep-alive")) | ||
345 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
346 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
347 | "Connection", "Keep-Alive")) | ||
348 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
349 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
350 | "Keep-Alive", "timeout=5, max=100")) | ||
351 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
352 | |||
353 | /* | ||
354 | const union MHD_ConnectionInfo *info; | ||
355 | info = MHD_get_connection_info (connection, | ||
356 | MHD_CONNECTION_INFO_CONNECTION_FD); | ||
357 | int val = 1; | ||
358 | int rv; | ||
359 | rv = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); | ||
360 | if(rv == -1) { | ||
361 | DIE("setsockopt"); | ||
362 | }*/ | ||
363 | return MHD_YES; | ||
364 | } | ||
365 | |||
366 | void | ||
367 | http_create_response(struct Proxy* proxy, char **nv) | ||
368 | { | ||
369 | size_t i; | ||
370 | //uint64_t response_size=MHD_SIZE_UNKNOWN; | ||
371 | |||
372 | /*for(i = 0; nv[i]; i += 2) { | ||
373 | if(0 == strcmp("content-length", nv[i])) | ||
374 | { | ||
375 | response_size = atoi(nv[i+1]); | ||
376 | break; | ||
377 | } | ||
378 | }*/ | ||
379 | /* | ||
380 | proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
381 | 4096, | ||
382 | &http_response_callback, | ||
383 | proxy, | ||
384 | &http_response_done_callback); | ||
385 | |||
386 | if (proxy->http_response == NULL) | ||
387 | DIE("no response"); | ||
388 | |||
389 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
390 | "Proxy-Connection", "keep-alive")) | ||
391 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
392 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
393 | "Connection", "Keep-Alive")) | ||
394 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
395 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
396 | "Keep-Alive", "timeout=5, max=100")) | ||
397 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
398 | */ | ||
399 | for(i = 0; nv[i]; i += 2) { | ||
400 | //printf(" %s: %s\n", nv[i], nv[i+1]); | ||
401 | //int j; | ||
402 | |||
403 | if(0 == strcmp(":status", nv[i])) | ||
404 | { | ||
405 | //raise(SIGINT); | ||
406 | //proxy->status_msg = nv[i+1]; | ||
407 | char tmp[4]; | ||
408 | memcpy(&tmp,nv[i+1],3); | ||
409 | tmp[3]=0; | ||
410 | proxy->status = atoi(tmp); | ||
411 | continue; | ||
412 | } | ||
413 | else if(0 == strcmp(":version", nv[i])) | ||
414 | { | ||
415 | proxy->version = nv[i+1]; | ||
416 | continue; | ||
417 | } | ||
418 | else if(0 == strcmp("content-length", nv[i])) | ||
419 | { | ||
420 | //proxy->length = atoi(nv[i+1]); | ||
421 | //response_size = atoi(nv[i+1]); | ||
422 | continue; | ||
423 | } | ||
424 | |||
425 | //for(j=0; j<strlen(nv[i]) && ':'==nv[i][j]; ++j); | ||
426 | |||
427 | char *header = *(nv+i); | ||
428 | //header[0] = toupper(header[0]); | ||
429 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
430 | header, nv[i+1])) | ||
431 | { | ||
432 | PRINT_INFO2("SPDY_name_value_add failed: '%s' '%s'", header, nv[i+1]); | ||
433 | //abort(); | ||
434 | } | ||
435 | PRINT_INFO2("adding '%s: %s'",header, nv[i+1]); | ||
436 | } | ||
437 | |||
438 | //PRINT_INFO2("%i", MHD_get_response_headers(proxy->http_response, NULL, NULL)); | ||
439 | //PRINT_INFO2("state before %i", proxy->http_connection->state); | ||
440 | //PRINT_INFO2("loop before %i", proxy->http_connection->event_loop_info); | ||
441 | if(MHD_NO == MHD_queue_response (proxy->http_connection, proxy->status, proxy->http_response)){ | ||
442 | PRINT_INFO("No queue"); | ||
443 | abort(); | ||
444 | } | ||
445 | //PRINT_INFO2("state after %i", proxy->http_connection->state); | ||
446 | //PRINT_INFO2("loop after %i", proxy->http_connection->event_loop_info); | ||
447 | //MHD_destroy_response (proxy->http_response); | ||
448 | //PRINT_INFO2("state after %i", proxy->http_connection->state); | ||
449 | //PRINT_INFO2("loop after %i", proxy->http_connection->event_loop_info); | ||
450 | } | ||
diff --git a/src/examples/mhd2spdy_http.h b/src/examples/mhd2spdy_http.h new file mode 100644 index 00000000..0b5dde99 --- /dev/null +++ b/src/examples/mhd2spdy_http.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | Copyright (C) 2013 Andrey Uzunov | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file structures.h | ||
20 | * @author Andrey Uzunov | ||
21 | */ | ||
22 | |||
23 | #ifndef HTTP_H | ||
24 | #define HTTP_H | ||
25 | |||
26 | #include "mhd2spdy_structures.h" | ||
27 | |||
28 | int | ||
29 | http_cb_request (void *cls, | ||
30 | struct MHD_Connection *connection, | ||
31 | const char *url, | ||
32 | const char *method, | ||
33 | const char *version, | ||
34 | const char *upload_data, | ||
35 | size_t *upload_data_size, | ||
36 | void **ptr); | ||
37 | |||
38 | void * http_log_cb(void * cls, const char * uri); | ||
39 | |||
40 | void | ||
41 | http_create_response(struct Proxy* proxy, char **nv); | ||
42 | |||
43 | #endif | ||
diff --git a/src/examples/mhd2spdy_spdy.c b/src/examples/mhd2spdy_spdy.c new file mode 100644 index 00000000..93cad507 --- /dev/null +++ b/src/examples/mhd2spdy_spdy.c | |||
@@ -0,0 +1,908 @@ | |||
1 | /* | ||
2 | * Spdylay - SPDY Library | ||
3 | * | ||
4 | * Copyright (c) 2012 Tatsuhiro Tsujikawa | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining | ||
7 | * a copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice shall be | ||
15 | * included in all copies or substantial portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
24 | */ | ||
25 | |||
26 | /** | ||
27 | * @file spdy.c | ||
28 | * @author Tatsuhiro Tsujikawa | ||
29 | * @author Andrey Uzunov | ||
30 | */ | ||
31 | |||
32 | #include "mhd2spdy_structures.h" | ||
33 | #include "mhd2spdy_spdy.h" | ||
34 | #include "mhd2spdy_http.h" | ||
35 | |||
36 | enum | ||
37 | { | ||
38 | IO_NONE, | ||
39 | WANT_READ, | ||
40 | WANT_WRITE | ||
41 | }; | ||
42 | |||
43 | |||
44 | /* | ||
45 | * Prints error containing the function name |func| and message |msg| | ||
46 | * and exit. | ||
47 | */ | ||
48 | static void spdy_dief(const char *func, const char *msg) | ||
49 | { | ||
50 | fprintf(stderr, "FATAL: %s: %s\n", func, msg); | ||
51 | exit(EXIT_FAILURE); | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * Prints error containing the function name |func| and error code | ||
56 | * |error_code| and exit. | ||
57 | */ | ||
58 | void spdy_diec(const char *func, int error_code) | ||
59 | { | ||
60 | fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code, | ||
61 | spdylay_strerror(error_code)); | ||
62 | exit(EXIT_FAILURE); | ||
63 | } | ||
64 | |||
65 | |||
66 | /* | ||
67 | * The implementation of spdylay_send_callback type. Here we write | ||
68 | * |data| with size |length| to the network and return the number of | ||
69 | * bytes actually written. See the documentation of | ||
70 | * spdylay_send_callback for the details. | ||
71 | */ | ||
72 | static ssize_t spdy_cb_send(spdylay_session *session, | ||
73 | const uint8_t *data, size_t length, int flags, | ||
74 | void *user_data) | ||
75 | { | ||
76 | //PRINT_INFO("spdy_cb_send called"); | ||
77 | struct SPDY_Connection *connection; | ||
78 | ssize_t rv; | ||
79 | connection = (struct SPDY_Connection*)user_data; | ||
80 | connection->want_io = IO_NONE; | ||
81 | if(connection->is_tls) | ||
82 | { | ||
83 | ERR_clear_error(); | ||
84 | rv = SSL_write(connection->ssl, data, length); | ||
85 | if(rv < 0) { | ||
86 | int err = SSL_get_error(connection->ssl, rv); | ||
87 | if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { | ||
88 | connection->want_io = (err == SSL_ERROR_WANT_READ ? | ||
89 | WANT_READ : WANT_WRITE); | ||
90 | rv = SPDYLAY_ERR_WOULDBLOCK; | ||
91 | } else { | ||
92 | rv = SPDYLAY_ERR_CALLBACK_FAILURE; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | else | ||
97 | { | ||
98 | rv = write(connection->fd, | ||
99 | data, | ||
100 | length); | ||
101 | |||
102 | if (rv < 0) | ||
103 | { | ||
104 | switch(errno) | ||
105 | { | ||
106 | case EAGAIN: | ||
107 | #if EAGAIN != EWOULDBLOCK | ||
108 | case EWOULDBLOCK: | ||
109 | #endif | ||
110 | connection->want_io = WANT_WRITE; | ||
111 | rv = SPDYLAY_ERR_WOULDBLOCK; | ||
112 | break; | ||
113 | |||
114 | default: | ||
115 | rv = SPDYLAY_ERR_CALLBACK_FAILURE; | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | return rv; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * The implementation of spdylay_recv_callback type. Here we read data | ||
124 | * from the network and write them in |buf|. The capacity of |buf| is | ||
125 | * |length| bytes. Returns the number of bytes stored in |buf|. See | ||
126 | * the documentation of spdylay_recv_callback for the details. | ||
127 | */ | ||
128 | static ssize_t spdy_cb_recv(spdylay_session *session, | ||
129 | uint8_t *buf, size_t length, int flags, | ||
130 | void *user_data) | ||
131 | { | ||
132 | struct SPDY_Connection *connection; | ||
133 | ssize_t rv; | ||
134 | |||
135 | connection = (struct SPDY_Connection*)user_data; | ||
136 | //prevent monopolizing everything | ||
137 | if(!(++connection->counter % 10)) return SPDYLAY_ERR_WOULDBLOCK; | ||
138 | connection->want_io = IO_NONE; | ||
139 | if(connection->is_tls) | ||
140 | { | ||
141 | ERR_clear_error(); | ||
142 | rv = SSL_read(connection->ssl, buf, length); | ||
143 | if(rv < 0) { | ||
144 | int err = SSL_get_error(connection->ssl, rv); | ||
145 | if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { | ||
146 | connection->want_io = (err == SSL_ERROR_WANT_READ ? | ||
147 | WANT_READ : WANT_WRITE); | ||
148 | rv = SPDYLAY_ERR_WOULDBLOCK; | ||
149 | } else { | ||
150 | rv = SPDYLAY_ERR_CALLBACK_FAILURE; | ||
151 | } | ||
152 | } else if(rv == 0) { | ||
153 | rv = SPDYLAY_ERR_EOF; | ||
154 | } | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | rv = read(connection->fd, | ||
159 | buf, | ||
160 | length); | ||
161 | |||
162 | if (rv < 0) | ||
163 | { | ||
164 | switch(errno) | ||
165 | { | ||
166 | case EAGAIN: | ||
167 | #if EAGAIN != EWOULDBLOCK | ||
168 | case EWOULDBLOCK: | ||
169 | #endif | ||
170 | connection->want_io = WANT_READ; | ||
171 | rv = SPDYLAY_ERR_WOULDBLOCK; | ||
172 | break; | ||
173 | |||
174 | default: | ||
175 | rv = SPDYLAY_ERR_CALLBACK_FAILURE; | ||
176 | } | ||
177 | } | ||
178 | else if(rv == 0) | ||
179 | rv = SPDYLAY_ERR_EOF; | ||
180 | } | ||
181 | return rv; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * The implementation of spdylay_before_ctrl_send_callback type. We | ||
186 | * use this function to get stream ID of the request. This is because | ||
187 | * stream ID is not known when we submit the request | ||
188 | * (spdylay_spdy_submit_request). | ||
189 | */ | ||
190 | /*static void spdy_cb_before_ctrl_send(spdylay_session *session, | ||
191 | spdylay_frame_type type, | ||
192 | spdylay_frame *frame, | ||
193 | void *user_data) | ||
194 | { | ||
195 | }*/ | ||
196 | |||
197 | |||
198 | static void spdy_cb_on_ctrl_send(spdylay_session *session, | ||
199 | spdylay_frame_type type, | ||
200 | spdylay_frame *frame, void *user_data) | ||
201 | { | ||
202 | //char **nv; | ||
203 | //const char *name = NULL; | ||
204 | int32_t stream_id; | ||
205 | //size_t i; | ||
206 | struct Proxy *proxy; | ||
207 | |||
208 | switch(type) { | ||
209 | case SPDYLAY_SYN_STREAM: | ||
210 | //nv = frame->syn_stream.nv; | ||
211 | //name = "SYN_STREAM"; | ||
212 | stream_id = frame->syn_stream.stream_id; | ||
213 | proxy = spdylay_session_get_stream_user_data(session, stream_id); | ||
214 | ++glob_opt.streams_opened; | ||
215 | ++proxy->spdy_connection->streams_opened; | ||
216 | PRINT_INFO2("opening stream: str open %i; %s", glob_opt.streams_opened, proxy->url); | ||
217 | break; | ||
218 | default: | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | void spdy_cb_on_ctrl_recv(spdylay_session *session, | ||
224 | spdylay_frame_type type, | ||
225 | spdylay_frame *frame, void *user_data) | ||
226 | { | ||
227 | //struct SPDY_Request *req; | ||
228 | char **nv; | ||
229 | //const char *name = NULL; | ||
230 | int32_t stream_id; | ||
231 | struct Proxy * proxy; | ||
232 | |||
233 | switch(type) { | ||
234 | case SPDYLAY_SYN_REPLY: | ||
235 | nv = frame->syn_reply.nv; | ||
236 | //name = "SYN_REPLY"; | ||
237 | stream_id = frame->syn_reply.stream_id; | ||
238 | break; | ||
239 | case SPDYLAY_HEADERS: | ||
240 | nv = frame->headers.nv; | ||
241 | //name = "HEADERS"; | ||
242 | stream_id = frame->headers.stream_id; | ||
243 | break; | ||
244 | default: | ||
245 | return; | ||
246 | break; | ||
247 | } | ||
248 | |||
249 | proxy = spdylay_session_get_stream_user_data(session, stream_id); | ||
250 | PRINT_INFO2("received headers for %s", proxy->url); | ||
251 | |||
252 | http_create_response(proxy, nv); | ||
253 | glob_opt.spdy_data_received = true; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * The implementation of spdylay_on_stream_close_callback type. We use | ||
258 | * this function to know the response is fully received. Since we just | ||
259 | * fetch 1 resource in this program, after reception of the response, | ||
260 | * we submit GOAWAY and close the session. | ||
261 | */ | ||
262 | static void spdy_cb_on_stream_close(spdylay_session *session, | ||
263 | int32_t stream_id, | ||
264 | spdylay_status_code status_code, | ||
265 | void *user_data) | ||
266 | { | ||
267 | struct Proxy * proxy = spdylay_session_get_stream_user_data(session, stream_id); | ||
268 | |||
269 | assert(NULL != proxy); | ||
270 | |||
271 | --glob_opt.streams_opened; | ||
272 | --proxy->spdy_connection->streams_opened; | ||
273 | PRINT_INFO2("closing stream: str opened %i", glob_opt.streams_opened); | ||
274 | |||
275 | DLL_remove(proxy->spdy_connection->proxies_head, proxy->spdy_connection->proxies_tail, proxy); | ||
276 | |||
277 | if(proxy->http_active) | ||
278 | proxy->spdy_active = false; | ||
279 | else | ||
280 | free_proxy(proxy); | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | #define SPDY_MAX_OUTLEN 4096 | ||
285 | |||
286 | /* | ||
287 | * The implementation of spdylay_on_data_chunk_recv_callback type. We | ||
288 | * use this function to print the received response body. | ||
289 | */ | ||
290 | static void spdy_cb_on_data_chunk_recv(spdylay_session *session, uint8_t flags, | ||
291 | int32_t stream_id, | ||
292 | const uint8_t *data, size_t len, | ||
293 | void *user_data) | ||
294 | { | ||
295 | //struct SPDY_Request *req; | ||
296 | struct Proxy *proxy; | ||
297 | proxy = spdylay_session_get_stream_user_data(session, stream_id); | ||
298 | |||
299 | if(NULL == proxy->http_body) | ||
300 | proxy->http_body = au_malloc(len); | ||
301 | else | ||
302 | proxy->http_body = realloc(proxy->http_body, proxy->http_body_size + len); | ||
303 | if(NULL == proxy->http_body) | ||
304 | { | ||
305 | PRINT_INFO("not enough memory (realloc returned NULL)"); | ||
306 | return ; | ||
307 | } | ||
308 | |||
309 | memcpy(proxy->http_body + proxy->http_body_size, data, len); | ||
310 | proxy->http_body_size += len; | ||
311 | PRINT_INFO2("received data for %s; %zu bytes", proxy->url, len); | ||
312 | glob_opt.spdy_data_received = true; | ||
313 | } | ||
314 | |||
315 | static void spdy_cb_on_data_recv(spdylay_session *session, | ||
316 | uint8_t flags, int32_t stream_id, int32_t length, void *user_data) | ||
317 | { | ||
318 | if(flags & SPDYLAY_DATA_FLAG_FIN) | ||
319 | { | ||
320 | struct Proxy *proxy; | ||
321 | proxy = spdylay_session_get_stream_user_data(session, stream_id); | ||
322 | proxy->done = true; | ||
323 | PRINT_INFO2("last data frame received for %s", proxy->url); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * Setup callback functions. Spdylay API offers many callback | ||
329 | * functions, but most of them are optional. The send_callback is | ||
330 | * always required. Since we use spdylay_session_recv(), the | ||
331 | * recv_callback is also required. | ||
332 | */ | ||
333 | static void spdy_setup_spdylay_callbacks(spdylay_session_callbacks *callbacks) | ||
334 | { | ||
335 | memset(callbacks, 0, sizeof(spdylay_session_callbacks)); | ||
336 | callbacks->send_callback = spdy_cb_send; | ||
337 | callbacks->recv_callback = spdy_cb_recv; | ||
338 | //callbacks->before_ctrl_send_callback = spdy_cb_before_ctrl_send; | ||
339 | callbacks->on_ctrl_send_callback = spdy_cb_on_ctrl_send; | ||
340 | callbacks->on_ctrl_recv_callback = spdy_cb_on_ctrl_recv; | ||
341 | callbacks->on_stream_close_callback = spdy_cb_on_stream_close; | ||
342 | callbacks->on_data_chunk_recv_callback = spdy_cb_on_data_chunk_recv; | ||
343 | callbacks->on_data_recv_callback = spdy_cb_on_data_recv; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Callback function for SSL/TLS NPN. Since this program only supports | ||
348 | * SPDY protocol, if server does not offer SPDY protocol the Spdylay | ||
349 | * library supports, we terminate program. | ||
350 | */ | ||
351 | static int spdy_cb_ssl_select_next_proto(SSL* ssl, | ||
352 | unsigned char **out, unsigned char *outlen, | ||
353 | const unsigned char *in, unsigned int inlen, | ||
354 | void *arg) | ||
355 | { | ||
356 | //PRINT_INFO("spdy_cb_ssl_select_next_proto"); | ||
357 | int rv; | ||
358 | uint16_t *spdy_proto_version; | ||
359 | /* spdylay_select_next_protocol() selects SPDY protocol version the | ||
360 | Spdylay library supports. */ | ||
361 | rv = spdylay_select_next_protocol(out, outlen, in, inlen); | ||
362 | if(rv <= 0) { | ||
363 | PRINT_INFO("Server did not advertise spdy/2 or spdy/3 protocol."); | ||
364 | return rv; | ||
365 | } | ||
366 | spdy_proto_version = (uint16_t*)arg; | ||
367 | *spdy_proto_version = rv; | ||
368 | return SSL_TLSEXT_ERR_OK; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Setup SSL context. We pass |spdy_proto_version| to get negotiated | ||
373 | * SPDY protocol version in NPN callback. | ||
374 | */ | ||
375 | void spdy_ssl_init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version) | ||
376 | { | ||
377 | /* Disable SSLv2 and enable all workarounds for buggy servers */ | ||
378 | SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION); | ||
379 | SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); | ||
380 | SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); | ||
381 | /* Set NPN callback */ | ||
382 | SSL_CTX_set_next_proto_select_cb(ssl_ctx, spdy_cb_ssl_select_next_proto, | ||
383 | spdy_proto_version); | ||
384 | } | ||
385 | |||
386 | static int spdy_ssl_handshake(SSL *ssl, int fd) | ||
387 | { | ||
388 | int rv; | ||
389 | if(SSL_set_fd(ssl, fd) == 0) { | ||
390 | spdy_dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL)); | ||
391 | } | ||
392 | ERR_clear_error(); | ||
393 | rv = SSL_connect(ssl); | ||
394 | if(rv <= 0) { | ||
395 | PRINT_INFO2("SSL_connect %s", ERR_error_string(ERR_get_error(), NULL)); | ||
396 | } | ||
397 | |||
398 | return rv; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Connects to the host |host| and port |port|. This function returns | ||
403 | * the file descriptor of the client socket. | ||
404 | */ | ||
405 | static int spdy_socket_connect_to(const char *host, uint16_t port) | ||
406 | { | ||
407 | struct addrinfo hints; | ||
408 | int fd = -1; | ||
409 | int rv; | ||
410 | char service[NI_MAXSERV]; | ||
411 | struct addrinfo *res, *rp; | ||
412 | snprintf(service, sizeof(service), "%u", port); | ||
413 | memset(&hints, 0, sizeof(struct addrinfo)); | ||
414 | hints.ai_family = AF_UNSPEC; | ||
415 | hints.ai_socktype = SOCK_STREAM; | ||
416 | rv = getaddrinfo(host, service, &hints, &res); | ||
417 | if(rv != 0) { | ||
418 | printf("%s\n",host); | ||
419 | spdy_dief("getaddrinfo", gai_strerror(rv)); | ||
420 | } | ||
421 | for(rp = res; rp; rp = rp->ai_next) { | ||
422 | fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); | ||
423 | if(fd == -1) { | ||
424 | continue; | ||
425 | } | ||
426 | while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 && | ||
427 | errno == EINTR); | ||
428 | if(rv == 0) { | ||
429 | break; | ||
430 | } | ||
431 | close(fd); | ||
432 | fd = -1; | ||
433 | } | ||
434 | freeaddrinfo(res); | ||
435 | return fd; | ||
436 | } | ||
437 | |||
438 | static void spdy_socket_make_non_block(int fd) | ||
439 | { | ||
440 | int flags, rv; | ||
441 | while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR); | ||
442 | if(flags == -1) { | ||
443 | spdy_dief("fcntl", strerror(errno)); | ||
444 | } | ||
445 | while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR); | ||
446 | if(rv == -1) { | ||
447 | spdy_dief("fcntl", strerror(errno)); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * Setting TCP_NODELAY is not mandatory for the SPDY protocol. | ||
453 | */ | ||
454 | static void spdy_socket_set_tcp_nodelay(int fd) | ||
455 | { | ||
456 | int val = 1; | ||
457 | int rv; | ||
458 | rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); | ||
459 | if(rv == -1) { | ||
460 | spdy_dief("setsockopt", strerror(errno)); | ||
461 | } | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * Update |pollfd| based on the state of |connection|. | ||
466 | */ | ||
467 | void spdy_ctl_poll(struct pollfd *pollfd, struct SPDY_Connection *connection) | ||
468 | { | ||
469 | pollfd->events = 0; | ||
470 | if(spdylay_session_want_read(connection->session) || | ||
471 | connection->want_io == WANT_READ) { | ||
472 | pollfd->events |= POLLIN; | ||
473 | } | ||
474 | if(spdylay_session_want_write(connection->session) || | ||
475 | connection->want_io == WANT_WRITE) { | ||
476 | pollfd->events |= POLLOUT; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * Update |selectfd| based on the state of |connection|. | ||
482 | */ | ||
483 | bool spdy_ctl_select(fd_set * read_fd_set, | ||
484 | fd_set * write_fd_set, | ||
485 | fd_set * except_fd_set, | ||
486 | struct SPDY_Connection *connection) | ||
487 | { | ||
488 | bool ret = false; | ||
489 | |||
490 | if(spdylay_session_want_read(connection->session) || | ||
491 | connection->want_io == WANT_READ) { | ||
492 | FD_SET(connection->fd, read_fd_set); | ||
493 | ret = true; | ||
494 | } | ||
495 | if(spdylay_session_want_write(connection->session) || | ||
496 | connection->want_io == WANT_WRITE) { | ||
497 | FD_SET(connection->fd, write_fd_set); | ||
498 | ret = true; | ||
499 | } | ||
500 | return ret; | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Performs the network I/O. | ||
505 | */ | ||
506 | int spdy_exec_io(struct SPDY_Connection *connection) | ||
507 | { | ||
508 | int rv; | ||
509 | rv = spdylay_session_recv(connection->session); | ||
510 | if(rv != 0) { | ||
511 | PRINT_INFO2("spdylay_session_recv %i", rv); | ||
512 | return rv; | ||
513 | } | ||
514 | rv = spdylay_session_send(connection->session); | ||
515 | if(rv != 0) { | ||
516 | PRINT_INFO2("spdylay_session_send %i", rv); | ||
517 | } | ||
518 | return rv; | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | * Fetches the resource denoted by |uri|. | ||
523 | */ | ||
524 | struct SPDY_Connection * spdy_connect(const struct URI *uri, uint16_t port, bool is_tls) | ||
525 | { | ||
526 | spdylay_session_callbacks callbacks; | ||
527 | int fd; | ||
528 | //SSL_CTX *ssl_ctx; | ||
529 | SSL *ssl=NULL; | ||
530 | //struct SPDY_Request req; | ||
531 | struct SPDY_Connection * connection; | ||
532 | int rv; | ||
533 | |||
534 | spdy_setup_spdylay_callbacks(&callbacks); | ||
535 | |||
536 | /* Establish connection and setup SSL */ | ||
537 | PRINT_INFO2("connecting to %s:%i", uri->host, port); | ||
538 | fd = spdy_socket_connect_to(uri->host, port); | ||
539 | if(fd == -1) { | ||
540 | PRINT_INFO("Could not open file descriptor"); | ||
541 | return NULL;//glob_opt.spdy_connection; | ||
542 | } | ||
543 | |||
544 | if(is_tls) | ||
545 | { | ||
546 | /*ssl_ctx = SSL_CTX_new(SSLv23_client_method()); | ||
547 | if(ssl_ctx == NULL) { | ||
548 | spdy_dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL)); | ||
549 | } | ||
550 | spdy_ssl_init_ssl_ctx(ssl_ctx, &spdy_proto_version); | ||
551 | */ | ||
552 | ssl = SSL_new(glob_opt.ssl_ctx); | ||
553 | if(ssl == NULL) { | ||
554 | spdy_dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); | ||
555 | } | ||
556 | |||
557 | //TODO non-blocking | ||
558 | /* To simplify the program, we perform SSL/TLS handshake in blocking | ||
559 | I/O. */ | ||
560 | glob_opt.spdy_proto_version = 0; | ||
561 | rv = spdy_ssl_handshake(ssl, fd); | ||
562 | if(rv <= 0 || (glob_opt.spdy_proto_version != 3 && glob_opt.spdy_proto_version != 2)) | ||
563 | { | ||
564 | PRINT_INFO("Closing SSL"); | ||
565 | //no spdy on the other side | ||
566 | SSL_shutdown(ssl); | ||
567 | close(fd); | ||
568 | SSL_free(ssl); | ||
569 | |||
570 | return NULL; | ||
571 | } | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | glob_opt.spdy_proto_version = 3; | ||
576 | } | ||
577 | |||
578 | if(NULL == (connection = au_malloc(sizeof(struct SPDY_Connection)))) | ||
579 | return NULL; | ||
580 | //memset(connection, 0 , sizeof(struct SPDY_Connection)); | ||
581 | |||
582 | connection->is_tls = is_tls; | ||
583 | connection->ssl = ssl; | ||
584 | connection->want_io = IO_NONE; | ||
585 | connection->host = strdup(uri->host); | ||
586 | |||
587 | /* Here make file descriptor non-block */ | ||
588 | spdy_socket_make_non_block(fd); | ||
589 | spdy_socket_set_tcp_nodelay(fd); | ||
590 | |||
591 | PRINT_INFO2("[INFO] SPDY protocol version = %d\n", glob_opt.spdy_proto_version); | ||
592 | rv = spdylay_session_client_new(&(connection->session), glob_opt.spdy_proto_version, | ||
593 | &callbacks, connection); | ||
594 | if(rv != 0) { | ||
595 | spdy_diec("spdylay_session_client_new", rv); | ||
596 | } | ||
597 | |||
598 | connection->fd = fd; | ||
599 | |||
600 | return connection; | ||
601 | } | ||
602 | |||
603 | void | ||
604 | spdy_free_connection(struct SPDY_Connection * connection) | ||
605 | { | ||
606 | if(NULL != connection) | ||
607 | { | ||
608 | spdylay_session_del(connection->session); | ||
609 | SSL_free(connection->ssl); | ||
610 | free(connection->host); | ||
611 | free(connection); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | int | ||
616 | spdy_request(const char **nv, struct Proxy *proxy) | ||
617 | { | ||
618 | int ret; | ||
619 | uint16_t port; | ||
620 | struct SPDY_Connection *connection; | ||
621 | |||
622 | if(glob_opt.only_proxy) | ||
623 | { | ||
624 | connection = glob_opt.spdy_connection; | ||
625 | } | ||
626 | else | ||
627 | { | ||
628 | connection = glob_opt.spdy_connections_head; | ||
629 | while(NULL != connection) | ||
630 | { | ||
631 | if(0 == strcasecmp(proxy->uri->host, connection->host)) | ||
632 | break; | ||
633 | connection = connection->next; | ||
634 | } | ||
635 | |||
636 | if(NULL == connection) | ||
637 | { | ||
638 | //connect to host | ||
639 | port = proxy->uri->port; | ||
640 | if(0 == port) port = 443; | ||
641 | connection = spdy_connect(proxy->uri, port, true); | ||
642 | if(NULL != connection) | ||
643 | { | ||
644 | DLL_insert(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection); | ||
645 | glob_opt.total_spdy_connections++; | ||
646 | } | ||
647 | else | ||
648 | connection = glob_opt.spdy_connection; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | if(NULL == connection) | ||
653 | { | ||
654 | PRINT_INFO("there is no proxy!"); | ||
655 | return -1; | ||
656 | } | ||
657 | |||
658 | proxy->spdy_connection = connection; | ||
659 | ret = spdylay_submit_request(connection->session, 0, nv, NULL, proxy); | ||
660 | if(ret != 0) { | ||
661 | spdy_diec("spdylay_spdy_submit_request", ret); | ||
662 | } | ||
663 | DLL_insert(connection->proxies_head, connection->proxies_tail, proxy); | ||
664 | |||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | |||
669 | void | ||
670 | spdy_get_pollfdset(struct pollfd fds[], struct SPDY_Connection *connections[], int max_size, nfds_t *real_size) | ||
671 | { | ||
672 | struct SPDY_Connection *connection; | ||
673 | struct Proxy *proxy; | ||
674 | |||
675 | *real_size = 0; | ||
676 | if(max_size<1) return; | ||
677 | if(NULL != glob_opt.spdy_connection) | ||
678 | { | ||
679 | spdy_ctl_poll(&(fds[*real_size]), glob_opt.spdy_connection); | ||
680 | if(!fds[*real_size].events) | ||
681 | { | ||
682 | //PRINT_INFO("TODO drop connection"); | ||
683 | glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened; | ||
684 | |||
685 | for(proxy = glob_opt.spdy_connection->proxies_head; NULL != proxy; proxy=proxy->next) | ||
686 | { | ||
687 | DLL_remove(glob_opt.spdy_connection->proxies_head, glob_opt.spdy_connection->proxies_tail, proxy); | ||
688 | proxy->spdy_active = false; | ||
689 | } | ||
690 | spdy_free_connection(glob_opt.spdy_connection); | ||
691 | glob_opt.spdy_connection = NULL; | ||
692 | } | ||
693 | else | ||
694 | { | ||
695 | fds[*real_size].fd = glob_opt.spdy_connection->fd; | ||
696 | connections[*real_size] = glob_opt.spdy_connection; | ||
697 | ++(*real_size); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | connection = glob_opt.spdy_connections_head; | ||
702 | |||
703 | while(NULL != connection && *real_size < max_size) | ||
704 | { | ||
705 | assert(!glob_opt.only_proxy); | ||
706 | spdy_ctl_poll(&(fds[*real_size]), connection); | ||
707 | if(!fds[*real_size].events) | ||
708 | { | ||
709 | //PRINT_INFO("TODO drop connection"); | ||
710 | glob_opt.streams_opened -= connection->streams_opened; | ||
711 | DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection); | ||
712 | glob_opt.total_spdy_connections--; | ||
713 | |||
714 | for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy->next) | ||
715 | { | ||
716 | DLL_remove(connection->proxies_head, connection->proxies_tail, proxy); | ||
717 | proxy->spdy_active = false; | ||
718 | } | ||
719 | spdy_free_connection(connection); | ||
720 | } | ||
721 | else | ||
722 | { | ||
723 | fds[*real_size].fd = connection->fd; | ||
724 | connections[*real_size] = connection; | ||
725 | ++(*real_size); | ||
726 | } | ||
727 | connection = connection->next; | ||
728 | } | ||
729 | |||
730 | //, "TODO max num of conn reached; close something" | ||
731 | assert(NULL == connection); | ||
732 | } | ||
733 | |||
734 | |||
735 | int | ||
736 | spdy_get_selectfdset(fd_set * read_fd_set, | ||
737 | fd_set * write_fd_set, | ||
738 | fd_set * except_fd_set, | ||
739 | struct SPDY_Connection *connections[], int max_size, nfds_t *real_size) | ||
740 | { | ||
741 | struct SPDY_Connection *connection; | ||
742 | struct Proxy *proxy; | ||
743 | bool ret; | ||
744 | int maxfd = 0; | ||
745 | |||
746 | *real_size = 0; | ||
747 | if(max_size<1) return 0; | ||
748 | if(NULL != glob_opt.spdy_connection) | ||
749 | { | ||
750 | ret = spdy_ctl_select(read_fd_set, | ||
751 | write_fd_set, | ||
752 | except_fd_set, glob_opt.spdy_connection); | ||
753 | if(!ret) | ||
754 | { | ||
755 | //PRINT_INFO("TODO drop connection"); | ||
756 | glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened; | ||
757 | |||
758 | for(proxy = glob_opt.spdy_connection->proxies_head; NULL != proxy; proxy=proxy->next) | ||
759 | { | ||
760 | DLL_remove(glob_opt.spdy_connection->proxies_head, glob_opt.spdy_connection->proxies_tail, proxy); | ||
761 | proxy->spdy_active = false; | ||
762 | } | ||
763 | spdy_free_connection(glob_opt.spdy_connection); | ||
764 | glob_opt.spdy_connection = NULL; | ||
765 | } | ||
766 | else | ||
767 | { | ||
768 | connections[*real_size] = glob_opt.spdy_connection; | ||
769 | ++(*real_size); | ||
770 | if(maxfd < glob_opt.spdy_connection->fd) maxfd = glob_opt.spdy_connection->fd; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | connection = glob_opt.spdy_connections_head; | ||
775 | |||
776 | while(NULL != connection && *real_size < max_size) | ||
777 | { | ||
778 | assert(!glob_opt.only_proxy); | ||
779 | ret = spdy_ctl_select(read_fd_set, | ||
780 | write_fd_set, | ||
781 | except_fd_set, connection); | ||
782 | if(!ret) | ||
783 | { | ||
784 | //PRINT_INFO("TODO drop connection"); | ||
785 | glob_opt.streams_opened -= connection->streams_opened; | ||
786 | DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection); | ||
787 | glob_opt.total_spdy_connections--; | ||
788 | |||
789 | for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy->next) | ||
790 | { | ||
791 | DLL_remove(connection->proxies_head, connection->proxies_tail, proxy); | ||
792 | proxy->spdy_active = false; | ||
793 | } | ||
794 | spdy_free_connection(connection); | ||
795 | } | ||
796 | else | ||
797 | { | ||
798 | connections[*real_size] = connection; | ||
799 | ++(*real_size); | ||
800 | if(maxfd < connection->fd) maxfd = connection->fd; | ||
801 | } | ||
802 | connection = connection->next; | ||
803 | } | ||
804 | |||
805 | //, "TODO max num of conn reached; close something" | ||
806 | assert(NULL == connection); | ||
807 | |||
808 | return maxfd; | ||
809 | } | ||
810 | |||
811 | |||
812 | void | ||
813 | spdy_run(struct pollfd fds[], struct SPDY_Connection *connections[], int size) | ||
814 | { | ||
815 | int i; | ||
816 | int ret; | ||
817 | struct Proxy *proxy; | ||
818 | //PRINT_INFO2("size is %i", size); | ||
819 | |||
820 | for(i=0; i<size; ++i) | ||
821 | { | ||
822 | // PRINT_INFO2("exec about to be called for %s", connections[i]->host); | ||
823 | if(fds[i].revents & (POLLIN | POLLOUT)) | ||
824 | { | ||
825 | ret = spdy_exec_io(connections[i]); | ||
826 | //PRINT_INFO2("%i",ret); | ||
827 | //if((spdy_pollfds[i].revents & POLLHUP) || (spdy_pollfds[0].revents & POLLERR)) | ||
828 | // PRINT_INFO("SPDY SPDY_Connection error"); | ||
829 | |||
830 | //TODO POLLRDHUP | ||
831 | // always close on ret != 0? | ||
832 | |||
833 | if(0 != ret) | ||
834 | { | ||
835 | glob_opt.streams_opened -= connections[i]->streams_opened; | ||
836 | if(connections[i] == glob_opt.spdy_connection) | ||
837 | { | ||
838 | glob_opt.spdy_connection = NULL; | ||
839 | } | ||
840 | else | ||
841 | { | ||
842 | DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]); | ||
843 | glob_opt.total_spdy_connections--; | ||
844 | } | ||
845 | for(proxy = connections[i]->proxies_head; NULL != proxy; proxy=proxy->next) | ||
846 | { | ||
847 | DLL_remove(connections[i]->proxies_head, connections[i]->proxies_tail, proxy); | ||
848 | proxy->spdy_active = false; | ||
849 | } | ||
850 | spdy_free_connection(connections[i]); | ||
851 | } | ||
852 | } | ||
853 | else | ||
854 | { | ||
855 | PRINT_INFO("not called"); | ||
856 | } | ||
857 | } | ||
858 | } | ||
859 | |||
860 | void | ||
861 | spdy_run_select(fd_set * read_fd_set, | ||
862 | fd_set * write_fd_set, | ||
863 | fd_set * except_fd_set, struct SPDY_Connection *connections[], int size) | ||
864 | { | ||
865 | int i; | ||
866 | int ret; | ||
867 | struct Proxy *proxy; | ||
868 | //PRINT_INFO2("size is %i", size); | ||
869 | |||
870 | for(i=0; i<size; ++i) | ||
871 | { | ||
872 | // PRINT_INFO2("exec about to be called for %s", connections[i]->host); | ||
873 | if(FD_ISSET(connections[i]->fd, read_fd_set) || FD_ISSET(connections[i]->fd, write_fd_set) || FD_ISSET(connections[i]->fd, except_fd_set)) | ||
874 | { | ||
875 | ret = spdy_exec_io(connections[i]); | ||
876 | //PRINT_INFO2("%i",ret); | ||
877 | //if((spdy_pollfds[i].revents & POLLHUP) || (spdy_pollfds[0].revents & POLLERR)) | ||
878 | // PRINT_INFO("SPDY SPDY_Connection error"); | ||
879 | |||
880 | //TODO POLLRDHUP | ||
881 | // always close on ret != 0? | ||
882 | |||
883 | if(0 != ret) | ||
884 | { | ||
885 | glob_opt.streams_opened -= connections[i]->streams_opened; | ||
886 | if(connections[i] == glob_opt.spdy_connection) | ||
887 | { | ||
888 | glob_opt.spdy_connection = NULL; | ||
889 | } | ||
890 | else | ||
891 | { | ||
892 | DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]); | ||
893 | glob_opt.total_spdy_connections--; | ||
894 | } | ||
895 | for(proxy = connections[i]->proxies_head; NULL != proxy; proxy=proxy->next) | ||
896 | { | ||
897 | DLL_remove(connections[i]->proxies_head, connections[i]->proxies_tail, proxy); | ||
898 | proxy->spdy_active = false; | ||
899 | } | ||
900 | spdy_free_connection(connections[i]); | ||
901 | } | ||
902 | } | ||
903 | else | ||
904 | { | ||
905 | PRINT_INFO("not called"); | ||
906 | } | ||
907 | } | ||
908 | } | ||
diff --git a/src/examples/mhd2spdy_spdy.h b/src/examples/mhd2spdy_spdy.h new file mode 100644 index 00000000..e9568ea8 --- /dev/null +++ b/src/examples/mhd2spdy_spdy.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | Copyright (C) 2013 Andrey Uzunov | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file spdy.h | ||
20 | * @author Andrey Uzunov | ||
21 | */ | ||
22 | |||
23 | #ifndef SPDY_H | ||
24 | #define SPDY_H | ||
25 | |||
26 | #include "mhd2spdy_structures.h" | ||
27 | |||
28 | struct SPDY_Connection * spdy_connect(const struct URI *uri, uint16_t port, bool is_tls); | ||
29 | |||
30 | void spdy_ctl_poll(struct pollfd *pollfd, struct SPDY_Connection *connection); | ||
31 | |||
32 | bool spdy_ctl_select(fd_set * read_fd_set, | ||
33 | fd_set * write_fd_set, | ||
34 | fd_set * except_fd_set, | ||
35 | struct SPDY_Connection *connection); | ||
36 | |||
37 | int spdy_exec_io(struct SPDY_Connection *connection); | ||
38 | |||
39 | void spdy_diec(const char *func, int error_code); | ||
40 | |||
41 | int | ||
42 | spdy_request(const char **nv, struct Proxy *proxy); | ||
43 | |||
44 | void spdy_ssl_init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version); | ||
45 | |||
46 | void | ||
47 | spdy_free_connection(struct SPDY_Connection * connection); | ||
48 | |||
49 | void | ||
50 | spdy_get_pollfdset(struct pollfd fds[], struct SPDY_Connection *connections[], int max_size, nfds_t *real_size); | ||
51 | |||
52 | |||
53 | int | ||
54 | spdy_get_selectfdset(fd_set * read_fd_set, | ||
55 | fd_set * write_fd_set, | ||
56 | fd_set * except_fd_set, | ||
57 | struct SPDY_Connection *connections[], int max_size, nfds_t *real_size); | ||
58 | |||
59 | void | ||
60 | spdy_run(struct pollfd fds[], struct SPDY_Connection *connections[], int size); | ||
61 | |||
62 | void | ||
63 | spdy_run_select(fd_set * read_fd_set, | ||
64 | fd_set * write_fd_set, | ||
65 | fd_set * except_fd_set, struct SPDY_Connection *connections[], int size); | ||
66 | |||
67 | #endif | ||
diff --git a/src/examples/mhd2spdy_structures.c b/src/examples/mhd2spdy_structures.c new file mode 100644 index 00000000..a3486e3a --- /dev/null +++ b/src/examples/mhd2spdy_structures.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | Copyright (C) 2013 Andrey Uzunov | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file structures.h | ||
20 | * @author Andrey Uzunov | ||
21 | */ | ||
22 | |||
23 | #include "mhd2spdy_structures.h" | ||
24 | |||
25 | |||
26 | void | ||
27 | free_uri(struct URI * uri) | ||
28 | { | ||
29 | if(NULL != uri) | ||
30 | { | ||
31 | free(uri->full_uri); | ||
32 | free(uri->scheme); | ||
33 | free(uri->host_and_port); | ||
34 | //free(uri->host_and_port_for_connecting); | ||
35 | free(uri->host); | ||
36 | free(uri->path); | ||
37 | free(uri->path_and_more); | ||
38 | free(uri->query); | ||
39 | free(uri->fragment); | ||
40 | uri->port = 0; | ||
41 | free(uri); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | int | ||
46 | init_parse_uri(regex_t * preg) | ||
47 | { | ||
48 | // RFC 2396 | ||
49 | // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? | ||
50 | /* | ||
51 | scheme = $2 | ||
52 | authority = $4 | ||
53 | path = $5 | ||
54 | query = $7 | ||
55 | fragment = $9 | ||
56 | */ | ||
57 | |||
58 | return regcomp(preg, "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", REG_EXTENDED); | ||
59 | } | ||
60 | |||
61 | void | ||
62 | deinit_parse_uri(regex_t * preg) | ||
63 | { | ||
64 | regfree(preg); | ||
65 | } | ||
66 | |||
67 | int | ||
68 | parse_uri(regex_t * preg, char * full_uri, struct URI ** uri) | ||
69 | { | ||
70 | int ret; | ||
71 | char *colon; | ||
72 | long long port; | ||
73 | size_t nmatch = 10; | ||
74 | regmatch_t pmatch[10]; | ||
75 | |||
76 | if (0 != (ret = regexec(preg, full_uri, nmatch, pmatch, 0))) | ||
77 | return ret; | ||
78 | |||
79 | *uri = au_malloc(sizeof(struct URI)); | ||
80 | if(NULL == *uri) | ||
81 | return -200; | ||
82 | |||
83 | (*uri)->full_uri = strdup(full_uri); | ||
84 | |||
85 | asprintf(&((*uri)->scheme), "%.*s",pmatch[2].rm_eo - pmatch[2].rm_so, &full_uri[pmatch[2].rm_so]); | ||
86 | asprintf(&((*uri)->host_and_port), "%.*s",pmatch[4].rm_eo - pmatch[4].rm_so, &full_uri[pmatch[4].rm_so]); | ||
87 | asprintf(&((*uri)->path), "%.*s",pmatch[5].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]); | ||
88 | asprintf(&((*uri)->path_and_more), "%.*s",pmatch[9].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]); | ||
89 | asprintf(&((*uri)->query), "%.*s",pmatch[7].rm_eo - pmatch[7].rm_so, &full_uri[pmatch[7].rm_so]); | ||
90 | asprintf(&((*uri)->fragment), "%.*s",pmatch[9].rm_eo - pmatch[9].rm_so, &full_uri[pmatch[9].rm_so]); | ||
91 | |||
92 | colon = strrchr((*uri)->host_and_port, ':'); | ||
93 | if(NULL == colon) | ||
94 | { | ||
95 | (*uri)->host = strdup((*uri)->host_and_port); | ||
96 | /*if(0 == strcasecmp("http", uri->scheme)) | ||
97 | { | ||
98 | uri->port = 80; | ||
99 | asprintf(&(uri->host_and_port_for_connecting), "%s:80", uri->host_and_port); | ||
100 | } | ||
101 | else if(0 == strcasecmp("https", uri->scheme)) | ||
102 | { | ||
103 | uri->port = 443; | ||
104 | asprintf(&(uri->host_and_port_for_connecting), "%s:443", uri->host_and_port); | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | PRINT_INFO("no standard scheme!"); | ||
109 | */(*uri)->port = 0; | ||
110 | /*uri->host_and_port_for_connecting = strdup(uri->host_and_port); | ||
111 | }*/ | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | port = atoi(colon + 1); | ||
116 | if(port<1 || port >= 256 * 256) | ||
117 | { | ||
118 | free_uri(*uri); | ||
119 | return -100; | ||
120 | } | ||
121 | (*uri)->port = port; | ||
122 | asprintf(&((*uri)->host), "%.*s", (int)(colon - (*uri)->host_and_port), (*uri)->host_and_port); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | void | ||
128 | free_proxy(struct Proxy *proxy) | ||
129 | { | ||
130 | //PRINT_INFO("free proxy called"); | ||
131 | free(proxy->http_body); | ||
132 | free_uri(proxy->uri); | ||
133 | free(proxy->url); | ||
134 | free(proxy->http_uri); | ||
135 | free(proxy); | ||
136 | } | ||
137 | |||
138 | void *au_malloc(size_t size) | ||
139 | { | ||
140 | void *new_memory; | ||
141 | |||
142 | new_memory = malloc(size); | ||
143 | if(NULL != new_memory) | ||
144 | { | ||
145 | glob_opt.global_memory += size; | ||
146 | memset(new_memory, 0, size); | ||
147 | } | ||
148 | return new_memory; | ||
149 | } | ||
diff --git a/src/examples/mhd2spdy_structures.h b/src/examples/mhd2spdy_structures.h new file mode 100644 index 00000000..175dc62e --- /dev/null +++ b/src/examples/mhd2spdy_structures.h | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | Copyright (C) 2013 Andrey Uzunov | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file structures.h | ||
20 | * @author Andrey Uzunov | ||
21 | */ | ||
22 | #ifndef STRUCTURES_H | ||
23 | #define STRUCTURES_H | ||
24 | |||
25 | #define _GNU_SOURCE | ||
26 | |||
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 <assert.h> | ||
36 | #include <microhttpd.h> | ||
37 | #include <signal.h> | ||
38 | #include <poll.h> | ||
39 | #include <fcntl.h> | ||
40 | #include <regex.h> | ||
41 | #include <sys/types.h> | ||
42 | #include <sys/socket.h> | ||
43 | #include <netdb.h> | ||
44 | #include <netinet/in.h> | ||
45 | #include <netinet/tcp.h> | ||
46 | #include <openssl/ssl.h> | ||
47 | #include <openssl/err.h> | ||
48 | #include <spdylay/spdylay.h> | ||
49 | #include <getopt.h> | ||
50 | |||
51 | struct Proxy; | ||
52 | |||
53 | struct SPDY_Connection { | ||
54 | SSL *ssl; | ||
55 | //SSL_CTX *ssl_ctx; | ||
56 | spdylay_session *session; | ||
57 | struct SPDY_Connection *prev; | ||
58 | struct SPDY_Connection *next; | ||
59 | struct Proxy *proxies_head; | ||
60 | struct Proxy *proxies_tail; | ||
61 | char *host; | ||
62 | /* WANT_READ if SSL connection needs more input; or WANT_WRITE if it | ||
63 | needs more output; or IO_NONE. This is necessary because SSL/TLS | ||
64 | re-negotiation is possible at any time. Spdylay API offers | ||
65 | similar functions like spdylay_session_want_read() and | ||
66 | spdylay_session_want_write() but they do not take into account | ||
67 | SSL connection. */ | ||
68 | int fd; | ||
69 | int want_io; | ||
70 | uint counter; | ||
71 | uint streams_opened; | ||
72 | bool is_tls; | ||
73 | }; | ||
74 | |||
75 | |||
76 | struct URI | ||
77 | { | ||
78 | char * full_uri; | ||
79 | char * scheme; | ||
80 | char * host_and_port; | ||
81 | //char * host_and_port_for_connecting; | ||
82 | char * host; | ||
83 | char * path; | ||
84 | char * path_and_more; | ||
85 | char * query; | ||
86 | char * fragment; | ||
87 | uint16_t port; | ||
88 | }; | ||
89 | |||
90 | struct HTTP_URI; | ||
91 | |||
92 | struct Proxy | ||
93 | { | ||
94 | struct MHD_Connection *http_connection; | ||
95 | struct MHD_Response *http_response; | ||
96 | struct URI *uri; | ||
97 | struct HTTP_URI *http_uri; //TODO remove me | ||
98 | struct SPDY_Connection *spdy_connection; | ||
99 | struct Proxy *next; | ||
100 | struct Proxy *prev; | ||
101 | //char *path; | ||
102 | char *url; | ||
103 | //struct SPDY_Request *request; | ||
104 | //struct SPDY_Response *response; | ||
105 | //CURL *curl_handle; | ||
106 | //struct curl_slist *curl_headers; | ||
107 | //struct SPDY_NameValue *headers; | ||
108 | char *version; | ||
109 | //char *status_msg; | ||
110 | void *http_body; | ||
111 | size_t http_body_size; | ||
112 | ssize_t length; | ||
113 | int status; | ||
114 | int id; | ||
115 | bool done; | ||
116 | bool http_active; | ||
117 | bool spdy_active; | ||
118 | }; | ||
119 | |||
120 | struct HTTP_URI | ||
121 | { | ||
122 | char * uri; | ||
123 | struct Proxy * proxy; | ||
124 | }; | ||
125 | |||
126 | struct SPDY_Headers | ||
127 | { | ||
128 | const char **nv; | ||
129 | int num; | ||
130 | int cnt; | ||
131 | }; | ||
132 | |||
133 | struct global_options | ||
134 | { | ||
135 | char *spdy2http_str; | ||
136 | struct SPDY_Connection *spdy_connection; | ||
137 | struct SPDY_Connection *spdy_connections_head; | ||
138 | struct SPDY_Connection *spdy_connections_tail; | ||
139 | int streams_opened; | ||
140 | int responses_pending; | ||
141 | regex_t uri_preg; | ||
142 | size_t global_memory; | ||
143 | SSL_CTX *ssl_ctx; | ||
144 | uint32_t total_spdy_connections; | ||
145 | uint16_t spdy_proto_version; | ||
146 | uint16_t listen_port; | ||
147 | bool verbose; | ||
148 | bool only_proxy; | ||
149 | bool spdy_data_received; | ||
150 | } glob_opt; | ||
151 | |||
152 | /* | ||
153 | |||
154 | #define SOCK_ADDR_IN_PTR(sa) ((struct sockaddr_in *)(sa)) | ||
155 | #define SOCK_ADDR_IN_FAMILY(sa) SOCK_ADDR_IN_PTR(sa)->sin_family | ||
156 | #define SOCK_ADDR_IN_PORT(sa) SOCK_ADDR_IN_PTR(sa)->sin_port | ||
157 | #define SOCK_ADDR_IN_ADDR(sa) SOCK_ADDR_IN_PTR(sa)->sin_addr | ||
158 | |||
159 | #ifdef HAS_IPV6 | ||
160 | |||
161 | #define SOCK_ADDR_IN6_PTR(sa) ((struct sockaddr_in6 *)(sa)) | ||
162 | #define SOCK_ADDR_IN6_FAMILY(sa) SOCK_ADDR_IN6_PTR(sa)->sin6_family | ||
163 | #define SOCK_ADDR_IN6_PORT(sa) SOCK_ADDR_IN6_PTR(sa)->sin6_port | ||
164 | #define SOCK_ADDR_IN6_ADDR(sa) SOCK_ADDR_IN6_PTR(sa)->sin6_addr | ||
165 | |||
166 | #endif | ||
167 | */ | ||
168 | |||
169 | //forbidden headers | ||
170 | #define SPDY_HTTP_HEADER_TRANSFER_ENCODING "transfer-encoding" | ||
171 | #define SPDY_HTTP_HEADER_PROXY_CONNECTION "proxy-connection" | ||
172 | #define SPDY_HTTP_HEADER_KEEP_ALIVE "keep-alive" | ||
173 | #define SPDY_HTTP_HEADER_CONNECTION "connection" | ||
174 | |||
175 | #define MAX_SPDY_CONNECTIONS 100 | ||
176 | |||
177 | |||
178 | /** | ||
179 | * Insert an element at the head of a DLL. Assumes that head, tail and | ||
180 | * element are structs with prev and next fields. | ||
181 | * | ||
182 | * @param head pointer to the head of the DLL (struct ? *) | ||
183 | * @param tail pointer to the tail of the DLL (struct ? *) | ||
184 | * @param element element to insert (struct ? *) | ||
185 | */ | ||
186 | #define DLL_insert(head,tail,element) do { \ | ||
187 | (element)->next = (head); \ | ||
188 | (element)->prev = NULL; \ | ||
189 | if ((tail) == NULL) \ | ||
190 | (tail) = element; \ | ||
191 | else \ | ||
192 | (head)->prev = element; \ | ||
193 | (head) = (element); } while (0) | ||
194 | |||
195 | |||
196 | /** | ||
197 | * Remove an element from a DLL. Assumes | ||
198 | * that head, tail and element are structs | ||
199 | * with prev and next fields. | ||
200 | * | ||
201 | * @param head pointer to the head of the DLL (struct ? *) | ||
202 | * @param tail pointer to the tail of the DLL (struct ? *) | ||
203 | * @param element element to remove (struct ? *) | ||
204 | */ | ||
205 | #define DLL_remove(head,tail,element) do { \ | ||
206 | if ((element)->prev == NULL) \ | ||
207 | (head) = (element)->next; \ | ||
208 | else \ | ||
209 | (element)->prev->next = (element)->next; \ | ||
210 | if ((element)->next == NULL) \ | ||
211 | (tail) = (element)->prev; \ | ||
212 | else \ | ||
213 | (element)->next->prev = (element)->prev; \ | ||
214 | (element)->next = NULL; \ | ||
215 | (element)->prev = NULL; } while (0) | ||
216 | |||
217 | |||
218 | #define PRINT_INFO(msg) do{\ | ||
219 | if(glob_opt.verbose){\ | ||
220 | printf("%i:%s\n", __LINE__, msg);\ | ||
221 | fflush(stdout);\ | ||
222 | }\ | ||
223 | }\ | ||
224 | while(0) | ||
225 | |||
226 | |||
227 | #define PRINT_INFO2(fmt, ...) do{\ | ||
228 | if(glob_opt.verbose){\ | ||
229 | printf("%i\n", __LINE__);\ | ||
230 | printf(fmt,##__VA_ARGS__);\ | ||
231 | printf("\n");\ | ||
232 | fflush(stdout);\ | ||
233 | }\ | ||
234 | }\ | ||
235 | while(0) | ||
236 | |||
237 | |||
238 | #define DIE(msg) do{\ | ||
239 | printf("FATAL ERROR (line %i): %s\n", __LINE__, msg);\ | ||
240 | fflush(stdout);\ | ||
241 | exit(EXIT_FAILURE);\ | ||
242 | }\ | ||
243 | while(0) | ||
244 | |||
245 | |||
246 | |||
247 | |||
248 | void | ||
249 | free_uri(struct URI * uri); | ||
250 | |||
251 | int | ||
252 | init_parse_uri(regex_t * preg); | ||
253 | |||
254 | void | ||
255 | deinit_parse_uri(regex_t * preg); | ||
256 | |||
257 | int | ||
258 | parse_uri(regex_t * preg, char * full_uri, struct URI ** uri); | ||
259 | |||
260 | void | ||
261 | free_proxy(struct Proxy *proxy); | ||
262 | |||
263 | void *au_malloc(size_t size); | ||
264 | |||
265 | #endif | ||
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index a16bf62d..d14284a1 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -2312,7 +2312,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2312 | case MHD_CONNECTION_FOOTERS_SENT: | 2312 | case MHD_CONNECTION_FOOTERS_SENT: |
2313 | #if HAVE_DECL_TCP_CORK | 2313 | #if HAVE_DECL_TCP_CORK |
2314 | /* done sending, uncork */ | 2314 | /* done sending, uncork */ |
2315 | { | 2315 | if (0) { |
2316 | const int val = 0; | 2316 | const int val = 0; |
2317 | setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, | 2317 | setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, |
2318 | sizeof (val)); | 2318 | sizeof (val)); |
diff --git a/src/microspdy/io_raw.c b/src/microspdy/io_raw.c index 58127e84..357e7d84 100644 --- a/src/microspdy/io_raw.c +++ b/src/microspdy/io_raw.c | |||
@@ -159,6 +159,7 @@ SPDYF_raw_is_pending(struct SPDY_Session *session) | |||
159 | int | 159 | int |
160 | SPDYF_raw_before_write(struct SPDY_Session *session) | 160 | SPDYF_raw_before_write(struct SPDY_Session *session) |
161 | { | 161 | { |
162 | #if HAVE_DECL_TCP_CORK | ||
162 | if(0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)) | 163 | if(0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)) |
163 | { | 164 | { |
164 | int val = 1; | 165 | int val = 1; |
@@ -168,6 +169,7 @@ SPDYF_raw_before_write(struct SPDY_Session *session) | |||
168 | if(-1 == ret) | 169 | if(-1 == ret) |
169 | SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_CORK"); | 170 | SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_CORK"); |
170 | } | 171 | } |
172 | #endif | ||
171 | 173 | ||
172 | return SPDY_YES; | 174 | return SPDY_YES; |
173 | } | 175 | } |
@@ -176,6 +178,7 @@ SPDYF_raw_before_write(struct SPDY_Session *session) | |||
176 | int | 178 | int |
177 | SPDYF_raw_after_write(struct SPDY_Session *session, int was_written) | 179 | SPDYF_raw_after_write(struct SPDY_Session *session, int was_written) |
178 | { | 180 | { |
181 | #if HAVE_DECL_TCP_CORK | ||
179 | if(SPDY_YES == was_written && 0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)) | 182 | if(SPDY_YES == was_written && 0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)) |
180 | { | 183 | { |
181 | int val = 0; | 184 | int val = 0; |
@@ -186,5 +189,6 @@ SPDYF_raw_after_write(struct SPDY_Session *session, int was_written) | |||
186 | SPDYF_DEBUG("WARNING: Couldn't unset the new connection to TCP_CORK"); | 189 | SPDYF_DEBUG("WARNING: Couldn't unset the new connection to TCP_CORK"); |
187 | } | 190 | } |
188 | 191 | ||
192 | #endif | ||
189 | return was_written; | 193 | return was_written; |
190 | } | 194 | } |