diff options
author | Matthias Wachs <wachs@net.in.tum.de> | 2012-09-28 09:48:23 +0000 |
---|---|---|
committer | Matthias Wachs <wachs@net.in.tum.de> | 2012-09-28 09:48:23 +0000 |
commit | e833cb7d636f4613d3b1d9f77098a049093ef288 (patch) | |
tree | 264333e7a7f2e67e090c9360bbdce1eed78b90e4 /src/transport | |
parent | 9d7c31dff02f838f635710ad6156e286afbec3f1 (diff) | |
download | gnunet-e833cb7d636f4613d3b1d9f77098a049093ef288.tar.gz gnunet-e833cb7d636f4613d3b1d9f77098a049093ef288.zip |
rm old code
Diffstat (limited to 'src/transport')
-rw-r--r-- | src/transport/plugin_transport_http_client_old.c | 645 | ||||
-rw-r--r-- | src/transport/plugin_transport_http_server_old.c | 1336 |
2 files changed, 0 insertions, 1981 deletions
diff --git a/src/transport/plugin_transport_http_client_old.c b/src/transport/plugin_transport_http_client_old.c deleted file mode 100644 index ff23da974..000000000 --- a/src/transport/plugin_transport_http_client_old.c +++ /dev/null | |||
@@ -1,645 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2002--2012 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/plugin_transport_http_client.c | ||
23 | * @brief http transport service plugin | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | |||
27 | #include "plugin_transport_http.h" | ||
28 | |||
29 | static struct Plugin * p; | ||
30 | |||
31 | #if VERBOSE_CURL | ||
32 | /** | ||
33 | * Function to log curl debug messages with GNUNET_log | ||
34 | * @param curl handle | ||
35 | * @param type curl_infotype | ||
36 | * @param data data | ||
37 | * @param size size | ||
38 | * @param cls closure | ||
39 | * @return 0 | ||
40 | */ | ||
41 | static int | ||
42 | client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) | ||
43 | { | ||
44 | if (type == CURLINFO_TEXT) | ||
45 | { | ||
46 | char text[size + 2]; | ||
47 | |||
48 | memcpy (text, data, size); | ||
49 | if (text[size - 1] == '\n') | ||
50 | text[size] = '\0'; | ||
51 | else | ||
52 | { | ||
53 | text[size] = '\n'; | ||
54 | text[size + 1] = '\0'; | ||
55 | } | ||
56 | #if BUILD_HTTPS | ||
57 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-https", | ||
58 | "Client: %p - %s", cls, text); | ||
59 | #else | ||
60 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-http", | ||
61 | "Client: %p - %s", cls, text); | ||
62 | #endif | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | #endif | ||
67 | |||
68 | /** | ||
69 | * Task performing curl operations | ||
70 | * @param cls plugin as closure | ||
71 | * @param tc gnunet scheduler task context | ||
72 | */ | ||
73 | static void | ||
74 | client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Function setting up file descriptors and scheduling task to run | ||
79 | * | ||
80 | * @param plugin plugin as closure | ||
81 | * @param now schedule task in 1ms, regardless of what curl may say | ||
82 | * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok | ||
83 | */ | ||
84 | static int | ||
85 | client_schedule (struct Plugin *plugin, int now) | ||
86 | { | ||
87 | fd_set rs; | ||
88 | fd_set ws; | ||
89 | fd_set es; | ||
90 | int max; | ||
91 | struct GNUNET_NETWORK_FDSet *grs; | ||
92 | struct GNUNET_NETWORK_FDSet *gws; | ||
93 | long to; | ||
94 | CURLMcode mret; | ||
95 | struct GNUNET_TIME_Relative timeout; | ||
96 | |||
97 | /* Cancel previous scheduled task */ | ||
98 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
99 | { | ||
100 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
101 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
102 | } | ||
103 | max = -1; | ||
104 | FD_ZERO (&rs); | ||
105 | FD_ZERO (&ws); | ||
106 | FD_ZERO (&es); | ||
107 | mret = curl_multi_fdset (plugin->client_mh, &rs, &ws, &es, &max); | ||
108 | if (mret != CURLM_OK) | ||
109 | { | ||
110 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | ||
111 | "curl_multi_fdset", __FILE__, __LINE__, | ||
112 | curl_multi_strerror (mret)); | ||
113 | return GNUNET_SYSERR; | ||
114 | } | ||
115 | mret = curl_multi_timeout (plugin->client_mh, &to); | ||
116 | if (to == -1) | ||
117 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1); | ||
118 | else | ||
119 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to); | ||
120 | if (now == GNUNET_YES) | ||
121 | timeout = GNUNET_TIME_UNIT_MILLISECONDS; | ||
122 | |||
123 | if (mret != CURLM_OK) | ||
124 | { | ||
125 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | ||
126 | "curl_multi_timeout", __FILE__, __LINE__, | ||
127 | curl_multi_strerror (mret)); | ||
128 | return GNUNET_SYSERR; | ||
129 | } | ||
130 | |||
131 | grs = GNUNET_NETWORK_fdset_create (); | ||
132 | gws = GNUNET_NETWORK_fdset_create (); | ||
133 | GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); | ||
134 | GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); | ||
135 | |||
136 | plugin->client_perform_task = | ||
137 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
138 | timeout, grs, gws, | ||
139 | &client_run, plugin); | ||
140 | GNUNET_NETWORK_fdset_destroy (gws); | ||
141 | GNUNET_NETWORK_fdset_destroy (grs); | ||
142 | return GNUNET_OK; | ||
143 | } | ||
144 | |||
145 | |||
146 | int | ||
147 | client_send (struct Session *s, struct HTTP_Message *msg) | ||
148 | { | ||
149 | GNUNET_assert (s != NULL); | ||
150 | GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); | ||
151 | |||
152 | if (GNUNET_YES != exist_session(p, s)) | ||
153 | { | ||
154 | GNUNET_break (0); | ||
155 | return GNUNET_SYSERR; | ||
156 | } | ||
157 | if (s->client_put_paused == GNUNET_YES) | ||
158 | { | ||
159 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
160 | "Client: %p was suspended, unpausing\n", s->client_put); | ||
161 | s->client_put_paused = GNUNET_NO; | ||
162 | curl_easy_pause (s->client_put, CURLPAUSE_CONT); | ||
163 | } | ||
164 | client_schedule (s->plugin, GNUNET_YES); | ||
165 | |||
166 | return GNUNET_OK; | ||
167 | } | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Task performing curl operations | ||
172 | * | ||
173 | * @param cls plugin as closure | ||
174 | * @param tc gnunet scheduler task context | ||
175 | */ | ||
176 | static void | ||
177 | client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
178 | { | ||
179 | struct Plugin *plugin = cls; | ||
180 | int running; | ||
181 | CURLMcode mret; | ||
182 | |||
183 | GNUNET_assert (cls != NULL); | ||
184 | |||
185 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
186 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
187 | return; | ||
188 | |||
189 | do | ||
190 | { | ||
191 | running = 0; | ||
192 | mret = curl_multi_perform (plugin->client_mh, &running); | ||
193 | |||
194 | CURLMsg *msg; | ||
195 | int msgs_left; | ||
196 | |||
197 | while ((msg = curl_multi_info_read (plugin->client_mh, &msgs_left))) | ||
198 | { | ||
199 | CURL *easy_h = msg->easy_handle; | ||
200 | struct Session *s = NULL; | ||
201 | char *d = (char *) s; | ||
202 | |||
203 | if (easy_h == NULL) | ||
204 | { | ||
205 | GNUNET_break (0); | ||
206 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
207 | "Client: connection to ended with reason %i: `%s', %i handles running\n", | ||
208 | msg->data.result, | ||
209 | curl_easy_strerror (msg->data.result), running); | ||
210 | continue; | ||
211 | } | ||
212 | |||
213 | GNUNET_assert (CURLE_OK == | ||
214 | curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); | ||
215 | s = (struct Session *) d; | ||
216 | |||
217 | if (GNUNET_YES != exist_session(plugin, s)) | ||
218 | { | ||
219 | GNUNET_break (0); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | GNUNET_assert (s != NULL); | ||
224 | if (msg->msg == CURLMSG_DONE) | ||
225 | { | ||
226 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
227 | "Client: %p connection to '%s' %s ended with reason %i: `%s'\n", | ||
228 | msg->easy_handle, GNUNET_i2s (&s->target), | ||
229 | http_plugin_address_to_string (NULL, s->addr, | ||
230 | s->addrlen), | ||
231 | msg->data.result, | ||
232 | curl_easy_strerror (msg->data.result)); | ||
233 | |||
234 | /* Disconnect other transmission direction and tell transport */ | ||
235 | client_disconnect (s); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | while (mret == CURLM_CALL_MULTI_PERFORM); | ||
240 | client_schedule (plugin, GNUNET_NO); | ||
241 | } | ||
242 | |||
243 | |||
244 | int | ||
245 | client_disconnect (struct Session *s) | ||
246 | { | ||
247 | int res = GNUNET_OK; | ||
248 | CURLMcode mret; | ||
249 | struct Plugin *plugin = s->plugin; | ||
250 | struct HTTP_Message *msg; | ||
251 | struct HTTP_Message *t; | ||
252 | |||
253 | if (GNUNET_YES != exist_session(plugin, s)) | ||
254 | { | ||
255 | GNUNET_break (0); | ||
256 | return GNUNET_SYSERR; | ||
257 | } | ||
258 | |||
259 | if (s->client_put != NULL) | ||
260 | { | ||
261 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
262 | "Client: %p / %p Deleting outbound PUT session to peer `%s'\n", | ||
263 | s, s->client_put, GNUNET_i2s (&s->target)); | ||
264 | |||
265 | /* remove curl handle from multi handle */ | ||
266 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_put); | ||
267 | if (mret != CURLM_OK) | ||
268 | { | ||
269 | /* clean up easy handle, handle is now invalid and free'd */ | ||
270 | res = GNUNET_SYSERR; | ||
271 | GNUNET_break (0); | ||
272 | } | ||
273 | curl_easy_cleanup (s->client_put); | ||
274 | s->client_put = NULL; | ||
275 | } | ||
276 | |||
277 | |||
278 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
279 | { | ||
280 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
281 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
282 | } | ||
283 | |||
284 | if (s->client_get != NULL) | ||
285 | { | ||
286 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
287 | "Client: %p / %p Deleting outbound GET session to peer `%s'\n", | ||
288 | s, | ||
289 | s->client_get, GNUNET_i2s (&s->target)); | ||
290 | |||
291 | /* remove curl handle from multi handle */ | ||
292 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_get); | ||
293 | if (mret != CURLM_OK) | ||
294 | { | ||
295 | /* clean up easy handle, handle is now invalid and free'd */ | ||
296 | res = GNUNET_SYSERR; | ||
297 | GNUNET_break (0); | ||
298 | } | ||
299 | curl_easy_cleanup (s->client_get); | ||
300 | s->client_get = NULL; | ||
301 | } | ||
302 | |||
303 | msg = s->msg_head; | ||
304 | while (msg != NULL) | ||
305 | { | ||
306 | t = msg->next; | ||
307 | if (NULL != msg->transmit_cont) | ||
308 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
309 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
310 | GNUNET_free (msg); | ||
311 | msg = t; | ||
312 | } | ||
313 | |||
314 | plugin->cur_connections -= 2; | ||
315 | |||
316 | notify_session_end (plugin, &s->target, s); | ||
317 | |||
318 | GNUNET_assert (plugin->outbound_sessions > 0); | ||
319 | plugin->outbound_sessions --; | ||
320 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
321 | "# HTTP outbound sessions", | ||
322 | plugin->outbound_sessions, | ||
323 | GNUNET_NO); | ||
324 | |||
325 | /* Re-schedule since handles have changed */ | ||
326 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
327 | { | ||
328 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
329 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
330 | } | ||
331 | client_schedule (plugin, GNUNET_YES); | ||
332 | |||
333 | return res; | ||
334 | } | ||
335 | |||
336 | static int | ||
337 | client_receive_mst_cb (void *cls, void *client, | ||
338 | const struct GNUNET_MessageHeader *message) | ||
339 | { | ||
340 | struct Session *s = cls; | ||
341 | struct GNUNET_TIME_Relative delay; | ||
342 | |||
343 | if (GNUNET_YES != exist_session(p, s)) | ||
344 | { | ||
345 | GNUNET_break (0); | ||
346 | return GNUNET_OK; | ||
347 | } | ||
348 | |||
349 | delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); | ||
350 | s->next_receive = | ||
351 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); | ||
352 | |||
353 | if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) | ||
354 | { | ||
355 | struct Plugin *plugin = s->plugin; | ||
356 | |||
357 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
358 | "Client: peer `%s' address `%s' next read delayed for %llu ms\n", | ||
359 | GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), | ||
360 | delay); | ||
361 | } | ||
362 | return GNUNET_OK; | ||
363 | } | ||
364 | |||
365 | |||
366 | static void | ||
367 | client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
368 | { | ||
369 | struct Session *s = cls; | ||
370 | |||
371 | if (GNUNET_YES != exist_session(p, s)) | ||
372 | { | ||
373 | GNUNET_break (0); | ||
374 | return; | ||
375 | } | ||
376 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
377 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
378 | return; | ||
379 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
380 | "Client: %p Waking up receive handle\n", s->client_get); | ||
381 | if (s->client_get != NULL) | ||
382 | curl_easy_pause (s->client_get, CURLPAUSE_CONT); | ||
383 | } | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Callback method used with libcurl | ||
388 | * Method is called when libcurl needs to write data during sending | ||
389 | * | ||
390 | * @param stream pointer where to write data | ||
391 | * @param size size of an individual element | ||
392 | * @param nmemb count of elements that can be written to the buffer | ||
393 | * @param cls destination pointer, passed to the libcurl handle | ||
394 | * @return bytes read from stream | ||
395 | */ | ||
396 | static size_t | ||
397 | client_receive (void *stream, size_t size, size_t nmemb, void *cls) | ||
398 | { | ||
399 | struct Session *s = cls; | ||
400 | struct GNUNET_TIME_Absolute now; | ||
401 | size_t len = size * nmemb; | ||
402 | struct Plugin *plugin = s->plugin; | ||
403 | |||
404 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
405 | "Client: Received %u bytes from peer `%s'\n", len, | ||
406 | GNUNET_i2s (&s->target)); | ||
407 | now = GNUNET_TIME_absolute_get (); | ||
408 | if (now.abs_value < s->next_receive.abs_value) | ||
409 | { | ||
410 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
411 | struct GNUNET_TIME_Relative delta = | ||
412 | GNUNET_TIME_absolute_get_difference (now, s->next_receive); | ||
413 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
414 | "Client: %p No inbound bandwidth available! Next read was delayed for %llu ms\n", | ||
415 | s->client_get, delta.rel_value); | ||
416 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
417 | { | ||
418 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
419 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
420 | } | ||
421 | s->recv_wakeup_task = | ||
422 | GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s); | ||
423 | return CURLPAUSE_ALL; | ||
424 | } | ||
425 | if (NULL == s->msg_tk) | ||
426 | s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s); | ||
427 | GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO); | ||
428 | return len; | ||
429 | } | ||
430 | |||
431 | |||
432 | /** | ||
433 | * Callback method used with libcurl | ||
434 | * Method is called when libcurl needs to read data during sending | ||
435 | * | ||
436 | * @param stream pointer where to write data | ||
437 | * @param size size of an individual element | ||
438 | * @param nmemb count of elements that can be written to the buffer | ||
439 | * @param cls source pointer, passed to the libcurl handle | ||
440 | * @return bytes written to stream, returning 0 will terminate connection! | ||
441 | */ | ||
442 | static size_t | ||
443 | client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) | ||
444 | { | ||
445 | struct Session *s = cls; | ||
446 | struct Plugin *plugin = s->plugin; | ||
447 | struct HTTP_Message *msg = s->msg_head; | ||
448 | size_t len; | ||
449 | |||
450 | if (GNUNET_YES != exist_session(plugin, s)) | ||
451 | { | ||
452 | GNUNET_break (0); | ||
453 | return 0; | ||
454 | } | ||
455 | if (NULL == msg) | ||
456 | { | ||
457 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
458 | "Client: %p Nothing to send! Suspending PUT handle!\n", | ||
459 | s->client_put); | ||
460 | s->client_put_paused = GNUNET_YES; | ||
461 | return CURL_READFUNC_PAUSE; | ||
462 | } | ||
463 | /* data to send */ | ||
464 | GNUNET_assert (msg->pos < msg->size); | ||
465 | /* calculate how much fits in buffer */ | ||
466 | len = GNUNET_MIN (msg->size - msg->pos, | ||
467 | size * nmemb); | ||
468 | memcpy (stream, &msg->buf[msg->pos], len); | ||
469 | msg->pos += len; | ||
470 | if (msg->pos == msg->size) | ||
471 | { | ||
472 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
473 | "Client: %p Message with %u bytes sent, removing message from queue\n", | ||
474 | s->client_put, msg->size, msg->pos); | ||
475 | /* Calling transmit continuation */ | ||
476 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
477 | if (NULL != msg->transmit_cont) | ||
478 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); | ||
479 | GNUNET_free (msg); | ||
480 | } | ||
481 | return len; | ||
482 | } | ||
483 | |||
484 | |||
485 | int | ||
486 | client_connect (struct Session *s) | ||
487 | { | ||
488 | struct Plugin *plugin = s->plugin; | ||
489 | int res = GNUNET_OK; | ||
490 | char *url; | ||
491 | CURLMcode mret; | ||
492 | |||
493 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
494 | "Initiating outbound session peer `%s'\n", | ||
495 | GNUNET_i2s (&s->target)); | ||
496 | s->inbound = GNUNET_NO; | ||
497 | plugin->last_tag++; | ||
498 | /* create url */ | ||
499 | GNUNET_asprintf (&url, "%s%s;%u", | ||
500 | http_plugin_address_to_string (plugin, s->addr, s->addrlen), | ||
501 | GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey), | ||
502 | plugin->last_tag); | ||
503 | #if 0 | ||
504 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url); | ||
505 | #endif | ||
506 | /* create get connection */ | ||
507 | s->client_get = curl_easy_init (); | ||
508 | #if VERBOSE_CURL | ||
509 | curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L); | ||
510 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log); | ||
511 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get); | ||
512 | #endif | ||
513 | #if BUILD_HTTPS | ||
514 | curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
515 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0); | ||
516 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0); | ||
517 | #endif | ||
518 | curl_easy_setopt (s->client_get, CURLOPT_URL, url); | ||
519 | //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb); | ||
520 | //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps); | ||
521 | curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb); | ||
522 | curl_easy_setopt (s->client_get, CURLOPT_READDATA, s); | ||
523 | curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive); | ||
524 | curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s); | ||
525 | curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS, | ||
526 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
527 | curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s); | ||
528 | curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS, | ||
529 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
530 | curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE, | ||
531 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
532 | #if CURL_TCP_NODELAY | ||
533 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); | ||
534 | #endif | ||
535 | |||
536 | /* create put connection */ | ||
537 | s->client_put = curl_easy_init (); | ||
538 | #if VERBOSE_CURL | ||
539 | curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L); | ||
540 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log); | ||
541 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put); | ||
542 | #endif | ||
543 | #if BUILD_HTTPS | ||
544 | curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
545 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0); | ||
546 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0); | ||
547 | #endif | ||
548 | curl_easy_setopt (s->client_put, CURLOPT_URL, url); | ||
549 | curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L); | ||
550 | //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb); | ||
551 | //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps); | ||
552 | curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb); | ||
553 | curl_easy_setopt (s->client_put, CURLOPT_READDATA, s); | ||
554 | curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive); | ||
555 | curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s); | ||
556 | curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS, | ||
557 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
558 | curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s); | ||
559 | curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS, | ||
560 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
561 | curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE, | ||
562 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
563 | #if CURL_TCP_NODELAY | ||
564 | curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); | ||
565 | #endif | ||
566 | |||
567 | GNUNET_free (url); | ||
568 | |||
569 | mret = curl_multi_add_handle (plugin->client_mh, s->client_get); | ||
570 | if (mret != CURLM_OK) | ||
571 | { | ||
572 | curl_easy_cleanup (s->client_get); | ||
573 | res = GNUNET_SYSERR; | ||
574 | GNUNET_break (0); | ||
575 | } | ||
576 | |||
577 | mret = curl_multi_add_handle (plugin->client_mh, s->client_put); | ||
578 | if (mret != CURLM_OK) | ||
579 | { | ||
580 | curl_multi_remove_handle (plugin->client_mh, s->client_get); | ||
581 | curl_easy_cleanup (s->client_get); | ||
582 | curl_easy_cleanup (s->client_put); | ||
583 | res = GNUNET_SYSERR; | ||
584 | GNUNET_break (0); | ||
585 | } | ||
586 | |||
587 | /* Perform connect */ | ||
588 | plugin->cur_connections += 2; | ||
589 | |||
590 | plugin->outbound_sessions ++; | ||
591 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
592 | "# HTTP outbound sessions", | ||
593 | plugin->outbound_sessions, | ||
594 | GNUNET_NO); | ||
595 | |||
596 | /* Re-schedule since handles have changed */ | ||
597 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
598 | { | ||
599 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
600 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
601 | } | ||
602 | plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin); | ||
603 | |||
604 | return res; | ||
605 | } | ||
606 | |||
607 | |||
608 | int | ||
609 | client_start (struct Plugin *plugin) | ||
610 | { | ||
611 | int res = GNUNET_OK; | ||
612 | p = plugin; | ||
613 | |||
614 | curl_global_init (CURL_GLOBAL_ALL); | ||
615 | plugin->client_mh = curl_multi_init (); | ||
616 | |||
617 | if (NULL == plugin->client_mh) | ||
618 | { | ||
619 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
620 | _ | ||
621 | ("Could not initialize curl multi handle, failed to start %s plugin!\n"), | ||
622 | plugin->name); | ||
623 | res = GNUNET_SYSERR; | ||
624 | } | ||
625 | return res; | ||
626 | } | ||
627 | |||
628 | |||
629 | void | ||
630 | client_stop (struct Plugin *plugin) | ||
631 | { | ||
632 | p = NULL; | ||
633 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
634 | { | ||
635 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
636 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
637 | } | ||
638 | |||
639 | curl_multi_cleanup (plugin->client_mh); | ||
640 | curl_global_cleanup (); | ||
641 | } | ||
642 | |||
643 | |||
644 | |||
645 | /* end of plugin_transport_http_client.c */ | ||
diff --git a/src/transport/plugin_transport_http_server_old.c b/src/transport/plugin_transport_http_server_old.c deleted file mode 100644 index f81f5cf6e..000000000 --- a/src/transport/plugin_transport_http_server_old.c +++ /dev/null | |||
@@ -1,1336 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/plugin_transport_http.c | ||
23 | * @brief http transport service plugin | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | |||
27 | #include "plugin_transport_http.h" | ||
28 | |||
29 | #define HTTP_ERROR_RESPONSE "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>" | ||
30 | #define _RECEIVE 0 | ||
31 | #define _SEND 1 | ||
32 | |||
33 | static struct Plugin * p; | ||
34 | |||
35 | /** | ||
36 | * Function that queries MHD's select sets and | ||
37 | * starts the task waiting for them. | ||
38 | * @param plugin plugin | ||
39 | * @param daemon_handle the MHD daemon handle | ||
40 | * @param now schedule now or with MHD delay | ||
41 | * @return gnunet task identifier | ||
42 | */ | ||
43 | static GNUNET_SCHEDULER_TaskIdentifier | ||
44 | server_schedule (struct Plugin *plugin, | ||
45 | struct MHD_Daemon *daemon_handle, | ||
46 | int now); | ||
47 | |||
48 | static void | ||
49 | server_log (void *arg, const char *fmt, va_list ap) | ||
50 | { | ||
51 | char text[1024]; | ||
52 | |||
53 | vsnprintf (text, sizeof (text), fmt, ap); | ||
54 | va_end (ap); | ||
55 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Check if incoming connection is accepted. | ||
60 | * NOTE: Here every connection is accepted | ||
61 | * @param cls plugin as closure | ||
62 | * @param addr address of incoming connection | ||
63 | * @param addr_len address length of incoming connection | ||
64 | * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected | ||
65 | * | ||
66 | */ | ||
67 | static int | ||
68 | server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) | ||
69 | { | ||
70 | struct Plugin *plugin = cls; | ||
71 | |||
72 | if (plugin->cur_connections <= plugin->max_connections) | ||
73 | return MHD_YES; | ||
74 | else | ||
75 | { | ||
76 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
77 | "Server: Cannot accept new connections\n"); | ||
78 | return MHD_NO; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | |||
83 | #if BUILD_HTTPS | ||
84 | static char * | ||
85 | server_load_file (const char *file) | ||
86 | { | ||
87 | struct GNUNET_DISK_FileHandle *gn_file; | ||
88 | uint64_t fsize; | ||
89 | char *text = NULL; | ||
90 | |||
91 | if (GNUNET_OK != GNUNET_DISK_file_size (file, | ||
92 | &fsize, GNUNET_NO, GNUNET_YES)) | ||
93 | return NULL; | ||
94 | text = GNUNET_malloc (fsize + 1); | ||
95 | gn_file = | ||
96 | GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, | ||
97 | GNUNET_DISK_PERM_USER_READ); | ||
98 | if (gn_file == NULL) | ||
99 | { | ||
100 | GNUNET_free (text); | ||
101 | return NULL; | ||
102 | } | ||
103 | if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize)) | ||
104 | { | ||
105 | GNUNET_free (text); | ||
106 | GNUNET_DISK_file_close (gn_file); | ||
107 | return NULL; | ||
108 | } | ||
109 | text[fsize] = '\0'; | ||
110 | GNUNET_DISK_file_close (gn_file); | ||
111 | return text; | ||
112 | } | ||
113 | #endif | ||
114 | |||
115 | |||
116 | #if BUILD_HTTPS | ||
117 | |||
118 | static int | ||
119 | server_load_certificate (struct Plugin *plugin) | ||
120 | { | ||
121 | int res = GNUNET_OK; | ||
122 | |||
123 | char *key_file; | ||
124 | char *cert_file; | ||
125 | |||
126 | /* Get crypto init string from config | ||
127 | * If not present just use default values */ | ||
128 | |||
129 | GNUNET_assert (GNUNET_OK == | ||
130 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, | ||
131 | plugin->name, | ||
132 | "CRYPTO_INIT", | ||
133 | &plugin->crypto_init)); | ||
134 | |||
135 | if (GNUNET_OK != | ||
136 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, | ||
137 | "KEY_FILE", &key_file)) | ||
138 | { | ||
139 | key_file = GNUNET_strdup ("https_key.key"); | ||
140 | } | ||
141 | |||
142 | if (GNUNET_OK != | ||
143 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, | ||
144 | "CERT_FILE", &cert_file)) | ||
145 | { | ||
146 | GNUNET_asprintf (&cert_file, "%s", "https_cert.crt"); | ||
147 | } | ||
148 | |||
149 | /* read key & certificates from file */ | ||
150 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
151 | "Loading TLS certificate from key-file `%s' cert-file`%s'\n", | ||
152 | key_file, cert_file); | ||
153 | |||
154 | plugin->key = server_load_file (key_file); | ||
155 | plugin->cert = server_load_file (cert_file); | ||
156 | |||
157 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
158 | { | ||
159 | struct GNUNET_OS_Process *cert_creation; | ||
160 | |||
161 | GNUNET_free_non_null (plugin->key); | ||
162 | plugin->key = NULL; | ||
163 | GNUNET_free_non_null (plugin->cert); | ||
164 | plugin->cert = NULL; | ||
165 | |||
166 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
167 | "No usable TLS certificate found, creating certificate\n"); | ||
168 | errno = 0; | ||
169 | cert_creation = | ||
170 | GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, | ||
171 | "gnunet-transport-certificate-creation", | ||
172 | "gnunet-transport-certificate-creation", | ||
173 | key_file, cert_file, NULL); | ||
174 | if (cert_creation == NULL) | ||
175 | { | ||
176 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
177 | _ | ||
178 | ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); | ||
179 | GNUNET_free (key_file); | ||
180 | GNUNET_free (cert_file); | ||
181 | |||
182 | GNUNET_free_non_null (plugin->key); | ||
183 | plugin->key = NULL; | ||
184 | GNUNET_free_non_null (plugin->cert); | ||
185 | plugin->cert = NULL; | ||
186 | GNUNET_free_non_null (plugin->crypto_init); | ||
187 | plugin->crypto_init = NULL; | ||
188 | |||
189 | return GNUNET_SYSERR; | ||
190 | } | ||
191 | GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); | ||
192 | GNUNET_OS_process_destroy (cert_creation); | ||
193 | |||
194 | plugin->key = server_load_file (key_file); | ||
195 | plugin->cert = server_load_file (cert_file); | ||
196 | } | ||
197 | |||
198 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
199 | { | ||
200 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
201 | _ | ||
202 | ("No usable TLS certificate found and creating one failed!\n"), | ||
203 | "transport-https"); | ||
204 | GNUNET_free (key_file); | ||
205 | GNUNET_free (cert_file); | ||
206 | |||
207 | GNUNET_free_non_null (plugin->key); | ||
208 | plugin->key = NULL; | ||
209 | GNUNET_free_non_null (plugin->cert); | ||
210 | plugin->cert = NULL; | ||
211 | GNUNET_free_non_null (plugin->crypto_init); | ||
212 | plugin->crypto_init = NULL; | ||
213 | |||
214 | return GNUNET_SYSERR; | ||
215 | } | ||
216 | GNUNET_free (key_file); | ||
217 | GNUNET_free (cert_file); | ||
218 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); | ||
219 | return res; | ||
220 | } | ||
221 | #endif | ||
222 | |||
223 | |||
224 | /** | ||
225 | * Reschedule the execution of both IPv4 and IPv6 server | ||
226 | * @param plugin the plugin | ||
227 | * @param server which server to schedule v4 or v6? | ||
228 | * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait | ||
229 | * until timeout | ||
230 | */ | ||
231 | static void | ||
232 | server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) | ||
233 | { | ||
234 | if ((server == plugin->server_v4) && (plugin->server_v4 != NULL)) | ||
235 | { | ||
236 | if (GNUNET_YES == plugin->server_v4_immediately) | ||
237 | return; /* No rescheduling, server will run asap */ | ||
238 | |||
239 | if (GNUNET_YES == now) | ||
240 | plugin->server_v4_immediately = GNUNET_YES; | ||
241 | |||
242 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
243 | { | ||
244 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
245 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
246 | } | ||
247 | plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now); | ||
248 | } | ||
249 | |||
250 | if ((server == plugin->server_v6) && (plugin->server_v6 != NULL)) | ||
251 | { | ||
252 | if (GNUNET_YES == plugin->server_v6_immediately) | ||
253 | return; /* No rescheduling, server will run asap */ | ||
254 | |||
255 | if (GNUNET_YES == now) | ||
256 | plugin->server_v6_immediately = GNUNET_YES; | ||
257 | |||
258 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
259 | { | ||
260 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
261 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
262 | } | ||
263 | plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * Callback called by MessageStreamTokenizer when a message has arrived | ||
269 | * @param cls current session as closure | ||
270 | * @param client clien | ||
271 | * @param message the message to be forwarded to transport service | ||
272 | */ | ||
273 | static int | ||
274 | server_receive_mst_cb (void *cls, void *client, | ||
275 | const struct GNUNET_MessageHeader *message) | ||
276 | { | ||
277 | struct Session *s = cls; | ||
278 | |||
279 | GNUNET_assert (NULL != p); | ||
280 | if (GNUNET_NO == exist_session(p, s)) | ||
281 | return GNUNET_OK; | ||
282 | |||
283 | struct Plugin *plugin = s->plugin; | ||
284 | struct GNUNET_TIME_Relative delay; | ||
285 | |||
286 | delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); | ||
287 | |||
288 | s->next_receive = | ||
289 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); | ||
290 | |||
291 | if (delay.rel_value > 0) | ||
292 | { | ||
293 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
294 | "Server: peer `%s' address `%s' next read delayed for %llu ms\n", | ||
295 | GNUNET_i2s (&s->target), | ||
296 | http_plugin_address_to_string (NULL, s->addr, s->addrlen), | ||
297 | delay); | ||
298 | } | ||
299 | return GNUNET_OK; | ||
300 | } | ||
301 | |||
302 | |||
303 | /** | ||
304 | * Callback called by MHD when it needs data to send | ||
305 | * @param cls current session | ||
306 | * @param pos position in buffer | ||
307 | * @param buf the buffer to write data to | ||
308 | * @param max max number of bytes available in buffer | ||
309 | * @return bytes written to buffer | ||
310 | */ | ||
311 | static ssize_t | ||
312 | server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) | ||
313 | { | ||
314 | struct Session *s = cls; | ||
315 | ssize_t bytes_read = 0; | ||
316 | struct HTTP_Message *msg; | ||
317 | |||
318 | GNUNET_assert (NULL != p); | ||
319 | if (GNUNET_NO == exist_session(p, s)) | ||
320 | return 0; | ||
321 | msg = s->msg_head; | ||
322 | if (NULL != msg) | ||
323 | { | ||
324 | /* sending */ | ||
325 | bytes_read = GNUNET_MIN (msg->size - msg->pos, | ||
326 | max); | ||
327 | memcpy (buf, &msg->buf[msg->pos], bytes_read); | ||
328 | msg->pos += bytes_read; | ||
329 | |||
330 | /* removing message */ | ||
331 | if (msg->pos == msg->size) | ||
332 | { | ||
333 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
334 | if (NULL != msg->transmit_cont) | ||
335 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); | ||
336 | GNUNET_free (msg); | ||
337 | } | ||
338 | } | ||
339 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
340 | "Server: %p: sent %u bytes\n", s, bytes_read); | ||
341 | return bytes_read; | ||
342 | } | ||
343 | |||
344 | |||
345 | static struct Session * | ||
346 | server_lookup_session (struct Plugin *plugin, | ||
347 | struct ServerConnection * sc) | ||
348 | { | ||
349 | struct Session *s; | ||
350 | |||
351 | for (s = plugin->head; NULL != s; s = s->next) | ||
352 | if ((s->server_recv == sc) || (s->server_send == sc)) | ||
353 | return s; | ||
354 | for (s = plugin->server_semi_head; NULL != s; s = s->next) | ||
355 | if ((s->server_recv == sc) || (s->server_send == sc)) | ||
356 | return s; | ||
357 | return NULL; | ||
358 | } | ||
359 | |||
360 | |||
361 | static struct ServerConnection * | ||
362 | server_lookup_serverconnection (struct Plugin *plugin, | ||
363 | struct MHD_Connection *mhd_connection, const char *url, | ||
364 | const char *method) | ||
365 | { | ||
366 | struct Session *s = NULL; | ||
367 | struct Session *t; | ||
368 | struct ServerConnection *sc = NULL; | ||
369 | const union MHD_ConnectionInfo *conn_info; | ||
370 | struct GNUNET_ATS_Information ats; | ||
371 | struct IPv4HttpAddress a4; | ||
372 | struct IPv6HttpAddress a6; | ||
373 | struct sockaddr_in *s4; | ||
374 | struct sockaddr_in6 *s6; | ||
375 | void *a; | ||
376 | size_t a_len; | ||
377 | struct GNUNET_PeerIdentity target; | ||
378 | uint32_t tag = 0; | ||
379 | int direction = GNUNET_SYSERR; | ||
380 | |||
381 | /* url parsing variables */ | ||
382 | size_t url_len; | ||
383 | char *url_end; | ||
384 | char *hash_start; | ||
385 | char *hash_end; | ||
386 | char *tag_start; | ||
387 | char *tag_end; | ||
388 | |||
389 | conn_info = MHD_get_connection_info (mhd_connection, | ||
390 | MHD_CONNECTION_INFO_CLIENT_ADDRESS); | ||
391 | if ((conn_info->client_addr->sa_family != AF_INET) && | ||
392 | (conn_info->client_addr->sa_family != AF_INET6)) | ||
393 | return NULL; | ||
394 | |||
395 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
396 | "New %s connection from %s\n", | ||
397 | method, url); | ||
398 | /* URL parsing | ||
399 | * URL is valid if it is in the form [peerid[103];tag]*/ | ||
400 | url_len = strlen (url); | ||
401 | url_end = (char *) &url[url_len]; | ||
402 | |||
403 | if (url_len < 105) | ||
404 | { | ||
405 | goto error; /* too short */ | ||
406 | } | ||
407 | hash_start = strrchr (url, '/'); | ||
408 | if (NULL == hash_start) | ||
409 | { | ||
410 | goto error; /* '/' delimiter not found */ | ||
411 | } | ||
412 | if (hash_start >= url_end) | ||
413 | { | ||
414 | goto error; /* mal formed */ | ||
415 | } | ||
416 | hash_start++; | ||
417 | |||
418 | hash_end = strrchr (hash_start, ';'); | ||
419 | if (NULL == hash_end) | ||
420 | goto error; /* ';' delimiter not found */ | ||
421 | if (hash_end >= url_end) | ||
422 | { | ||
423 | goto error; /* mal formed */ | ||
424 | } | ||
425 | |||
426 | if (hash_start >= hash_end) | ||
427 | { | ||
428 | goto error; /* mal formed */ | ||
429 | } | ||
430 | |||
431 | if ((strlen(hash_start) - strlen(hash_end)) != 103) | ||
432 | { | ||
433 | goto error; /* invalid hash length */ | ||
434 | } | ||
435 | |||
436 | char hash[104]; | ||
437 | memcpy (hash, hash_start, 103); | ||
438 | hash[103] = '\0'; | ||
439 | if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((const char *) hash, &(target.hashPubKey))) | ||
440 | { | ||
441 | goto error; /* mal formed */ | ||
442 | } | ||
443 | |||
444 | if (hash_end >= url_end) | ||
445 | { | ||
446 | goto error; /* mal formed */ | ||
447 | } | ||
448 | |||
449 | tag_start = &hash_end[1]; | ||
450 | /* Converting tag */ | ||
451 | tag_end = NULL; | ||
452 | tag = strtoul (tag_start, &tag_end, 10); | ||
453 | if (tag == 0) | ||
454 | { | ||
455 | goto error; /* mal formed */ | ||
456 | } | ||
457 | if (tag_end == NULL) | ||
458 | { | ||
459 | goto error; /* mal formed */ | ||
460 | } | ||
461 | if (tag_end != url_end) | ||
462 | { | ||
463 | goto error; /* mal formed */ | ||
464 | } | ||
465 | |||
466 | if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) | ||
467 | direction = _RECEIVE; | ||
468 | else if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) | ||
469 | direction = _SEND; | ||
470 | else | ||
471 | { | ||
472 | goto error; | ||
473 | } | ||
474 | |||
475 | plugin->cur_connections++; | ||
476 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
477 | "Server: New %s connection from %s with tag %u\n", | ||
478 | method, | ||
479 | GNUNET_i2s (&target), tag); | ||
480 | |||
481 | /* find duplicate session */ | ||
482 | t = plugin->head; | ||
483 | while (t != NULL) | ||
484 | { | ||
485 | if ((t->inbound) && | ||
486 | (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) | ||
487 | && | ||
488 | /* FIXME add source address comparison */ | ||
489 | (t->tag == tag)) | ||
490 | break; | ||
491 | t = t->next; | ||
492 | } | ||
493 | if (t != NULL) | ||
494 | { | ||
495 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
496 | "Server: Duplicate session, dismissing new connection from peer `%s'\n", | ||
497 | GNUNET_i2s (&target)); | ||
498 | goto error; | ||
499 | } | ||
500 | |||
501 | /* find semi-session */ | ||
502 | t = plugin->server_semi_head; | ||
503 | |||
504 | while (t != NULL) | ||
505 | { | ||
506 | /* FIXME add source address comparison */ | ||
507 | if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) | ||
508 | && (t->tag == tag)) | ||
509 | { | ||
510 | break; | ||
511 | } | ||
512 | t = t->next; | ||
513 | } | ||
514 | |||
515 | if (t == NULL) | ||
516 | goto create; | ||
517 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
518 | "Server: Found existing semi-session for `%s'\n", | ||
519 | GNUNET_i2s (&target)); | ||
520 | |||
521 | if ((direction == _SEND) && (t->server_send != NULL)) | ||
522 | { | ||
523 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
524 | "Server: Duplicate GET session, dismissing new connection from peer `%s'\n", | ||
525 | GNUNET_i2s (&target)); | ||
526 | goto error; | ||
527 | } | ||
528 | else | ||
529 | { | ||
530 | s = t; | ||
531 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
532 | plugin->server_semi_tail, s); | ||
533 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
534 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
535 | "Server: Found matching semi-session, merging session for peer `%s'\n", | ||
536 | GNUNET_i2s (&target)); | ||
537 | |||
538 | plugin->inbound_sessions ++; | ||
539 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
540 | "# HTTP inbound sessions", | ||
541 | plugin->inbound_sessions, | ||
542 | GNUNET_NO); | ||
543 | GNUNET_assert (NULL != s); | ||
544 | goto found; | ||
545 | } | ||
546 | if ((direction == _RECEIVE) && (t->server_recv != NULL)) | ||
547 | { | ||
548 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
549 | "Server: Duplicate PUT session, dismissing new connection from peer `%s'\n", | ||
550 | GNUNET_i2s (&target)); | ||
551 | goto error; | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | s = t; | ||
556 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
557 | plugin->server_semi_tail, s); | ||
558 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
559 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
560 | "Server: Found matching semi-session, merging session for peer `%s'\n", | ||
561 | GNUNET_i2s (&target)); | ||
562 | plugin->inbound_sessions ++; | ||
563 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
564 | "# HTTP inbound sessions", | ||
565 | plugin->inbound_sessions, | ||
566 | GNUNET_NO); | ||
567 | GNUNET_assert (NULL != s); | ||
568 | goto found; | ||
569 | } | ||
570 | |||
571 | create: | ||
572 | /* create new session */ | ||
573 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
574 | "Server: Creating new session for peer `%s' \n", | ||
575 | GNUNET_i2s (&target)); | ||
576 | switch (conn_info->client_addr->sa_family) | ||
577 | { | ||
578 | case (AF_INET): | ||
579 | s4 = ((struct sockaddr_in *) conn_info->client_addr); | ||
580 | a4.u4_port = s4->sin_port; | ||
581 | memcpy (&a4.ipv4_addr, &s4->sin_addr, sizeof (struct in_addr)); | ||
582 | a = &a4; | ||
583 | a_len = sizeof (struct IPv4HttpAddress); | ||
584 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s4, sizeof (struct sockaddr_in)); | ||
585 | break; | ||
586 | case (AF_INET6): | ||
587 | s6 = ((struct sockaddr_in6 *) conn_info->client_addr); | ||
588 | a6.u6_port = s6->sin6_port; | ||
589 | memcpy (&a6.ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); | ||
590 | a = &a6; | ||
591 | a_len = sizeof (struct IPv6HttpAddress); | ||
592 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s6, sizeof (struct sockaddr_in6)); | ||
593 | break; | ||
594 | default: | ||
595 | GNUNET_break (0); | ||
596 | goto error; | ||
597 | } | ||
598 | s = create_session (plugin, &target, a, a_len); | ||
599 | GNUNET_assert (NULL != s); | ||
600 | s->ats_address_network_type = ats.value; | ||
601 | s->inbound = GNUNET_YES; | ||
602 | s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; | ||
603 | s->tag = tag; | ||
604 | s->server_recv = NULL; | ||
605 | s->server_send = NULL; | ||
606 | |||
607 | GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head, | ||
608 | plugin->server_semi_tail, s); | ||
609 | goto found; | ||
610 | |||
611 | error: | ||
612 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
613 | "Server: Invalid connection request\n"); | ||
614 | return NULL; | ||
615 | |||
616 | found: | ||
617 | sc = GNUNET_malloc (sizeof (struct ServerConnection)); | ||
618 | sc->mhd_conn = mhd_connection; | ||
619 | sc->direction = direction; | ||
620 | sc->session = s; | ||
621 | if (direction == _SEND) | ||
622 | s->server_send = sc; | ||
623 | if (direction == _RECEIVE) | ||
624 | s->server_recv = sc; | ||
625 | |||
626 | #if MHD_VERSION >= 0x00090E00 | ||
627 | int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); | ||
628 | |||
629 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
630 | "Server: Setting timeout for %p to %u sec.\n", sc, to); | ||
631 | MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to); | ||
632 | |||
633 | struct MHD_Daemon *d = NULL; | ||
634 | |||
635 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
636 | d = plugin->server_v6; | ||
637 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
638 | d = plugin->server_v4; | ||
639 | |||
640 | server_reschedule (plugin, d, GNUNET_NO); | ||
641 | #endif | ||
642 | return sc; | ||
643 | } | ||
644 | |||
645 | /** | ||
646 | * Process GET or PUT request received via MHD. For | ||
647 | * GET, queue response that will send back our pending | ||
648 | * messages. For PUT, process incoming data and send | ||
649 | * to GNUnet core. In either case, check if a session | ||
650 | * already exists and create a new one if not. | ||
651 | */ | ||
652 | static int | ||
653 | server_access_cb (void *cls, struct MHD_Connection *mhd_connection, | ||
654 | const char *url, const char *method, const char *version, | ||
655 | const char *upload_data, size_t * upload_data_size, | ||
656 | void **httpSessionCache) | ||
657 | { | ||
658 | struct Plugin *plugin = cls; | ||
659 | struct ServerConnection *sc = *httpSessionCache; | ||
660 | struct Session *s; | ||
661 | struct MHD_Response *response; | ||
662 | int res = MHD_YES; | ||
663 | |||
664 | GNUNET_assert (cls != NULL); | ||
665 | if (sc == NULL) | ||
666 | { | ||
667 | /* new connection */ | ||
668 | sc = server_lookup_serverconnection (plugin, mhd_connection, url, method); | ||
669 | if (sc != NULL) | ||
670 | (*httpSessionCache) = sc; | ||
671 | else | ||
672 | { | ||
673 | response = | ||
674 | MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), | ||
675 | HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); | ||
676 | res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response); | ||
677 | MHD_destroy_response (response); | ||
678 | return res; | ||
679 | } | ||
680 | } | ||
681 | else | ||
682 | { | ||
683 | /* 'old' connection */ | ||
684 | if (NULL == server_lookup_session (plugin, sc)) | ||
685 | { | ||
686 | /* Session was already disconnected */ | ||
687 | return MHD_NO; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | /* existing connection */ | ||
692 | sc = (*httpSessionCache); | ||
693 | s = sc->session; | ||
694 | |||
695 | GNUNET_assert (NULL != s); | ||
696 | |||
697 | /* connection is to be disconnected */ | ||
698 | if (sc->disconnect == GNUNET_YES) | ||
699 | { | ||
700 | /* Sent HTTP/1.1: 200 OK as PUT Response\ */ | ||
701 | response = | ||
702 | MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!", | ||
703 | MHD_NO, MHD_NO); | ||
704 | res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
705 | MHD_destroy_response (response); | ||
706 | return MHD_YES; | ||
707 | } | ||
708 | |||
709 | GNUNET_assert (s != NULL); | ||
710 | /* Check if both directions are connected */ | ||
711 | if ((sc->session->server_recv == NULL) || (sc->session->server_send == NULL)) | ||
712 | { | ||
713 | /* Delayed read from since not both semi-connections are connected */ | ||
714 | return MHD_YES; | ||
715 | } | ||
716 | |||
717 | if (sc->direction == _SEND) | ||
718 | { | ||
719 | response = | ||
720 | MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
721 | 32 * 1024, | ||
722 | &server_send_callback, s, | ||
723 | NULL); | ||
724 | MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
725 | MHD_destroy_response (response); | ||
726 | return MHD_YES; | ||
727 | } | ||
728 | if (sc->direction == _RECEIVE) | ||
729 | { | ||
730 | if (*upload_data_size == 0) | ||
731 | { | ||
732 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
733 | "Server: Peer `%s' PUT on address `%s' connected\n", | ||
734 | GNUNET_i2s (&s->target), | ||
735 | http_plugin_address_to_string (NULL, s->addr, | ||
736 | s->addrlen)); | ||
737 | return MHD_YES; | ||
738 | } | ||
739 | |||
740 | /* Receiving data */ | ||
741 | if ((*upload_data_size > 0)) | ||
742 | { | ||
743 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
744 | "Server: peer `%s' PUT on address `%s' received %u bytes\n", | ||
745 | GNUNET_i2s (&s->target), | ||
746 | http_plugin_address_to_string (NULL, s->addr, | ||
747 | s->addrlen), | ||
748 | *upload_data_size); | ||
749 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
750 | |||
751 | if ((s->next_receive.abs_value <= now.abs_value)) | ||
752 | { | ||
753 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
754 | "Server: %p: PUT with %u bytes forwarded to MST\n", s, | ||
755 | *upload_data_size); | ||
756 | if (s->msg_tk == NULL) | ||
757 | { | ||
758 | s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); | ||
759 | } | ||
760 | GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, | ||
761 | *upload_data_size, GNUNET_NO, GNUNET_NO); | ||
762 | |||
763 | #if MHD_VERSION >= 0x00090E00 | ||
764 | int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); | ||
765 | struct ServerConnection *t = NULL; | ||
766 | |||
767 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
768 | "Server: Received %u bytes\n", *upload_data_size); | ||
769 | /* Setting timeouts for other connections */ | ||
770 | if (s->server_recv != NULL) | ||
771 | { | ||
772 | t = s->server_recv; | ||
773 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
774 | "Server: Setting timeout for %p to %u sec.\n", t, | ||
775 | to); | ||
776 | MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
777 | to); | ||
778 | } | ||
779 | if (s->server_send != NULL) | ||
780 | { | ||
781 | t = s->server_send; | ||
782 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
783 | "Server: Setting timeout for %p to %u sec.\n", t, | ||
784 | to); | ||
785 | MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
786 | to); | ||
787 | } | ||
788 | struct MHD_Daemon *d = NULL; | ||
789 | |||
790 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
791 | d = plugin->server_v6; | ||
792 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
793 | d = plugin->server_v4; | ||
794 | server_reschedule (plugin, d, GNUNET_NO); | ||
795 | #endif | ||
796 | (*upload_data_size) = 0; | ||
797 | } | ||
798 | else | ||
799 | { | ||
800 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
801 | "Server: %p no inbound bandwidth available! Next read was delayed by %llu ms\n", | ||
802 | s, now.abs_value - s->next_receive.abs_value); | ||
803 | } | ||
804 | return MHD_YES; | ||
805 | } | ||
806 | else | ||
807 | return MHD_NO; | ||
808 | } | ||
809 | return res; | ||
810 | } | ||
811 | |||
812 | static void | ||
813 | server_disconnect_cb (void *cls, struct MHD_Connection *connection, | ||
814 | void **httpSessionCache) | ||
815 | { | ||
816 | struct ServerConnection *sc = *httpSessionCache; | ||
817 | struct ServerConnection *tc = NULL; | ||
818 | struct Session *s = NULL; | ||
819 | struct Session *t = NULL; | ||
820 | struct Plugin *plugin = NULL; | ||
821 | |||
822 | if (sc == NULL) | ||
823 | return; | ||
824 | |||
825 | if (NULL == (s = server_lookup_session (p, sc))) | ||
826 | return; | ||
827 | |||
828 | GNUNET_assert (NULL != p); | ||
829 | if (GNUNET_NO == exist_session(p, s)) | ||
830 | return; | ||
831 | |||
832 | plugin = s->plugin; | ||
833 | if (sc->direction == _SEND) | ||
834 | { | ||
835 | |||
836 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
837 | "Server: %p peer `%s' GET on address `%s' disconnected\n", | ||
838 | s->server_send, GNUNET_i2s (&s->target), | ||
839 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
840 | s->server_send = NULL; | ||
841 | if (NULL != (tc = s->server_recv)) | ||
842 | { | ||
843 | tc->disconnect = GNUNET_YES; | ||
844 | GNUNET_assert (NULL != tc->mhd_conn); | ||
845 | #if MHD_VERSION >= 0x00090E00 | ||
846 | MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
847 | 1); | ||
848 | #endif | ||
849 | } | ||
850 | } | ||
851 | if (sc->direction == _RECEIVE) | ||
852 | { | ||
853 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
854 | "Server: %p peer `%s' PUT on address `%s' disconnected\n", | ||
855 | s->server_recv, GNUNET_i2s (&s->target), | ||
856 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
857 | s->server_recv = NULL; | ||
858 | if (NULL != (tc = s->server_send)) | ||
859 | { | ||
860 | tc->disconnect = GNUNET_YES; | ||
861 | GNUNET_assert (NULL != tc->mhd_conn); | ||
862 | #if MHD_VERSION >= 0x00090E00 | ||
863 | MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
864 | 1); | ||
865 | #endif | ||
866 | } | ||
867 | if (s->msg_tk != NULL) | ||
868 | { | ||
869 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
870 | s->msg_tk = NULL; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | GNUNET_free (sc); | ||
875 | |||
876 | t = plugin->server_semi_head; | ||
877 | while (t != NULL) | ||
878 | { | ||
879 | if (t == s) | ||
880 | { | ||
881 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
882 | plugin->server_semi_tail, s); | ||
883 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
884 | break; | ||
885 | } | ||
886 | t = t->next; | ||
887 | } | ||
888 | plugin->cur_connections--; | ||
889 | |||
890 | struct MHD_Daemon *d = NULL; | ||
891 | |||
892 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
893 | d = plugin->server_v6; | ||
894 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
895 | d = plugin->server_v4; | ||
896 | server_reschedule (plugin, d, GNUNET_NO); | ||
897 | |||
898 | if ((s->server_send == NULL) && (s->server_recv == NULL)) | ||
899 | { | ||
900 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
901 | "Server: peer `%s' on address `%s' disconnected\n", | ||
902 | GNUNET_i2s (&s->target), | ||
903 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
904 | if (s->msg_tk != NULL) | ||
905 | { | ||
906 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
907 | s->msg_tk = NULL; | ||
908 | } | ||
909 | |||
910 | GNUNET_assert (plugin->inbound_sessions > 0); | ||
911 | plugin->inbound_sessions --; | ||
912 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
913 | "# HTTP inbound sessions", | ||
914 | plugin->inbound_sessions, GNUNET_NO); | ||
915 | |||
916 | notify_session_end (s->plugin, &s->target, s); | ||
917 | } | ||
918 | } | ||
919 | |||
920 | int | ||
921 | server_disconnect (struct Session *s) | ||
922 | { | ||
923 | struct ServerConnection * send; | ||
924 | struct ServerConnection * recv; | ||
925 | |||
926 | send = (struct ServerConnection *) s->server_send; | ||
927 | if (s->server_send != NULL) | ||
928 | { | ||
929 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
930 | "Server: %p / %p Terminating inbound PUT session to peer `%s'\n", | ||
931 | s, s->server_send, GNUNET_i2s (&s->target)); | ||
932 | |||
933 | send->disconnect = GNUNET_YES; | ||
934 | #if MHD_VERSION >= 0x00090E00 | ||
935 | MHD_set_connection_option (send->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
936 | 1); | ||
937 | #endif | ||
938 | } | ||
939 | |||
940 | recv = (struct ServerConnection *) s->server_recv; | ||
941 | if (recv != NULL) | ||
942 | { | ||
943 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
944 | "Server: %p / %p Terminating inbound GET session to peer `%s'\n", | ||
945 | s, s->server_recv, GNUNET_i2s (&s->target)); | ||
946 | |||
947 | recv->disconnect = GNUNET_YES; | ||
948 | #if MHD_VERSION >= 0x00090E00 | ||
949 | MHD_set_connection_option (recv->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
950 | 1); | ||
951 | #endif | ||
952 | } | ||
953 | |||
954 | /* Schedule connection immediately */ | ||
955 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
956 | { | ||
957 | server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); | ||
958 | } | ||
959 | else if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
960 | { | ||
961 | server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); | ||
962 | } | ||
963 | return GNUNET_OK; | ||
964 | } | ||
965 | |||
966 | int | ||
967 | server_send (struct Session *s, struct HTTP_Message *msg) | ||
968 | { | ||
969 | GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); | ||
970 | |||
971 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
972 | { | ||
973 | server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); | ||
974 | } | ||
975 | else if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
976 | { | ||
977 | server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); | ||
978 | } | ||
979 | else | ||
980 | return GNUNET_SYSERR; | ||
981 | return GNUNET_OK; | ||
982 | } | ||
983 | |||
984 | |||
985 | |||
986 | /** | ||
987 | * Call MHD IPv4 to process pending requests and then go back | ||
988 | * and schedule the next run. | ||
989 | * @param cls plugin as closure | ||
990 | * @param tc task context | ||
991 | */ | ||
992 | static void | ||
993 | server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
994 | { | ||
995 | struct Plugin *plugin = cls; | ||
996 | |||
997 | GNUNET_assert (cls != NULL); | ||
998 | |||
999 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1000 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1001 | return; | ||
1002 | #if 0 | ||
1003 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1004 | "Running IPv4 server\n"); | ||
1005 | #endif | ||
1006 | plugin->server_v4_immediately = GNUNET_NO; | ||
1007 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); | ||
1008 | server_reschedule (plugin, plugin->server_v4, GNUNET_NO); | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | /** | ||
1013 | * Call MHD IPv6 to process pending requests and then go back | ||
1014 | * and schedule the next run. | ||
1015 | * @param cls plugin as closure | ||
1016 | * @param tc task context | ||
1017 | */ | ||
1018 | static void | ||
1019 | server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1020 | { | ||
1021 | struct Plugin *plugin = cls; | ||
1022 | |||
1023 | GNUNET_assert (cls != NULL); | ||
1024 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1025 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1026 | return; | ||
1027 | #if 0 | ||
1028 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1029 | "Running IPv6 server\n"); | ||
1030 | #endif | ||
1031 | plugin->server_v6_immediately = GNUNET_NO; | ||
1032 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); | ||
1033 | server_reschedule (plugin, plugin->server_v6, GNUNET_NO); | ||
1034 | } | ||
1035 | |||
1036 | /** | ||
1037 | * Function that queries MHD's select sets and | ||
1038 | * starts the task waiting for them. | ||
1039 | * @param plugin plugin | ||
1040 | * @param daemon_handle the MHD daemon handle | ||
1041 | * @return gnunet task identifier | ||
1042 | */ | ||
1043 | static GNUNET_SCHEDULER_TaskIdentifier | ||
1044 | server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, | ||
1045 | int now) | ||
1046 | { | ||
1047 | GNUNET_SCHEDULER_TaskIdentifier ret; | ||
1048 | fd_set rs; | ||
1049 | fd_set ws; | ||
1050 | fd_set es; | ||
1051 | struct GNUNET_NETWORK_FDSet *wrs; | ||
1052 | struct GNUNET_NETWORK_FDSet *wws; | ||
1053 | struct GNUNET_NETWORK_FDSet *wes; | ||
1054 | int max; | ||
1055 | unsigned MHD_LONG_LONG timeout; | ||
1056 | static unsigned long long last_timeout = 0; | ||
1057 | int haveto; | ||
1058 | |||
1059 | struct GNUNET_TIME_Relative tv; | ||
1060 | |||
1061 | ret = GNUNET_SCHEDULER_NO_TASK; | ||
1062 | FD_ZERO (&rs); | ||
1063 | FD_ZERO (&ws); | ||
1064 | FD_ZERO (&es); | ||
1065 | wrs = GNUNET_NETWORK_fdset_create (); | ||
1066 | wes = GNUNET_NETWORK_fdset_create (); | ||
1067 | wws = GNUNET_NETWORK_fdset_create (); | ||
1068 | max = -1; | ||
1069 | GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); | ||
1070 | haveto = MHD_get_timeout (daemon_handle, &timeout); | ||
1071 | if (haveto == MHD_YES) | ||
1072 | { | ||
1073 | if (timeout != last_timeout) | ||
1074 | { | ||
1075 | #if VERBOSE_SERVER | ||
1076 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1077 | "SELECT Timeout changed from %llu to %llu\n", | ||
1078 | last_timeout, timeout); | ||
1079 | #endif | ||
1080 | last_timeout = timeout; | ||
1081 | } | ||
1082 | tv.rel_value = (uint64_t) timeout; | ||
1083 | } | ||
1084 | else | ||
1085 | tv = GNUNET_TIME_UNIT_SECONDS; | ||
1086 | /* Force immediate run, since we have outbound data to send */ | ||
1087 | if (now == GNUNET_YES) | ||
1088 | tv = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1089 | GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); | ||
1090 | GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); | ||
1091 | GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); | ||
1092 | |||
1093 | if (daemon_handle == plugin->server_v4) | ||
1094 | { | ||
1095 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
1096 | { | ||
1097 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1098 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1099 | } | ||
1100 | #if 0 | ||
1101 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1102 | "Scheduling IPv4 server task in %llu ms\n", tv); | ||
1103 | #endif | ||
1104 | ret = | ||
1105 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1106 | tv, wrs, wws, | ||
1107 | &server_v4_run, plugin); | ||
1108 | } | ||
1109 | if (daemon_handle == plugin->server_v6) | ||
1110 | { | ||
1111 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
1112 | { | ||
1113 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1114 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1115 | } | ||
1116 | #if 0 | ||
1117 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1118 | "Scheduling IPv6 server task in %llu ms\n", tv); | ||
1119 | #endif | ||
1120 | ret = | ||
1121 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1122 | tv, wrs, wws, | ||
1123 | &server_v6_run, plugin); | ||
1124 | } | ||
1125 | GNUNET_NETWORK_fdset_destroy (wrs); | ||
1126 | GNUNET_NETWORK_fdset_destroy (wws); | ||
1127 | GNUNET_NETWORK_fdset_destroy (wes); | ||
1128 | return ret; | ||
1129 | } | ||
1130 | |||
1131 | int | ||
1132 | server_start (struct Plugin *plugin) | ||
1133 | { | ||
1134 | int res = GNUNET_OK; | ||
1135 | unsigned int timeout; | ||
1136 | p = plugin; | ||
1137 | GNUNET_assert (NULL != plugin); | ||
1138 | |||
1139 | #if BUILD_HTTPS | ||
1140 | res = server_load_certificate (plugin); | ||
1141 | if (res == GNUNET_SYSERR) | ||
1142 | { | ||
1143 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1144 | "Could not load or create server certificate! Loading plugin failed!\n"); | ||
1145 | return res; | ||
1146 | } | ||
1147 | #endif | ||
1148 | |||
1149 | |||
1150 | #if MHD_VERSION >= 0x00090E00 | ||
1151 | timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000; | ||
1152 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1153 | "MHD can set timeout per connection! Default time out %u sec.\n", | ||
1154 | timeout); | ||
1155 | #else | ||
1156 | timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000; | ||
1157 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, | ||
1158 | "MHD cannot set timeout per connection! Default time out %u sec.\n", | ||
1159 | timeout); | ||
1160 | #endif | ||
1161 | plugin->server_v4 = NULL; | ||
1162 | if (plugin->ipv4 == GNUNET_YES) | ||
1163 | { | ||
1164 | plugin->server_v4 = MHD_start_daemon ( | ||
1165 | #if VERBOSE_SERVER | ||
1166 | MHD_USE_DEBUG | | ||
1167 | #endif | ||
1168 | #if BUILD_HTTPS | ||
1169 | MHD_USE_SSL | | ||
1170 | #endif | ||
1171 | MHD_NO_FLAG, plugin->port, | ||
1172 | &server_accept_cb, plugin, | ||
1173 | &server_access_cb, plugin, | ||
1174 | MHD_OPTION_SOCK_ADDR, | ||
1175 | (struct sockaddr_in *) | ||
1176 | plugin->server_addr_v4, | ||
1177 | MHD_OPTION_CONNECTION_LIMIT, | ||
1178 | (unsigned int) | ||
1179 | plugin->max_connections, | ||
1180 | #if BUILD_HTTPS | ||
1181 | MHD_OPTION_HTTPS_PRIORITIES, | ||
1182 | plugin->crypto_init, | ||
1183 | MHD_OPTION_HTTPS_MEM_KEY, | ||
1184 | plugin->key, | ||
1185 | MHD_OPTION_HTTPS_MEM_CERT, | ||
1186 | plugin->cert, | ||
1187 | #endif | ||
1188 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
1189 | timeout, | ||
1190 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
1191 | (size_t) (2 * | ||
1192 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
1193 | MHD_OPTION_NOTIFY_COMPLETED, | ||
1194 | &server_disconnect_cb, plugin, | ||
1195 | MHD_OPTION_EXTERNAL_LOGGER, | ||
1196 | server_log, NULL, MHD_OPTION_END); | ||
1197 | } | ||
1198 | plugin->server_v6 = NULL; | ||
1199 | if (plugin->ipv6 == GNUNET_YES) | ||
1200 | { | ||
1201 | plugin->server_v6 = MHD_start_daemon ( | ||
1202 | #if VERBOSE_SERVER | ||
1203 | MHD_USE_DEBUG | | ||
1204 | #endif | ||
1205 | #if BUILD_HTTPS | ||
1206 | MHD_USE_SSL | | ||
1207 | #endif | ||
1208 | MHD_USE_IPv6, plugin->port, | ||
1209 | &server_accept_cb, plugin, | ||
1210 | &server_access_cb, plugin, | ||
1211 | MHD_OPTION_SOCK_ADDR, | ||
1212 | (struct sockaddr_in6 *) | ||
1213 | plugin->server_addr_v6, | ||
1214 | MHD_OPTION_CONNECTION_LIMIT, | ||
1215 | (unsigned int) | ||
1216 | plugin->max_connections, | ||
1217 | #if BUILD_HTTPS | ||
1218 | MHD_OPTION_HTTPS_PRIORITIES, | ||
1219 | plugin->crypto_init, | ||
1220 | MHD_OPTION_HTTPS_MEM_KEY, | ||
1221 | plugin->key, | ||
1222 | MHD_OPTION_HTTPS_MEM_CERT, | ||
1223 | plugin->cert, | ||
1224 | #endif | ||
1225 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
1226 | timeout, | ||
1227 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
1228 | (size_t) (2 * | ||
1229 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
1230 | MHD_OPTION_NOTIFY_COMPLETED, | ||
1231 | &server_disconnect_cb, plugin, | ||
1232 | MHD_OPTION_EXTERNAL_LOGGER, | ||
1233 | server_log, NULL, MHD_OPTION_END); | ||
1234 | |||
1235 | } | ||
1236 | |||
1237 | if ((plugin->ipv4 == GNUNET_YES) && (plugin->server_v4 == NULL)) | ||
1238 | { | ||
1239 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1240 | "Failed to start %s IPv4 server component on port %u\n", | ||
1241 | plugin->name, plugin->port); | ||
1242 | return GNUNET_SYSERR; | ||
1243 | } | ||
1244 | server_reschedule (plugin, plugin->server_v4, GNUNET_NO); | ||
1245 | |||
1246 | if ((plugin->ipv6 == GNUNET_YES) && (plugin->server_v6 == NULL)) | ||
1247 | { | ||
1248 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1249 | "Failed to start %s IPv6 server component on port %u\n", | ||
1250 | plugin->name, plugin->port); | ||
1251 | return GNUNET_SYSERR; | ||
1252 | } | ||
1253 | server_reschedule (plugin, plugin->server_v6, GNUNET_NO); | ||
1254 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1255 | "%s server component started on port %u\n", plugin->name, | ||
1256 | plugin->port); | ||
1257 | return res; | ||
1258 | } | ||
1259 | |||
1260 | void | ||
1261 | server_stop (struct Plugin *plugin) | ||
1262 | { | ||
1263 | struct Session *s = NULL; | ||
1264 | struct Session *t = NULL; | ||
1265 | |||
1266 | struct MHD_Daemon *server_v4_tmp = plugin->server_v4; | ||
1267 | plugin->server_v4 = NULL; | ||
1268 | |||
1269 | struct MHD_Daemon *server_v6_tmp = plugin->server_v6; | ||
1270 | plugin->server_v6 = NULL; | ||
1271 | |||
1272 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
1273 | { | ||
1274 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1275 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1276 | } | ||
1277 | |||
1278 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
1279 | { | ||
1280 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1281 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1282 | } | ||
1283 | |||
1284 | if (server_v6_tmp != NULL) | ||
1285 | { | ||
1286 | MHD_stop_daemon (server_v4_tmp); | ||
1287 | } | ||
1288 | if (server_v6_tmp != NULL) | ||
1289 | { | ||
1290 | MHD_stop_daemon (server_v6_tmp); | ||
1291 | } | ||
1292 | |||
1293 | /* cleaning up semi-sessions never propagated */ | ||
1294 | s = plugin->server_semi_head; | ||
1295 | while (s != NULL) | ||
1296 | { | ||
1297 | #if VERBOSE_SERVER | ||
1298 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1299 | "Deleting semi-sessions %p\n", s); | ||
1300 | #endif | ||
1301 | t = s->next; | ||
1302 | struct HTTP_Message *msg = s->msg_head; | ||
1303 | struct HTTP_Message *tmp = NULL; | ||
1304 | |||
1305 | while (msg != NULL) | ||
1306 | { | ||
1307 | tmp = msg->next; | ||
1308 | |||
1309 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
1310 | if (msg->transmit_cont != NULL) | ||
1311 | { | ||
1312 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
1313 | } | ||
1314 | GNUNET_free (msg); | ||
1315 | msg = tmp; | ||
1316 | } | ||
1317 | |||
1318 | delete_session (s); | ||
1319 | s = t; | ||
1320 | } | ||
1321 | |||
1322 | p = NULL; | ||
1323 | |||
1324 | #if BUILD_HTTPS | ||
1325 | GNUNET_free_non_null (plugin->crypto_init); | ||
1326 | GNUNET_free_non_null (plugin->cert); | ||
1327 | GNUNET_free_non_null (plugin->key); | ||
1328 | #endif | ||
1329 | |||
1330 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1331 | "%s server component stopped\n", plugin->name); | ||
1332 | } | ||
1333 | |||
1334 | |||
1335 | |||
1336 | /* end of plugin_transport_http.c */ | ||