aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-07-19 09:19:48 +0000
committerChristian Grothoff <christian@grothoff.org>2013-07-19 09:19:48 +0000
commit3b384315bcb2710490bfff676544b5872957f739 (patch)
treee4340910b0a8d413ed3e9bf588d601e1fc60acc3
parent32d7b92ba70509405f78b80711ef142391b63bd6 (diff)
downloadlibmicrohttpd-3b384315bcb2710490bfff676544b5872957f739.tar.gz
libmicrohttpd-3b384315bcb2710490bfff676544b5872957f739.zip
-importing Andrey Uzunov's mhd2spdy code
-rw-r--r--src/examples/Makefile.am15
-rw-r--r--src/examples/mhd2spdy.c323
-rw-r--r--src/examples/mhd2spdy_http.c450
-rw-r--r--src/examples/mhd2spdy_http.h43
-rw-r--r--src/examples/mhd2spdy_spdy.c908
-rw-r--r--src/examples/mhd2spdy_spdy.h67
-rw-r--r--src/examples/mhd2spdy_structures.c149
-rw-r--r--src/examples/mhd2spdy_structures.h265
-rw-r--r--src/microhttpd/connection.c2
-rw-r--r--src/microspdy/io_raw.c4
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
19spdyex = \ 19spdyex = \
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
24if HAVE_SPDYLAY
25spdyex += mhd2spdy
26endif
23endif 27endif
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
81mhd2spdy_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
86mhd2spdy_LDADD = \
87 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
88 -lssl -lcrypto -lspdylay
89
77benchmark_SOURCES = \ 90benchmark_SOURCES = \
78 benchmark.c 91 benchmark.c
79benchmark_LDADD = \ 92benchmark_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
39static int run = 1;
40//static int spdy_close = 0;
41
42static void catch_signal(int signal)
43{
44 //spdy_close = 1;
45 run = 0;
46}
47
48int
49run_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}
137else{*/
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
250void
251display_usage()
252{
253 printf(
254 "Usage: http2spdy [-vo] [-b <SPDY2HTTP-PROXY>] -p <PORT>\n"
255 "TODO\n"
256 );
257}
258
259
260int
261main (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
28void * 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/*
43static int
44http_query_iterate_cb(void *cls,
45 enum MHD_ValueKind kind,
46 const char *name, const char *value)
47{
48
49}*/
50
51
52static int
53http_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
80static ssize_t
81http_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
161static void
162http_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
197int
198http_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
366void
367http_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
28int
29http_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
38void * http_log_cb(void * cls, const char * uri);
39
40void
41http_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
36enum
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 */
48static 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 */
58void 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 */
72static 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 */
128static 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
198static 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
223void 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 */
262static 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 */
290static 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
315static 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 */
333static 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 */
351static 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 */
375void 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
386static 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 */
405static 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
438static 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 */
454static 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 */
467void 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 */
483bool 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 */
506int 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 */
524struct 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
603void
604spdy_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
615int
616spdy_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
669void
670spdy_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
735int
736spdy_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
812void
813spdy_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
860void
861spdy_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
28struct SPDY_Connection * spdy_connect(const struct URI *uri, uint16_t port, bool is_tls);
29
30void spdy_ctl_poll(struct pollfd *pollfd, struct SPDY_Connection *connection);
31
32bool 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
37int spdy_exec_io(struct SPDY_Connection *connection);
38
39void spdy_diec(const char *func, int error_code);
40
41int
42spdy_request(const char **nv, struct Proxy *proxy);
43
44void spdy_ssl_init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version);
45
46void
47spdy_free_connection(struct SPDY_Connection * connection);
48
49void
50spdy_get_pollfdset(struct pollfd fds[], struct SPDY_Connection *connections[], int max_size, nfds_t *real_size);
51
52
53int
54spdy_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
59void
60spdy_run(struct pollfd fds[], struct SPDY_Connection *connections[], int size);
61
62void
63spdy_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
26void
27free_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
45int
46init_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
61void
62deinit_parse_uri(regex_t * preg)
63{
64 regfree(preg);
65}
66
67int
68parse_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
127void
128free_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
138void *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
51struct Proxy;
52
53struct 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
76struct 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
90struct HTTP_URI;
91
92struct 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
120struct HTTP_URI
121{
122 char * uri;
123 struct Proxy * proxy;
124};
125
126struct SPDY_Headers
127{
128 const char **nv;
129 int num;
130 int cnt;
131};
132
133struct 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
248void
249free_uri(struct URI * uri);
250
251int
252init_parse_uri(regex_t * preg);
253
254void
255deinit_parse_uri(regex_t * preg);
256
257int
258parse_uri(regex_t * preg, char * full_uri, struct URI ** uri);
259
260void
261free_proxy(struct Proxy *proxy);
262
263void *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)
159int 159int
160SPDYF_raw_before_write(struct SPDY_Session *session) 160SPDYF_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)
176int 178int
177SPDYF_raw_after_write(struct SPDY_Session *session, int was_written) 179SPDYF_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}