diff options
Diffstat (limited to 'src/transport/plugin_transport_http_server.c')
-rw-r--r-- | src/transport/plugin_transport_http_server.c | 3603 |
1 files changed, 0 insertions, 3603 deletions
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c deleted file mode 100644 index 78b030e9a..000000000 --- a/src/transport/plugin_transport_http_server.c +++ /dev/null | |||
@@ -1,3603 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2002-2014, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/plugin_transport_http_server.c | ||
23 | * @brief HTTP/S server transport plugin | ||
24 | * @author Matthias Wachs | ||
25 | * @author David Barksdale | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "gnunet_transport_plugin.h" | ||
32 | #include "gnunet_nat_service.h" | ||
33 | #include "plugin_transport_http_common.h" | ||
34 | #include <microhttpd.h> | ||
35 | #include <regex.h> | ||
36 | #include "gnunet_mhd_compat.h" | ||
37 | |||
38 | #if BUILD_HTTPS | ||
39 | #define PLUGIN_NAME "https_server" | ||
40 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT \ | ||
41 | libgnunet_plugin_transport_https_server_init | ||
42 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE \ | ||
43 | libgnunet_plugin_transport_https_server_done | ||
44 | #else | ||
45 | #define PLUGIN_NAME "http_server" | ||
46 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT \ | ||
47 | libgnunet_plugin_transport_http_server_init | ||
48 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE \ | ||
49 | libgnunet_plugin_transport_http_server_done | ||
50 | #endif | ||
51 | |||
52 | #define HTTP_ERROR_RESPONSE \ | ||
53 | "<!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>" | ||
54 | #define _RECEIVE 0 | ||
55 | #define _SEND 1 | ||
56 | |||
57 | |||
58 | #define LOG(kind, ...) GNUNET_log_from (kind, "transport-" PLUGIN_NAME, \ | ||
59 | __VA_ARGS__) | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Information we keep with MHD for an HTTP request. | ||
64 | */ | ||
65 | struct ServerRequest | ||
66 | { | ||
67 | /** | ||
68 | * The session this server request belongs to | ||
69 | * Can be NULL, when session was disconnected and freed | ||
70 | */ | ||
71 | struct GNUNET_ATS_Session *session; | ||
72 | |||
73 | /** | ||
74 | * The MHD connection | ||
75 | */ | ||
76 | struct MHD_Connection *mhd_conn; | ||
77 | |||
78 | /** | ||
79 | * The MHD daemon | ||
80 | */ | ||
81 | struct MHD_Daemon *mhd_daemon; | ||
82 | |||
83 | /** | ||
84 | * Options requested by peer | ||
85 | */ | ||
86 | uint32_t options; | ||
87 | #define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */ | ||
88 | |||
89 | /** | ||
90 | * _RECV or _SEND | ||
91 | */ | ||
92 | int direction; | ||
93 | |||
94 | /** | ||
95 | * For PUT requests: Is this the first or last callback with size 0 | ||
96 | * For GET requests: Have we sent a message | ||
97 | */ | ||
98 | int connected; | ||
99 | |||
100 | /** | ||
101 | * Currently suspended | ||
102 | */ | ||
103 | bool suspended; | ||
104 | }; | ||
105 | |||
106 | |||
107 | /** | ||
108 | * Wrapper to manage addresses | ||
109 | */ | ||
110 | struct HttpAddressWrapper | ||
111 | { | ||
112 | /** | ||
113 | * Linked list next | ||
114 | */ | ||
115 | struct HttpAddressWrapper *next; | ||
116 | |||
117 | /** | ||
118 | * Linked list previous | ||
119 | */ | ||
120 | struct HttpAddressWrapper *prev; | ||
121 | |||
122 | /** | ||
123 | * An address we are using. | ||
124 | */ | ||
125 | struct HttpAddress *address; | ||
126 | |||
127 | /** | ||
128 | * Length of the address. | ||
129 | */ | ||
130 | size_t addrlen; | ||
131 | }; | ||
132 | |||
133 | |||
134 | /** | ||
135 | * Message to send using http | ||
136 | */ | ||
137 | struct HTTP_Message | ||
138 | { | ||
139 | /** | ||
140 | * next pointer for double linked list | ||
141 | */ | ||
142 | struct HTTP_Message *next; | ||
143 | |||
144 | /** | ||
145 | * previous pointer for double linked list | ||
146 | */ | ||
147 | struct HTTP_Message *prev; | ||
148 | |||
149 | /** | ||
150 | * buffer containing data to send | ||
151 | */ | ||
152 | char *buf; | ||
153 | |||
154 | /** | ||
155 | * amount of data already sent | ||
156 | */ | ||
157 | size_t pos; | ||
158 | |||
159 | /** | ||
160 | * buffer length | ||
161 | */ | ||
162 | size_t size; | ||
163 | |||
164 | /** | ||
165 | * HTTP/S specific overhead | ||
166 | */ | ||
167 | size_t overhead; | ||
168 | |||
169 | /** | ||
170 | * Continuation function to call once the transmission buffer | ||
171 | * has again space available. NULL if there is no | ||
172 | * continuation to call. | ||
173 | */ | ||
174 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; | ||
175 | |||
176 | /** | ||
177 | * Closure for transmit_cont. | ||
178 | */ | ||
179 | void *transmit_cont_cls; | ||
180 | }; | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Session handle for connections. | ||
185 | */ | ||
186 | struct GNUNET_ATS_Session | ||
187 | { | ||
188 | /** | ||
189 | * To whom are we talking to (set to our identity | ||
190 | * if we are still waiting for the welcome message) | ||
191 | */ | ||
192 | struct GNUNET_PeerIdentity target; | ||
193 | |||
194 | /** | ||
195 | * Pointer to the global plugin struct. | ||
196 | */ | ||
197 | struct HTTP_Server_Plugin *plugin; | ||
198 | |||
199 | /** | ||
200 | * next pointer for double linked list | ||
201 | */ | ||
202 | struct HTTP_Message *msg_head; | ||
203 | |||
204 | /** | ||
205 | * previous pointer for double linked list | ||
206 | */ | ||
207 | struct HTTP_Message *msg_tail; | ||
208 | |||
209 | /** | ||
210 | * Message stream tokenizer for incoming data | ||
211 | */ | ||
212 | struct GNUNET_MessageStreamTokenizer *msg_tk; | ||
213 | |||
214 | /** | ||
215 | * Client recv handle | ||
216 | */ | ||
217 | struct ServerRequest *server_recv; | ||
218 | |||
219 | /** | ||
220 | * Client send handle | ||
221 | */ | ||
222 | struct ServerRequest *server_send; | ||
223 | |||
224 | /** | ||
225 | * Address | ||
226 | */ | ||
227 | struct GNUNET_HELLO_Address *address; | ||
228 | |||
229 | /** | ||
230 | * Absolute time when to receive data again | ||
231 | * Used for receive throttling | ||
232 | */ | ||
233 | struct GNUNET_TIME_Absolute next_receive; | ||
234 | |||
235 | /** | ||
236 | * Absolute time when this connection will time out. | ||
237 | */ | ||
238 | struct GNUNET_TIME_Absolute timeout; | ||
239 | |||
240 | /** | ||
241 | * Session timeout task | ||
242 | */ | ||
243 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
244 | |||
245 | /** | ||
246 | * Task to resume MHD handling when receiving is allowed again | ||
247 | */ | ||
248 | struct GNUNET_SCHEDULER_Task *recv_wakeup_task; | ||
249 | |||
250 | /** | ||
251 | * Number of bytes waiting for transmission to this peer. | ||
252 | */ | ||
253 | unsigned long long bytes_in_queue; | ||
254 | |||
255 | /** | ||
256 | * Number of messages waiting for transmission to this peer. | ||
257 | */ | ||
258 | unsigned int msgs_in_queue; | ||
259 | |||
260 | /** | ||
261 | * Unique HTTP/S connection tag for this connection | ||
262 | */ | ||
263 | uint32_t tag; | ||
264 | |||
265 | /** | ||
266 | * ATS network type. | ||
267 | */ | ||
268 | enum GNUNET_NetworkType scope; | ||
269 | |||
270 | /** | ||
271 | * #GNUNET_YES if this session is known to the service. | ||
272 | */ | ||
273 | int known_to_service; | ||
274 | }; | ||
275 | |||
276 | |||
277 | /** | ||
278 | * Encapsulation of all of the state of the plugin. | ||
279 | */ | ||
280 | struct HTTP_Server_Plugin | ||
281 | { | ||
282 | /** | ||
283 | * Our environment. | ||
284 | */ | ||
285 | struct GNUNET_TRANSPORT_PluginEnvironment *env; | ||
286 | |||
287 | /** | ||
288 | * Hash map of open sessions. | ||
289 | */ | ||
290 | struct GNUNET_CONTAINER_MultiPeerMap *sessions; | ||
291 | |||
292 | /** | ||
293 | * Function to call about session status changes. | ||
294 | */ | ||
295 | GNUNET_TRANSPORT_SessionInfoCallback sic; | ||
296 | |||
297 | /** | ||
298 | * Closure for @e sic. | ||
299 | */ | ||
300 | void *sic_cls; | ||
301 | |||
302 | /** | ||
303 | * Plugin name | ||
304 | */ | ||
305 | char *name; | ||
306 | |||
307 | /** | ||
308 | * Protocol | ||
309 | */ | ||
310 | char *protocol; | ||
311 | |||
312 | /** | ||
313 | * External address | ||
314 | */ | ||
315 | char *external_hostname; | ||
316 | |||
317 | /** | ||
318 | * External hostname the plugin can be connected to, can be different to | ||
319 | * the host's FQDN, used e.g. for reverse proxying | ||
320 | */ | ||
321 | struct GNUNET_HELLO_Address *ext_addr; | ||
322 | |||
323 | /** | ||
324 | * NAT handle & address management | ||
325 | */ | ||
326 | struct GNUNET_NAT_Handle *nat; | ||
327 | |||
328 | /** | ||
329 | * IPv4 addresses DLL head | ||
330 | */ | ||
331 | struct HttpAddressWrapper *addr_head; | ||
332 | |||
333 | /** | ||
334 | * IPv4 addresses DLL tail | ||
335 | */ | ||
336 | struct HttpAddressWrapper *addr_tail; | ||
337 | |||
338 | /** | ||
339 | * IPv4 server socket to bind to | ||
340 | */ | ||
341 | struct sockaddr_in *server_addr_v4; | ||
342 | |||
343 | /** | ||
344 | * IPv6 server socket to bind to | ||
345 | */ | ||
346 | struct sockaddr_in6 *server_addr_v6; | ||
347 | |||
348 | /** | ||
349 | * MHD IPv4 daemon | ||
350 | */ | ||
351 | struct MHD_Daemon *server_v4; | ||
352 | |||
353 | /** | ||
354 | * MHD IPv4 daemon | ||
355 | */ | ||
356 | struct MHD_Daemon *server_v6; | ||
357 | |||
358 | #if BUILD_HTTPS | ||
359 | /** | ||
360 | * Crypto related | ||
361 | * | ||
362 | * Example: | ||
363 | * | ||
364 | * Use RC4-128 instead of AES: | ||
365 | * NONE:+VERS-TLS1.0:+ARCFOUR-128:+SHA1:+RSA:+COMP-NULL | ||
366 | * | ||
367 | */ | ||
368 | char *crypto_init; | ||
369 | |||
370 | /** | ||
371 | * TLS key | ||
372 | */ | ||
373 | char *key; | ||
374 | |||
375 | /** | ||
376 | * TLS certificate | ||
377 | */ | ||
378 | char *cert; | ||
379 | #endif | ||
380 | |||
381 | /** | ||
382 | * MHD IPv4 task | ||
383 | */ | ||
384 | struct GNUNET_SCHEDULER_Task *server_v4_task; | ||
385 | |||
386 | /** | ||
387 | * MHD IPv6 task | ||
388 | */ | ||
389 | struct GNUNET_SCHEDULER_Task *server_v6_task; | ||
390 | |||
391 | /** | ||
392 | * Task calling transport service about external address | ||
393 | */ | ||
394 | struct GNUNET_SCHEDULER_Task *notify_ext_task; | ||
395 | |||
396 | /** | ||
397 | * Notify transport only about external address | ||
398 | */ | ||
399 | unsigned int external_only; | ||
400 | |||
401 | /** | ||
402 | * The IPv4 server is scheduled to run asap | ||
403 | */ | ||
404 | int server_v4_immediately; | ||
405 | |||
406 | /** | ||
407 | * The IPv6 server is scheduled to run asap | ||
408 | */ | ||
409 | int server_v6_immediately; | ||
410 | |||
411 | /** | ||
412 | * Verify external address | ||
413 | */ | ||
414 | int verify_external_hostname; | ||
415 | |||
416 | /** | ||
417 | * Maximum number of sockets the plugin can use | ||
418 | * Each http request /request connections are two connections | ||
419 | */ | ||
420 | unsigned int max_request; | ||
421 | |||
422 | /** | ||
423 | * Current number of sockets the plugin can use | ||
424 | * Each http connection are two requests | ||
425 | */ | ||
426 | unsigned int cur_request; | ||
427 | |||
428 | /** | ||
429 | * Did we immediately end the session in disconnect_cb | ||
430 | */ | ||
431 | int in_shutdown; | ||
432 | |||
433 | /** | ||
434 | * Length of peer id | ||
435 | */ | ||
436 | int peer_id_length; | ||
437 | |||
438 | /** | ||
439 | * My options to be included in the address | ||
440 | */ | ||
441 | uint32_t options; | ||
442 | |||
443 | /** | ||
444 | * use IPv6 | ||
445 | */ | ||
446 | uint16_t use_ipv6; | ||
447 | |||
448 | /** | ||
449 | * use IPv4 | ||
450 | */ | ||
451 | uint16_t use_ipv4; | ||
452 | |||
453 | /** | ||
454 | * Port used | ||
455 | */ | ||
456 | uint16_t port; | ||
457 | |||
458 | /** | ||
459 | * Regex for parsing URLs. FIXME: this seems overkill. | ||
460 | */ | ||
461 | regex_t url_regex; | ||
462 | }; | ||
463 | |||
464 | |||
465 | /** | ||
466 | * If a session monitor is attached, notify it about the new | ||
467 | * session state. | ||
468 | * | ||
469 | * @param plugin our plugin | ||
470 | * @param session session that changed state | ||
471 | * @param state new state of the session | ||
472 | */ | ||
473 | static void | ||
474 | notify_session_monitor (struct HTTP_Server_Plugin *plugin, | ||
475 | struct GNUNET_ATS_Session *session, | ||
476 | enum GNUNET_TRANSPORT_SessionState state) | ||
477 | { | ||
478 | struct GNUNET_TRANSPORT_SessionInfo info; | ||
479 | |||
480 | if (NULL == plugin->sic) | ||
481 | return; | ||
482 | memset (&info, 0, sizeof(info)); | ||
483 | info.state = state; | ||
484 | info.is_inbound = GNUNET_YES; | ||
485 | info.num_msg_pending = session->msgs_in_queue; | ||
486 | info.num_bytes_pending = session->bytes_in_queue; | ||
487 | info.receive_delay = session->next_receive; | ||
488 | info.session_timeout = session->timeout; | ||
489 | info.address = session->address; | ||
490 | plugin->sic (plugin->sic_cls, | ||
491 | session, | ||
492 | &info); | ||
493 | } | ||
494 | |||
495 | |||
496 | /** | ||
497 | * Wake up an MHD connection which was suspended | ||
498 | * | ||
499 | * @param cls the session | ||
500 | */ | ||
501 | static void | ||
502 | server_wake_up (void *cls) | ||
503 | { | ||
504 | struct GNUNET_ATS_Session *s = cls; | ||
505 | |||
506 | s->recv_wakeup_task = NULL; | ||
507 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
508 | "Session %p: Waking up PUT handle\n", | ||
509 | s); | ||
510 | GNUNET_assert (s->server_recv->suspended); | ||
511 | MHD_resume_connection (s->server_recv->mhd_conn); | ||
512 | s->server_recv->suspended = false; | ||
513 | } | ||
514 | |||
515 | |||
516 | /** | ||
517 | * Reschedule the execution of both IPv4 and IPv6 server. | ||
518 | * | ||
519 | * @param plugin the plugin | ||
520 | * @param server which server to schedule v4 or v6? | ||
521 | * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait | ||
522 | * until timeout | ||
523 | */ | ||
524 | static void | ||
525 | server_reschedule (struct HTTP_Server_Plugin *plugin, | ||
526 | struct MHD_Daemon *server, | ||
527 | int now); | ||
528 | |||
529 | |||
530 | /** | ||
531 | * Deletes the session. Must not be used afterwards. | ||
532 | * | ||
533 | * @param s the session to delete | ||
534 | */ | ||
535 | static void | ||
536 | server_delete_session (struct GNUNET_ATS_Session *s) | ||
537 | { | ||
538 | struct HTTP_Server_Plugin *plugin = s->plugin; | ||
539 | struct HTTP_Message *msg; | ||
540 | |||
541 | if (NULL != s->timeout_task) | ||
542 | { | ||
543 | GNUNET_SCHEDULER_cancel (s->timeout_task); | ||
544 | s->timeout_task = NULL; | ||
545 | s->timeout = GNUNET_TIME_UNIT_ZERO_ABS; | ||
546 | } | ||
547 | if (NULL != s->recv_wakeup_task) | ||
548 | { | ||
549 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
550 | s->recv_wakeup_task = NULL; | ||
551 | if (NULL != s->server_recv) | ||
552 | { | ||
553 | GNUNET_assert (s->server_recv->suspended); | ||
554 | s->server_recv->suspended = false; | ||
555 | MHD_resume_connection (s->server_recv->mhd_conn); | ||
556 | } | ||
557 | } | ||
558 | GNUNET_assert (GNUNET_OK == | ||
559 | GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, | ||
560 | &s->target, | ||
561 | s)); | ||
562 | while (NULL != (msg = s->msg_head)) | ||
563 | { | ||
564 | GNUNET_CONTAINER_DLL_remove (s->msg_head, | ||
565 | s->msg_tail, | ||
566 | msg); | ||
567 | if (NULL != msg->transmit_cont) | ||
568 | msg->transmit_cont (msg->transmit_cont_cls, | ||
569 | &s->target, | ||
570 | GNUNET_SYSERR, | ||
571 | msg->size, | ||
572 | msg->pos + msg->overhead); | ||
573 | GNUNET_assert (s->msgs_in_queue > 0); | ||
574 | s->msgs_in_queue--; | ||
575 | GNUNET_assert (s->bytes_in_queue >= msg->size); | ||
576 | s->bytes_in_queue -= msg->size; | ||
577 | GNUNET_free (msg); | ||
578 | } | ||
579 | |||
580 | GNUNET_assert (0 == s->msgs_in_queue); | ||
581 | GNUNET_assert (0 == s->bytes_in_queue); | ||
582 | |||
583 | if (NULL != s->server_send) | ||
584 | { | ||
585 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
586 | "Server: %p / %p Terminating inbound PUT session to peer `%s'\n", | ||
587 | s, s->server_send, | ||
588 | GNUNET_i2s (&s->target)); | ||
589 | s->server_send->session = NULL; | ||
590 | MHD_set_connection_option (s->server_send->mhd_conn, | ||
591 | MHD_CONNECTION_OPTION_TIMEOUT, | ||
592 | 1 /* 0 = no timeout, so this is MIN */); | ||
593 | if (s->server_send->suspended) | ||
594 | { | ||
595 | s->server_send->suspended = false; | ||
596 | MHD_resume_connection (s->server_send->mhd_conn); | ||
597 | } | ||
598 | server_reschedule (plugin, | ||
599 | s->server_send->mhd_daemon, | ||
600 | GNUNET_YES); | ||
601 | } | ||
602 | |||
603 | if (NULL != s->server_recv) | ||
604 | { | ||
605 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
606 | "Server: %p / %p Terminating inbound GET session to peer `%s'\n", | ||
607 | s, s->server_recv, GNUNET_i2s (&s->target)); | ||
608 | s->server_recv->session = NULL; | ||
609 | MHD_set_connection_option (s->server_recv->mhd_conn, | ||
610 | MHD_CONNECTION_OPTION_TIMEOUT, | ||
611 | 1 /* 0 = no timeout, so this is MIN */); | ||
612 | server_reschedule (plugin, | ||
613 | s->server_recv->mhd_daemon, | ||
614 | GNUNET_YES); | ||
615 | } | ||
616 | notify_session_monitor (plugin, | ||
617 | s, | ||
618 | GNUNET_TRANSPORT_SS_DONE); | ||
619 | if (GNUNET_YES == s->known_to_service) | ||
620 | { | ||
621 | plugin->env->session_end (plugin->env->cls, | ||
622 | s->address, | ||
623 | s); | ||
624 | s->known_to_service = GNUNET_NO; | ||
625 | } | ||
626 | if (NULL != s->msg_tk) | ||
627 | { | ||
628 | GNUNET_MST_destroy (s->msg_tk); | ||
629 | s->msg_tk = NULL; | ||
630 | } | ||
631 | GNUNET_HELLO_address_free (s->address); | ||
632 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
633 | "Session %p destroyed\n", | ||
634 | s); | ||
635 | GNUNET_free (s); | ||
636 | } | ||
637 | |||
638 | |||
639 | /** | ||
640 | * Disconnect session @a s by telling MHD to close the | ||
641 | * connections (reducing timeout, etc.). | ||
642 | * | ||
643 | * @param cls closure with the `struct HTTP_Server_Plugin` | ||
644 | * @param s the session | ||
645 | * @return #GNUNET_OK on success | ||
646 | */ | ||
647 | static int | ||
648 | http_server_plugin_disconnect_session (void *cls, | ||
649 | struct GNUNET_ATS_Session *s) | ||
650 | { | ||
651 | server_delete_session (s); | ||
652 | return GNUNET_OK; | ||
653 | } | ||
654 | |||
655 | |||
656 | /** | ||
657 | * Session was idle, so disconnect it | ||
658 | * | ||
659 | * @param cls the session | ||
660 | */ | ||
661 | static void | ||
662 | server_session_timeout (void *cls) | ||
663 | { | ||
664 | struct GNUNET_ATS_Session *s = cls; | ||
665 | struct GNUNET_TIME_Relative left; | ||
666 | |||
667 | s->timeout_task = NULL; | ||
668 | left = GNUNET_TIME_absolute_get_remaining (s->timeout); | ||
669 | if (0 != left.rel_value_us) | ||
670 | { | ||
671 | /* not actually our turn yet, but let's at least update | ||
672 | the monitor, it may think we're about to die ... */ | ||
673 | notify_session_monitor (s->plugin, | ||
674 | s, | ||
675 | GNUNET_TRANSPORT_SS_UP); | ||
676 | s->timeout_task = GNUNET_SCHEDULER_add_delayed (left, | ||
677 | &server_session_timeout, | ||
678 | s); | ||
679 | return; | ||
680 | } | ||
681 | GNUNET_log (TIMEOUT_LOG, | ||
682 | "Session %p was idle for %s, disconnecting\n", | ||
683 | s, | ||
684 | GNUNET_STRINGS_relative_time_to_string ( | ||
685 | HTTP_SERVER_SESSION_TIMEOUT, | ||
686 | GNUNET_YES)); | ||
687 | server_delete_session (s); | ||
688 | } | ||
689 | |||
690 | |||
691 | /** | ||
692 | * Increment session timeout due to activity session @a s | ||
693 | * | ||
694 | * @param s the session | ||
695 | */ | ||
696 | static void | ||
697 | server_reschedule_session_timeout (struct GNUNET_ATS_Session *s) | ||
698 | { | ||
699 | GNUNET_assert (NULL != s->timeout_task); | ||
700 | s->timeout = GNUNET_TIME_relative_to_absolute ( | ||
701 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | ||
702 | } | ||
703 | |||
704 | |||
705 | /** | ||
706 | * Function that can be used by the transport service to transmit | ||
707 | * a message using the plugin. Note that in the case of a | ||
708 | * peer disconnecting, the continuation MUST be called | ||
709 | * prior to the disconnect notification itself. This function | ||
710 | * will be called with this peer's HELLO message to initiate | ||
711 | * a fresh connection to another peer. | ||
712 | * | ||
713 | * @param cls closure | ||
714 | * @param session which session must be used | ||
715 | * @param msgbuf the message to transmit | ||
716 | * @param msgbuf_size number of bytes in @a msgbuf | ||
717 | * @param priority how important is the message (most plugins will | ||
718 | * ignore message priority and just FIFO) | ||
719 | * @param to how long to wait at most for the transmission (does not | ||
720 | * require plugins to discard the message after the timeout, | ||
721 | * just advisory for the desired delay; most plugins will ignore | ||
722 | * this as well) | ||
723 | * @param cont continuation to call once the message has | ||
724 | * been transmitted (or if the transport is ready | ||
725 | * for the next transmission call; or if the | ||
726 | * peer disconnected...); can be NULL | ||
727 | * @param cont_cls closure for @a cont | ||
728 | * @return number of bytes used (on the physical network, with overheads); | ||
729 | * -1 on hard errors (i.e. address invalid); 0 is a legal value | ||
730 | * and does NOT mean that the message was not transmitted (DV) | ||
731 | */ | ||
732 | static ssize_t | ||
733 | http_server_plugin_send (void *cls, | ||
734 | struct GNUNET_ATS_Session *session, | ||
735 | const char *msgbuf, | ||
736 | size_t msgbuf_size, | ||
737 | unsigned int priority, | ||
738 | struct GNUNET_TIME_Relative to, | ||
739 | GNUNET_TRANSPORT_TransmitContinuation cont, | ||
740 | void *cont_cls) | ||
741 | { | ||
742 | struct HTTP_Server_Plugin *plugin = cls; | ||
743 | struct HTTP_Message *msg; | ||
744 | ssize_t bytes_sent = 0; | ||
745 | char *stat_txt; | ||
746 | |||
747 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
748 | "Session %p/request %p: Sending message with %lu to peer `%s'\n", | ||
749 | session, | ||
750 | session->server_send, | ||
751 | (unsigned long) msgbuf_size, | ||
752 | GNUNET_i2s (&session->target)); | ||
753 | |||
754 | /* create new message and schedule */ | ||
755 | bytes_sent = sizeof(struct HTTP_Message) + msgbuf_size; | ||
756 | msg = GNUNET_malloc (bytes_sent); | ||
757 | msg->next = NULL; | ||
758 | msg->size = msgbuf_size; | ||
759 | msg->pos = 0; | ||
760 | msg->buf = (char *) &msg[1]; | ||
761 | msg->transmit_cont = cont; | ||
762 | msg->transmit_cont_cls = cont_cls; | ||
763 | GNUNET_memcpy (msg->buf, | ||
764 | msgbuf, | ||
765 | msgbuf_size); | ||
766 | GNUNET_CONTAINER_DLL_insert_tail (session->msg_head, | ||
767 | session->msg_tail, | ||
768 | msg); | ||
769 | session->msgs_in_queue++; | ||
770 | session->bytes_in_queue += msg->size; | ||
771 | notify_session_monitor (plugin, | ||
772 | session, | ||
773 | GNUNET_TRANSPORT_SS_UP); | ||
774 | GNUNET_asprintf (&stat_txt, | ||
775 | "# bytes currently in %s_server buffers", | ||
776 | plugin->protocol); | ||
777 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
778 | stat_txt, msgbuf_size, GNUNET_NO); | ||
779 | GNUNET_free (stat_txt); | ||
780 | |||
781 | if (NULL != session->server_send) | ||
782 | { | ||
783 | if (session->server_send->suspended) | ||
784 | { | ||
785 | MHD_resume_connection (session->server_send->mhd_conn); | ||
786 | session->server_send->suspended = false; | ||
787 | } | ||
788 | server_reschedule (session->plugin, | ||
789 | session->server_send->mhd_daemon, | ||
790 | GNUNET_YES); | ||
791 | } | ||
792 | return bytes_sent; | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * Terminate session during shutdown. | ||
798 | * | ||
799 | * @param cls the `struct HTTP_Server_Plugin *` | ||
800 | * @param peer for which this is a session | ||
801 | * @param value the `struct GNUNET_ATS_Session` to clean up | ||
802 | * @return #GNUNET_OK (continue to iterate) | ||
803 | */ | ||
804 | static int | ||
805 | destroy_session_shutdown_cb (void *cls, | ||
806 | const struct GNUNET_PeerIdentity *peer, | ||
807 | void *value) | ||
808 | { | ||
809 | struct GNUNET_ATS_Session *s = value; | ||
810 | struct ServerRequest *sc_send; | ||
811 | struct ServerRequest *sc_recv; | ||
812 | |||
813 | sc_send = s->server_send; | ||
814 | sc_recv = s->server_recv; | ||
815 | server_delete_session (s); | ||
816 | if (NULL != sc_send) | ||
817 | sc_send->session = NULL; | ||
818 | if (NULL != sc_recv) | ||
819 | sc_recv->session = NULL; | ||
820 | |||
821 | return GNUNET_OK; | ||
822 | } | ||
823 | |||
824 | |||
825 | /** | ||
826 | * Terminate session. | ||
827 | * | ||
828 | * @param cls the `struct HTTP_Server_Plugin *` | ||
829 | * @param peer for which this is a session | ||
830 | * @param value the `struct GNUNET_ATS_Session` to clean up | ||
831 | * @return #GNUNET_OK (continue to iterate) | ||
832 | */ | ||
833 | static int | ||
834 | destroy_session_cb (void *cls, | ||
835 | const struct GNUNET_PeerIdentity *peer, | ||
836 | void *value) | ||
837 | { | ||
838 | struct GNUNET_ATS_Session *s = value; | ||
839 | |||
840 | server_delete_session (s); | ||
841 | return GNUNET_OK; | ||
842 | } | ||
843 | |||
844 | |||
845 | /** | ||
846 | * Function that can be used to force the plugin to disconnect | ||
847 | * from the given peer and cancel all previous transmissions | ||
848 | * (and their continuationc). | ||
849 | * | ||
850 | * @param cls closure | ||
851 | * @param target peer from which to disconnect | ||
852 | */ | ||
853 | static void | ||
854 | http_server_plugin_disconnect_peer (void *cls, | ||
855 | const struct GNUNET_PeerIdentity *target) | ||
856 | { | ||
857 | struct HTTP_Server_Plugin *plugin = cls; | ||
858 | |||
859 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
860 | "Transport tells me to disconnect `%s'\n", | ||
861 | GNUNET_i2s (target)); | ||
862 | GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions, | ||
863 | target, | ||
864 | &destroy_session_cb, | ||
865 | plugin); | ||
866 | } | ||
867 | |||
868 | |||
869 | /** | ||
870 | * Another peer has suggested an address for this | ||
871 | * peer and transport plugin. Check that this could be a valid | ||
872 | * address. If so, consider adding it to the list | ||
873 | * of addresses. | ||
874 | * | ||
875 | * @param cls closure | ||
876 | * @param addr pointer to the address | ||
877 | * @param addrlen length of @a addr | ||
878 | * @return #GNUNET_OK if this is a plausible address for this peer | ||
879 | * and transport | ||
880 | */ | ||
881 | static int | ||
882 | http_server_plugin_address_suggested (void *cls, | ||
883 | const void *addr, | ||
884 | size_t addrlen) | ||
885 | { | ||
886 | struct HTTP_Server_Plugin *plugin = cls; | ||
887 | struct HttpAddressWrapper *next; | ||
888 | struct HttpAddressWrapper *pos; | ||
889 | const struct HttpAddress *haddr = addr; | ||
890 | |||
891 | if ((NULL != plugin->ext_addr) && | ||
892 | (GNUNET_YES == (http_common_cmp_addresses (addr, addrlen, | ||
893 | plugin->ext_addr->address, | ||
894 | plugin->ext_addr-> | ||
895 | address_length))) ) | ||
896 | { | ||
897 | /* Checking HTTP_OPTIONS_VERIFY_CERTIFICATE option for external hostname */ | ||
898 | if ((ntohl (haddr->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE) != | ||
899 | (plugin->options & HTTP_OPTIONS_VERIFY_CERTIFICATE)) | ||
900 | return GNUNET_NO; /* VERIFY option not set as required! */ | ||
901 | return GNUNET_OK; | ||
902 | } | ||
903 | next = plugin->addr_head; | ||
904 | while (NULL != (pos = next)) | ||
905 | { | ||
906 | next = pos->next; | ||
907 | if (GNUNET_YES == (http_common_cmp_addresses (addr, | ||
908 | addrlen, | ||
909 | pos->address, | ||
910 | pos->addrlen))) | ||
911 | return GNUNET_OK; | ||
912 | } | ||
913 | return GNUNET_NO; | ||
914 | } | ||
915 | |||
916 | |||
917 | /** | ||
918 | * Creates a new outbound session the transport | ||
919 | * service will use to send data to the peer. | ||
920 | * | ||
921 | * Since HTTP/S server cannot create sessions, always returns NULL. | ||
922 | * | ||
923 | * @param cls the plugin | ||
924 | * @param address the address | ||
925 | * @return always NULL | ||
926 | */ | ||
927 | static struct GNUNET_ATS_Session * | ||
928 | http_server_plugin_get_session (void *cls, | ||
929 | const struct GNUNET_HELLO_Address *address) | ||
930 | { | ||
931 | return NULL; | ||
932 | } | ||
933 | |||
934 | |||
935 | /** | ||
936 | * Call MHD IPv4 to process pending requests and then go back | ||
937 | * and schedule the next run. | ||
938 | * | ||
939 | * @param cls plugin as closure | ||
940 | */ | ||
941 | static void | ||
942 | server_v4_run (void *cls) | ||
943 | { | ||
944 | struct HTTP_Server_Plugin *plugin = cls; | ||
945 | |||
946 | plugin->server_v4_task = NULL; | ||
947 | plugin->server_v4_immediately = GNUNET_NO; | ||
948 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); | ||
949 | server_reschedule (plugin, plugin->server_v4, GNUNET_NO); | ||
950 | } | ||
951 | |||
952 | |||
953 | /** | ||
954 | * Call MHD IPv6 to process pending requests and then go back | ||
955 | * and schedule the next run. | ||
956 | * | ||
957 | * @param cls plugin as closure | ||
958 | */ | ||
959 | static void | ||
960 | server_v6_run (void *cls) | ||
961 | { | ||
962 | struct HTTP_Server_Plugin *plugin = cls; | ||
963 | |||
964 | plugin->server_v6_task = NULL; | ||
965 | plugin->server_v6_immediately = GNUNET_NO; | ||
966 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); | ||
967 | server_reschedule (plugin, plugin->server_v6, GNUNET_NO); | ||
968 | } | ||
969 | |||
970 | |||
971 | /** | ||
972 | * Function that queries MHD's select sets and | ||
973 | * starts the task waiting for them. | ||
974 | * | ||
975 | * @param plugin plugin | ||
976 | * @param daemon_handle the MHD daemon handle | ||
977 | * @param now schedule now | ||
978 | * @return gnunet task identifier | ||
979 | */ | ||
980 | static struct GNUNET_SCHEDULER_Task * | ||
981 | server_schedule (struct HTTP_Server_Plugin *plugin, | ||
982 | struct MHD_Daemon *daemon_handle, | ||
983 | int now) | ||
984 | { | ||
985 | struct GNUNET_SCHEDULER_Task *ret; | ||
986 | fd_set rs; | ||
987 | fd_set ws; | ||
988 | fd_set es; | ||
989 | struct GNUNET_NETWORK_FDSet *wrs; | ||
990 | struct GNUNET_NETWORK_FDSet *wws; | ||
991 | int max; | ||
992 | MHD_UNSIGNED_LONG_LONG timeout; | ||
993 | static unsigned long long last_timeout = 0; | ||
994 | int haveto; | ||
995 | struct GNUNET_TIME_Relative tv; | ||
996 | |||
997 | if (GNUNET_YES == plugin->in_shutdown) | ||
998 | return NULL; | ||
999 | |||
1000 | ret = NULL; | ||
1001 | FD_ZERO (&rs); | ||
1002 | FD_ZERO (&ws); | ||
1003 | FD_ZERO (&es); | ||
1004 | wrs = GNUNET_NETWORK_fdset_create (); | ||
1005 | wws = GNUNET_NETWORK_fdset_create (); | ||
1006 | max = -1; | ||
1007 | GNUNET_assert (MHD_YES == | ||
1008 | MHD_get_fdset (daemon_handle, | ||
1009 | &rs, | ||
1010 | &ws, | ||
1011 | &es, | ||
1012 | &max)); | ||
1013 | haveto = MHD_get_timeout (daemon_handle, &timeout); | ||
1014 | if (haveto == MHD_YES) | ||
1015 | { | ||
1016 | if (timeout != last_timeout) | ||
1017 | { | ||
1018 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1019 | "SELECT Timeout changed from %llu to %llu (ms)\n", | ||
1020 | last_timeout, timeout); | ||
1021 | last_timeout = timeout; | ||
1022 | } | ||
1023 | if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL) | ||
1024 | tv.rel_value_us = (uint64_t) timeout * 1000LL; | ||
1025 | else | ||
1026 | tv = GNUNET_TIME_UNIT_SECONDS; | ||
1027 | } | ||
1028 | else | ||
1029 | tv = GNUNET_TIME_UNIT_SECONDS; | ||
1030 | /* Force immediate run, since we have outbound data to send */ | ||
1031 | if (now == GNUNET_YES) | ||
1032 | tv = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1033 | GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); | ||
1034 | GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); | ||
1035 | |||
1036 | if (daemon_handle == plugin->server_v4) | ||
1037 | { | ||
1038 | if (plugin->server_v4_task != NULL) | ||
1039 | { | ||
1040 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1041 | plugin->server_v4_task = NULL; | ||
1042 | } | ||
1043 | #if 0 | ||
1044 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1045 | "Scheduling IPv4 server task in %llu ms\n", | ||
1046 | tv); | ||
1047 | #endif | ||
1048 | ret = | ||
1049 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1050 | tv, wrs, wws, | ||
1051 | &server_v4_run, plugin); | ||
1052 | } | ||
1053 | if (daemon_handle == plugin->server_v6) | ||
1054 | { | ||
1055 | if (plugin->server_v6_task != NULL) | ||
1056 | { | ||
1057 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1058 | plugin->server_v6_task = NULL; | ||
1059 | } | ||
1060 | #if 0 | ||
1061 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1062 | "Scheduling IPv6 server task in %llu ms\n", tv); | ||
1063 | #endif | ||
1064 | ret = | ||
1065 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1066 | tv, wrs, wws, | ||
1067 | &server_v6_run, plugin); | ||
1068 | } | ||
1069 | GNUNET_NETWORK_fdset_destroy (wrs); | ||
1070 | GNUNET_NETWORK_fdset_destroy (wws); | ||
1071 | return ret; | ||
1072 | } | ||
1073 | |||
1074 | |||
1075 | /** | ||
1076 | * Reschedule the execution of both IPv4 and IPv6 server | ||
1077 | * | ||
1078 | * @param plugin the plugin | ||
1079 | * @param server which server to schedule v4 or v6? | ||
1080 | * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait | ||
1081 | * until timeout | ||
1082 | */ | ||
1083 | static void | ||
1084 | server_reschedule (struct HTTP_Server_Plugin *plugin, | ||
1085 | struct MHD_Daemon *server, | ||
1086 | int now) | ||
1087 | { | ||
1088 | if ((server == plugin->server_v4) && (plugin->server_v4 != NULL)) | ||
1089 | { | ||
1090 | if (GNUNET_YES == plugin->server_v4_immediately) | ||
1091 | return; /* No rescheduling, server will run asap */ | ||
1092 | |||
1093 | if (GNUNET_YES == now) | ||
1094 | plugin->server_v4_immediately = GNUNET_YES; | ||
1095 | |||
1096 | if (plugin->server_v4_task != NULL) | ||
1097 | { | ||
1098 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1099 | plugin->server_v4_task = NULL; | ||
1100 | } | ||
1101 | plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now); | ||
1102 | } | ||
1103 | |||
1104 | if ((server == plugin->server_v6) && (plugin->server_v6 != NULL)) | ||
1105 | { | ||
1106 | if (GNUNET_YES == plugin->server_v6_immediately) | ||
1107 | return; /* No rescheduling, server will run asap */ | ||
1108 | |||
1109 | if (GNUNET_YES == now) | ||
1110 | plugin->server_v6_immediately = GNUNET_YES; | ||
1111 | |||
1112 | if (plugin->server_v6_task != NULL) | ||
1113 | { | ||
1114 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1115 | plugin->server_v6_task = NULL; | ||
1116 | } | ||
1117 | plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now); | ||
1118 | } | ||
1119 | } | ||
1120 | |||
1121 | |||
1122 | /** | ||
1123 | * Function that is called to get the keepalive factor. | ||
1124 | * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to | ||
1125 | * calculate the interval between keepalive packets. | ||
1126 | * | ||
1127 | * @param cls closure with the `struct HTTP_Server_Plugin` | ||
1128 | * @return keepalive factor | ||
1129 | */ | ||
1130 | static unsigned int | ||
1131 | http_server_query_keepalive_factor (void *cls) | ||
1132 | { | ||
1133 | return 3; | ||
1134 | } | ||
1135 | |||
1136 | |||
1137 | /** | ||
1138 | * Function that will be called whenever the transport service wants to | ||
1139 | * notify the plugin that a session is still active and in use and | ||
1140 | * therefore the session timeout for this session has to be updated | ||
1141 | * | ||
1142 | * @param cls closure | ||
1143 | * @param peer which peer was the session for | ||
1144 | * @param session which session is being updated | ||
1145 | */ | ||
1146 | static void | ||
1147 | http_server_plugin_update_session_timeout (void *cls, | ||
1148 | const struct | ||
1149 | GNUNET_PeerIdentity *peer, | ||
1150 | struct GNUNET_ATS_Session *session) | ||
1151 | { | ||
1152 | server_reschedule_session_timeout (session); | ||
1153 | } | ||
1154 | |||
1155 | |||
1156 | /** | ||
1157 | * Tell MHD that the connection should timeout after @a to seconds. | ||
1158 | * | ||
1159 | * @param plugin our plugin | ||
1160 | * @param s session for which the timeout changes | ||
1161 | * @param to timeout in seconds | ||
1162 | */ | ||
1163 | static void | ||
1164 | server_mhd_connection_timeout (struct HTTP_Server_Plugin *plugin, | ||
1165 | struct GNUNET_ATS_Session *s, | ||
1166 | unsigned int to) | ||
1167 | { | ||
1168 | /* Setting timeouts for other connections */ | ||
1169 | if (NULL != s->server_recv) | ||
1170 | { | ||
1171 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1172 | "Setting timeout for %p to %u sec.\n", | ||
1173 | s->server_recv, to); | ||
1174 | MHD_set_connection_option (s->server_recv->mhd_conn, | ||
1175 | MHD_CONNECTION_OPTION_TIMEOUT, | ||
1176 | to); | ||
1177 | server_reschedule (plugin, s->server_recv->mhd_daemon, GNUNET_NO); | ||
1178 | } | ||
1179 | if (NULL != s->server_send) | ||
1180 | { | ||
1181 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1182 | "Setting timeout for %p to %u sec.\n", | ||
1183 | s->server_send, to); | ||
1184 | MHD_set_connection_option (s->server_send->mhd_conn, | ||
1185 | MHD_CONNECTION_OPTION_TIMEOUT, | ||
1186 | to); | ||
1187 | server_reschedule (plugin, s->server_send->mhd_daemon, GNUNET_NO); | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | |||
1192 | /** | ||
1193 | * Parse incoming URL for tag and target | ||
1194 | * | ||
1195 | * @param plugin plugin | ||
1196 | * @param url incoming url | ||
1197 | * @param target where to store the target | ||
1198 | * @param tag where to store the tag | ||
1199 | * @param options where to store the options | ||
1200 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1201 | */ | ||
1202 | static int | ||
1203 | server_parse_url (struct HTTP_Server_Plugin *plugin, | ||
1204 | const char *url, | ||
1205 | struct GNUNET_PeerIdentity *target, | ||
1206 | uint32_t *tag, | ||
1207 | uint32_t *options) | ||
1208 | { | ||
1209 | regmatch_t matches[4]; | ||
1210 | const char *tag_start; | ||
1211 | const char *target_start; | ||
1212 | char *tag_end; | ||
1213 | char *options_end; | ||
1214 | size_t hash_length; | ||
1215 | unsigned long int rc; | ||
1216 | |||
1217 | /* URL parsing */ | ||
1218 | #define URL_REGEX \ | ||
1219 | ("^.*/([0-9A-Z]+);([0-9]+)(,[0-9]+)?$") | ||
1220 | |||
1221 | if (NULL == url) | ||
1222 | { | ||
1223 | GNUNET_break (0); | ||
1224 | return GNUNET_SYSERR; | ||
1225 | } | ||
1226 | |||
1227 | if (regexec (&plugin->url_regex, url, 4, matches, 0)) | ||
1228 | { | ||
1229 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1230 | "URL `%s' did not match regex\n", url); | ||
1231 | return GNUNET_SYSERR; | ||
1232 | } | ||
1233 | |||
1234 | target_start = &url[matches[1].rm_so]; | ||
1235 | tag_start = &url[matches[2].rm_so]; | ||
1236 | |||
1237 | /* convert tag */ | ||
1238 | rc = strtoul (tag_start, &tag_end, 10); | ||
1239 | if (&url[matches[2].rm_eo] != tag_end) | ||
1240 | { | ||
1241 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1242 | "URL tag did not line up with submatch\n"); | ||
1243 | return GNUNET_SYSERR; | ||
1244 | } | ||
1245 | if (rc == 0) | ||
1246 | { | ||
1247 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1248 | "URL tag is zero\n"); | ||
1249 | return GNUNET_SYSERR; | ||
1250 | } | ||
1251 | if ((rc == ULONG_MAX) && (ERANGE == errno)) | ||
1252 | { | ||
1253 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1254 | "URL tag > ULONG_MAX\n"); | ||
1255 | return GNUNET_SYSERR; | ||
1256 | } | ||
1257 | if (rc > UINT32_MAX) | ||
1258 | { | ||
1259 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1260 | "URL tag > UINT32_MAX\n"); | ||
1261 | return GNUNET_SYSERR; | ||
1262 | } | ||
1263 | (*tag) = (uint32_t) rc; | ||
1264 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1265 | "Found tag `%u' in url\n", | ||
1266 | *tag); | ||
1267 | |||
1268 | /* convert peer id */ | ||
1269 | hash_length = matches[1].rm_eo - matches[1].rm_so; | ||
1270 | if (hash_length != plugin->peer_id_length) | ||
1271 | { | ||
1272 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1273 | "URL target is %lu bytes, expecting %u\n", | ||
1274 | (unsigned long) hash_length, plugin->peer_id_length); | ||
1275 | return GNUNET_SYSERR; | ||
1276 | } | ||
1277 | if (GNUNET_OK != | ||
1278 | GNUNET_CRYPTO_eddsa_public_key_from_string (target_start, | ||
1279 | hash_length, | ||
1280 | &target->public_key)) | ||
1281 | { | ||
1282 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1283 | "URL target conversion failed\n"); | ||
1284 | return GNUNET_SYSERR; | ||
1285 | } | ||
1286 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1287 | "Found target `%s' in URL\n", | ||
1288 | GNUNET_i2s_full (target)); | ||
1289 | |||
1290 | /* convert options */ | ||
1291 | if (-1 == matches[3].rm_so) | ||
1292 | { | ||
1293 | *options = 0; | ||
1294 | } | ||
1295 | else | ||
1296 | { | ||
1297 | rc = strtoul (&url[matches[3].rm_so + 1], &options_end, 10); | ||
1298 | if (&url[matches[3].rm_eo] != options_end) | ||
1299 | { | ||
1300 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1301 | "URL options did not line up with submatch\n"); | ||
1302 | return GNUNET_SYSERR; | ||
1303 | } | ||
1304 | if ((rc == ULONG_MAX) && (ERANGE == errno)) | ||
1305 | { | ||
1306 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1307 | "URL options > ULONG_MAX\n"); | ||
1308 | return GNUNET_SYSERR; | ||
1309 | } | ||
1310 | if (rc > UINT32_MAX) | ||
1311 | { | ||
1312 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1313 | "URL options > UINT32_MAX\n"); | ||
1314 | return GNUNET_SYSERR; | ||
1315 | } | ||
1316 | (*options) = (uint32_t) rc; | ||
1317 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1318 | "Found options `%u' in url\n", | ||
1319 | *options); | ||
1320 | } | ||
1321 | return GNUNET_OK; | ||
1322 | } | ||
1323 | |||
1324 | |||
1325 | /** | ||
1326 | * Closure for #session_tag_it(). | ||
1327 | */ | ||
1328 | struct GNUNET_ATS_SessionTagContext | ||
1329 | { | ||
1330 | /** | ||
1331 | * Set to session matching the tag. | ||
1332 | */ | ||
1333 | struct GNUNET_ATS_Session *res; | ||
1334 | |||
1335 | /** | ||
1336 | * Tag we are looking for. | ||
1337 | */ | ||
1338 | uint32_t tag; | ||
1339 | }; | ||
1340 | |||
1341 | |||
1342 | /** | ||
1343 | * Find a session with a matching tag. | ||
1344 | * | ||
1345 | * @param cls the `struct GNUNET_ATS_SessionTagContext *` | ||
1346 | * @param key peer identity (unused) | ||
1347 | * @param value the `struct GNUNET_ATS_Session *` | ||
1348 | * @return #GNUNET_NO if we found the session, #GNUNET_OK if not | ||
1349 | */ | ||
1350 | static int | ||
1351 | session_tag_it (void *cls, | ||
1352 | const struct GNUNET_PeerIdentity *key, | ||
1353 | void *value) | ||
1354 | { | ||
1355 | struct GNUNET_ATS_SessionTagContext *stc = cls; | ||
1356 | struct GNUNET_ATS_Session *s = value; | ||
1357 | |||
1358 | if (s->tag == stc->tag) | ||
1359 | { | ||
1360 | stc->res = s; | ||
1361 | return GNUNET_NO; | ||
1362 | } | ||
1363 | return GNUNET_YES; | ||
1364 | } | ||
1365 | |||
1366 | |||
1367 | /** | ||
1368 | * Lookup a mhd connection and create one if none is found | ||
1369 | * | ||
1370 | * @param plugin the plugin handle | ||
1371 | * @param mhd_connection the incoming mhd_connection | ||
1372 | * @param url incoming requested URL | ||
1373 | * @param method PUT or GET | ||
1374 | * @return the server connecetion | ||
1375 | */ | ||
1376 | static struct ServerRequest * | ||
1377 | server_lookup_connection (struct HTTP_Server_Plugin *plugin, | ||
1378 | struct MHD_Connection *mhd_connection, | ||
1379 | const char *url, | ||
1380 | const char *method) | ||
1381 | { | ||
1382 | struct GNUNET_ATS_Session *s = NULL; | ||
1383 | struct ServerRequest *sc = NULL; | ||
1384 | const union MHD_ConnectionInfo *conn_info; | ||
1385 | struct HttpAddress *addr; | ||
1386 | struct GNUNET_PeerIdentity target; | ||
1387 | size_t addr_len; | ||
1388 | struct GNUNET_ATS_SessionTagContext stc; | ||
1389 | uint32_t options; | ||
1390 | int direction = GNUNET_SYSERR; | ||
1391 | unsigned int to; | ||
1392 | enum GNUNET_NetworkType scope; | ||
1393 | |||
1394 | conn_info = MHD_get_connection_info (mhd_connection, | ||
1395 | MHD_CONNECTION_INFO_CLIENT_ADDRESS); | ||
1396 | if ((conn_info->client_addr->sa_family != AF_INET) && | ||
1397 | (conn_info->client_addr->sa_family != AF_INET6)) | ||
1398 | return NULL; | ||
1399 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1400 | "New %s request from %s\n", | ||
1401 | method, | ||
1402 | url); | ||
1403 | stc.tag = 0; | ||
1404 | options = 0; /* make gcc happy */ | ||
1405 | if (GNUNET_SYSERR == | ||
1406 | server_parse_url (plugin, url, &target, &stc.tag, &options)) | ||
1407 | { | ||
1408 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1409 | "Invalid url %s\n", url); | ||
1410 | return NULL; | ||
1411 | } | ||
1412 | if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) | ||
1413 | direction = _RECEIVE; | ||
1414 | else if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) | ||
1415 | direction = _SEND; | ||
1416 | else | ||
1417 | { | ||
1418 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1419 | "Invalid method %s for request from %s\n", | ||
1420 | method, url); | ||
1421 | return NULL; | ||
1422 | } | ||
1423 | |||
1424 | plugin->cur_request++; | ||
1425 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1426 | "New %s request from %s with tag %u (%u of %u)\n", | ||
1427 | method, | ||
1428 | GNUNET_i2s (&target), | ||
1429 | stc.tag, | ||
1430 | plugin->cur_request, plugin->max_request); | ||
1431 | /* find existing session */ | ||
1432 | stc.res = NULL; | ||
1433 | GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions, | ||
1434 | &target, | ||
1435 | &session_tag_it, | ||
1436 | &stc); | ||
1437 | if (NULL == (s = stc.res)) | ||
1438 | { | ||
1439 | /* create new session */ | ||
1440 | addr = NULL; | ||
1441 | switch (conn_info->client_addr->sa_family) | ||
1442 | { | ||
1443 | case (AF_INET): | ||
1444 | addr = http_common_address_from_socket (plugin->protocol, | ||
1445 | conn_info->client_addr, | ||
1446 | sizeof(struct sockaddr_in)); | ||
1447 | addr_len = http_common_address_get_size (addr); | ||
1448 | scope = plugin->env->get_address_type (plugin->env->cls, | ||
1449 | conn_info->client_addr, | ||
1450 | sizeof(struct sockaddr_in)); | ||
1451 | break; | ||
1452 | |||
1453 | case (AF_INET6): | ||
1454 | addr = http_common_address_from_socket (plugin->protocol, | ||
1455 | conn_info->client_addr, | ||
1456 | sizeof(struct sockaddr_in6)); | ||
1457 | addr_len = http_common_address_get_size (addr); | ||
1458 | scope = plugin->env->get_address_type (plugin->env->cls, | ||
1459 | conn_info->client_addr, | ||
1460 | sizeof(struct sockaddr_in6)); | ||
1461 | break; | ||
1462 | |||
1463 | default: | ||
1464 | /* external host name */ | ||
1465 | return NULL; | ||
1466 | } | ||
1467 | s = GNUNET_new (struct GNUNET_ATS_Session); | ||
1468 | s->target = target; | ||
1469 | s->plugin = plugin; | ||
1470 | s->scope = scope; | ||
1471 | s->address = GNUNET_HELLO_address_allocate (&s->target, | ||
1472 | PLUGIN_NAME, | ||
1473 | addr, | ||
1474 | addr_len, | ||
1475 | GNUNET_HELLO_ADDRESS_INFO_INBOUND); | ||
1476 | s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; | ||
1477 | s->tag = stc.tag; | ||
1478 | s->timeout = GNUNET_TIME_relative_to_absolute (HTTP_SERVER_SESSION_TIMEOUT); | ||
1479 | s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT, | ||
1480 | &server_session_timeout, | ||
1481 | s); | ||
1482 | (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions, | ||
1483 | &s->target, | ||
1484 | s, | ||
1485 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1486 | notify_session_monitor (plugin, | ||
1487 | s, | ||
1488 | GNUNET_TRANSPORT_SS_INIT); | ||
1489 | notify_session_monitor (plugin, | ||
1490 | s, | ||
1491 | GNUNET_TRANSPORT_SS_HANDSHAKE); | ||
1492 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1493 | "Creating new session %p for peer `%s' connecting from `%s'\n", | ||
1494 | s, GNUNET_i2s (&target), | ||
1495 | http_common_plugin_address_to_string (plugin->protocol, | ||
1496 | addr, | ||
1497 | addr_len)); | ||
1498 | GNUNET_free (addr); | ||
1499 | } | ||
1500 | |||
1501 | if ((_RECEIVE == direction) && | ||
1502 | (NULL != s->server_recv)) | ||
1503 | { | ||
1504 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1505 | "Duplicate PUT request from `%s' tag %u, dismissing new request\n", | ||
1506 | GNUNET_i2s (&target), | ||
1507 | stc.tag); | ||
1508 | return NULL; | ||
1509 | } | ||
1510 | if ((_SEND == direction) && (NULL != s->server_send)) | ||
1511 | { | ||
1512 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1513 | "Duplicate GET request from `%s' tag %u, dismissing new request\n", | ||
1514 | GNUNET_i2s (&target), | ||
1515 | stc.tag); | ||
1516 | return NULL; | ||
1517 | } | ||
1518 | sc = GNUNET_new (struct ServerRequest); | ||
1519 | if (conn_info->client_addr->sa_family == AF_INET) | ||
1520 | sc->mhd_daemon = plugin->server_v4; | ||
1521 | if (conn_info->client_addr->sa_family == AF_INET6) | ||
1522 | sc->mhd_daemon = plugin->server_v6; | ||
1523 | sc->mhd_conn = mhd_connection; | ||
1524 | sc->direction = direction; | ||
1525 | sc->connected = GNUNET_NO; | ||
1526 | sc->session = s; | ||
1527 | sc->options = options; | ||
1528 | if (direction == _SEND) | ||
1529 | { | ||
1530 | s->server_send = sc; | ||
1531 | } | ||
1532 | if (direction == _RECEIVE) | ||
1533 | { | ||
1534 | s->server_recv = sc; | ||
1535 | } | ||
1536 | |||
1537 | if ((GNUNET_NO == s->known_to_service) && | ||
1538 | (NULL != s->server_send) && | ||
1539 | (NULL != s->server_recv)) | ||
1540 | { | ||
1541 | s->known_to_service = GNUNET_YES; | ||
1542 | notify_session_monitor (plugin, | ||
1543 | s, | ||
1544 | GNUNET_TRANSPORT_SS_UP); | ||
1545 | plugin->env->session_start (plugin->env->cls, | ||
1546 | s->address, | ||
1547 | s, | ||
1548 | s->scope); | ||
1549 | } | ||
1550 | |||
1551 | to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL); | ||
1552 | server_mhd_connection_timeout (plugin, s, to); | ||
1553 | return sc; | ||
1554 | } | ||
1555 | |||
1556 | |||
1557 | /** | ||
1558 | * Callback called by MHD when it needs data to send | ||
1559 | * | ||
1560 | * @param cls current session | ||
1561 | * @param pos position in buffer | ||
1562 | * @param buf the buffer to write data to | ||
1563 | * @param max max number of bytes available in @a buf | ||
1564 | * @return bytes written to @a buf | ||
1565 | */ | ||
1566 | static ssize_t | ||
1567 | server_send_callback (void *cls, | ||
1568 | uint64_t pos, | ||
1569 | char *buf, | ||
1570 | size_t max) | ||
1571 | { | ||
1572 | struct ServerRequest *sc = cls; | ||
1573 | struct GNUNET_ATS_Session *s = sc->session; | ||
1574 | ssize_t bytes_read = 0; | ||
1575 | struct HTTP_Message *msg; | ||
1576 | char *stat_txt; | ||
1577 | |||
1578 | if (NULL == s) | ||
1579 | { | ||
1580 | /* session is disconnecting */ | ||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | sc = s->server_send; | ||
1585 | if (NULL == sc) | ||
1586 | return 0; | ||
1587 | msg = s->msg_head; | ||
1588 | if (NULL != msg) | ||
1589 | { | ||
1590 | /* sending */ | ||
1591 | bytes_read = GNUNET_MIN (msg->size - msg->pos, | ||
1592 | max); | ||
1593 | GNUNET_memcpy (buf, &msg->buf[msg->pos], bytes_read); | ||
1594 | msg->pos += bytes_read; | ||
1595 | |||
1596 | /* removing message */ | ||
1597 | if (msg->pos == msg->size) | ||
1598 | { | ||
1599 | GNUNET_CONTAINER_DLL_remove (s->msg_head, | ||
1600 | s->msg_tail, | ||
1601 | msg); | ||
1602 | if (NULL != msg->transmit_cont) | ||
1603 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK, | ||
1604 | msg->size, msg->size + msg->overhead); | ||
1605 | GNUNET_assert (s->msgs_in_queue > 0); | ||
1606 | s->msgs_in_queue--; | ||
1607 | GNUNET_assert (s->bytes_in_queue >= msg->size); | ||
1608 | s->bytes_in_queue -= msg->size; | ||
1609 | GNUNET_free (msg); | ||
1610 | notify_session_monitor (s->plugin, | ||
1611 | s, | ||
1612 | GNUNET_TRANSPORT_SS_UPDATE); | ||
1613 | } | ||
1614 | } | ||
1615 | if (0 < bytes_read) | ||
1616 | { | ||
1617 | sc->connected = GNUNET_YES; | ||
1618 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1619 | "Sent %lu bytes to peer `%s' with session %p \n", | ||
1620 | (unsigned long) bytes_read, | ||
1621 | GNUNET_i2s (&s->target), | ||
1622 | s); | ||
1623 | GNUNET_asprintf (&stat_txt, | ||
1624 | "# bytes currently in %s_server buffers", | ||
1625 | s->plugin->protocol); | ||
1626 | GNUNET_STATISTICS_update (s->plugin->env->stats, | ||
1627 | stat_txt, | ||
1628 | -bytes_read, | ||
1629 | GNUNET_NO); | ||
1630 | GNUNET_free (stat_txt); | ||
1631 | GNUNET_asprintf (&stat_txt, | ||
1632 | "# bytes transmitted via %s_server", | ||
1633 | s->plugin->protocol); | ||
1634 | GNUNET_STATISTICS_update (s->plugin->env->stats, | ||
1635 | stat_txt, bytes_read, GNUNET_NO); | ||
1636 | GNUNET_free (stat_txt); | ||
1637 | } | ||
1638 | else if ((sc->options & OPTION_LONG_POLL) && sc->connected) | ||
1639 | { | ||
1640 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1641 | "Completing GET response to peer `%s' with session %p\n", | ||
1642 | GNUNET_i2s (&s->target), | ||
1643 | s); | ||
1644 | return MHD_CONTENT_READER_END_OF_STREAM; | ||
1645 | } | ||
1646 | else | ||
1647 | { | ||
1648 | MHD_suspend_connection (s->server_send->mhd_conn); | ||
1649 | s->server_send->suspended = true; | ||
1650 | return 0; | ||
1651 | } | ||
1652 | return bytes_read; | ||
1653 | } | ||
1654 | |||
1655 | |||
1656 | /** | ||
1657 | * Callback called by MessageStreamTokenizer when a message has arrived | ||
1658 | * | ||
1659 | * @param cls current session as closure | ||
1660 | * @param message the message to be forwarded to transport service | ||
1661 | * @return #GNUNET_OK (all OK) | ||
1662 | */ | ||
1663 | static int | ||
1664 | server_receive_mst_cb (void *cls, | ||
1665 | const struct GNUNET_MessageHeader *message) | ||
1666 | { | ||
1667 | struct GNUNET_ATS_Session *s = cls; | ||
1668 | struct HTTP_Server_Plugin *plugin = s->plugin; | ||
1669 | struct GNUNET_TIME_Relative delay; | ||
1670 | char *stat_txt; | ||
1671 | |||
1672 | if (GNUNET_NO == s->known_to_service) | ||
1673 | { | ||
1674 | s->known_to_service = GNUNET_YES; | ||
1675 | plugin->env->session_start (plugin->env->cls, | ||
1676 | s->address, | ||
1677 | s, | ||
1678 | s->scope); | ||
1679 | notify_session_monitor (plugin, | ||
1680 | s, | ||
1681 | GNUNET_TRANSPORT_SS_UP); | ||
1682 | } | ||
1683 | delay = plugin->env->receive (plugin->env->cls, | ||
1684 | s->address, | ||
1685 | s, | ||
1686 | message); | ||
1687 | GNUNET_asprintf (&stat_txt, | ||
1688 | "# bytes received via %s_server", | ||
1689 | plugin->protocol); | ||
1690 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1691 | stat_txt, | ||
1692 | ntohs (message->size), | ||
1693 | GNUNET_NO); | ||
1694 | GNUNET_free (stat_txt); | ||
1695 | s->next_receive = GNUNET_TIME_relative_to_absolute (delay); | ||
1696 | if (delay.rel_value_us > 0) | ||
1697 | { | ||
1698 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1699 | "Peer `%s' address `%s' next read delayed for %s\n", | ||
1700 | GNUNET_i2s (&s->target), | ||
1701 | http_common_plugin_address_to_string (plugin->protocol, | ||
1702 | s->address->address, | ||
1703 | s->address->address_length), | ||
1704 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
1705 | GNUNET_YES)); | ||
1706 | } | ||
1707 | server_reschedule_session_timeout (s); | ||
1708 | return GNUNET_OK; | ||
1709 | } | ||
1710 | |||
1711 | |||
1712 | /** | ||
1713 | * Add headers to a request indicating that we allow Cross-Origin Resource | ||
1714 | * Sharing. | ||
1715 | * | ||
1716 | * @param response response object to modify | ||
1717 | */ | ||
1718 | static void | ||
1719 | add_cors_headers (struct MHD_Response *response) | ||
1720 | { | ||
1721 | MHD_add_response_header (response, | ||
1722 | "Access-Control-Allow-Origin", | ||
1723 | "*"); | ||
1724 | MHD_add_response_header (response, | ||
1725 | "Access-Control-Allow-Methods", | ||
1726 | "GET, PUT, OPTIONS"); | ||
1727 | MHD_add_response_header (response, | ||
1728 | "Access-Control-Max-Age", | ||
1729 | "86400"); | ||
1730 | } | ||
1731 | |||
1732 | |||
1733 | /** | ||
1734 | * MHD callback for a new incoming connection | ||
1735 | * | ||
1736 | * @param cls the plugin handle | ||
1737 | * @param mhd_connection the mhd connection | ||
1738 | * @param url the requested URL | ||
1739 | * @param method GET or PUT | ||
1740 | * @param version HTTP version | ||
1741 | * @param upload_data upload data | ||
1742 | * @param upload_data_size size of @a upload_data | ||
1743 | * @param httpSessionCache the session cache to remember the connection | ||
1744 | * @return #MHD_YES if connection is accepted, #MHD_NO on reject | ||
1745 | */ | ||
1746 | static MHD_RESULT | ||
1747 | server_access_cb (void *cls, | ||
1748 | struct MHD_Connection *mhd_connection, | ||
1749 | const char *url, | ||
1750 | const char *method, | ||
1751 | const char *version, | ||
1752 | const char *upload_data, | ||
1753 | size_t *upload_data_size, | ||
1754 | void **httpSessionCache) | ||
1755 | { | ||
1756 | struct HTTP_Server_Plugin *plugin = cls; | ||
1757 | struct ServerRequest *sc = *httpSessionCache; | ||
1758 | struct GNUNET_ATS_Session *s; | ||
1759 | struct MHD_Response *response; | ||
1760 | MHD_RESULT res = MHD_YES; | ||
1761 | |||
1762 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1763 | _ ( | ||
1764 | "Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %lu\n"), | ||
1765 | sc, | ||
1766 | plugin->cur_request, | ||
1767 | plugin->max_request, | ||
1768 | method, | ||
1769 | version, | ||
1770 | url, | ||
1771 | (unsigned long) (*upload_data_size)); | ||
1772 | if (NULL == sc) | ||
1773 | { | ||
1774 | /* CORS pre-flight request */ | ||
1775 | if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method)) | ||
1776 | { | ||
1777 | response = MHD_create_response_from_buffer (0, NULL, | ||
1778 | MHD_RESPMEM_PERSISTENT); | ||
1779 | add_cors_headers (response); | ||
1780 | res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
1781 | MHD_destroy_response (response); | ||
1782 | return res; | ||
1783 | } | ||
1784 | /* new connection */ | ||
1785 | sc = server_lookup_connection (plugin, mhd_connection, url, method); | ||
1786 | if (NULL != sc) | ||
1787 | { | ||
1788 | /* attach to new / existing session */ | ||
1789 | (*httpSessionCache) = sc; | ||
1790 | } | ||
1791 | else | ||
1792 | { | ||
1793 | /* existing session already has matching connection, refuse */ | ||
1794 | response = MHD_create_response_from_buffer (strlen (HTTP_ERROR_RESPONSE), | ||
1795 | HTTP_ERROR_RESPONSE, | ||
1796 | MHD_RESPMEM_PERSISTENT); | ||
1797 | MHD_add_response_header (response, | ||
1798 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
1799 | "text/html"); | ||
1800 | add_cors_headers (response); | ||
1801 | res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response); | ||
1802 | MHD_destroy_response (response); | ||
1803 | return res; | ||
1804 | } | ||
1805 | } | ||
1806 | /* 'old' connection */ | ||
1807 | if (NULL == (s = sc->session)) | ||
1808 | { | ||
1809 | /* Session was already disconnected; | ||
1810 | sent HTTP/1.1: 200 OK as response */ | ||
1811 | response = MHD_create_response_from_buffer (strlen ("Thank you!"), | ||
1812 | "Thank you!", | ||
1813 | MHD_RESPMEM_PERSISTENT); | ||
1814 | add_cors_headers (response); | ||
1815 | MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
1816 | MHD_destroy_response (response); | ||
1817 | return MHD_YES; | ||
1818 | } | ||
1819 | |||
1820 | if (sc->direction == _SEND) | ||
1821 | { | ||
1822 | response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 32 * 1024, | ||
1823 | &server_send_callback, sc, | ||
1824 | NULL); | ||
1825 | add_cors_headers (response); | ||
1826 | MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
1827 | MHD_destroy_response (response); | ||
1828 | return MHD_YES; | ||
1829 | } | ||
1830 | if (sc->direction == _RECEIVE) | ||
1831 | { | ||
1832 | if ((*upload_data_size == 0) && (sc->connected == GNUNET_NO)) | ||
1833 | { | ||
1834 | /* (*upload_data_size == 0) first callback when header are passed */ | ||
1835 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1836 | "Session %p / Connection %p: Peer `%s' PUT on address `%s' connected\n", | ||
1837 | s, sc, | ||
1838 | GNUNET_i2s (&s->target), | ||
1839 | http_common_plugin_address_to_string (plugin->protocol, | ||
1840 | s->address->address, | ||
1841 | s->address->address_length)); | ||
1842 | sc->connected = GNUNET_YES; | ||
1843 | return MHD_YES; | ||
1844 | } | ||
1845 | else if ((*upload_data_size == 0) && (sc->connected == GNUNET_YES)) | ||
1846 | { | ||
1847 | /* (*upload_data_size == 0) when upload is complete */ | ||
1848 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1849 | "Session %p / Connection %p: Peer `%s' PUT on address `%s' finished upload\n", | ||
1850 | s, sc, | ||
1851 | GNUNET_i2s (&s->target), | ||
1852 | http_common_plugin_address_to_string (plugin->protocol, | ||
1853 | s->address->address, | ||
1854 | s->address->address_length)); | ||
1855 | sc->connected = GNUNET_NO; | ||
1856 | /* Sent HTTP/1.1: 200 OK as PUT Response\ */ | ||
1857 | response = MHD_create_response_from_buffer (strlen ("Thank you!"), | ||
1858 | "Thank you!", | ||
1859 | MHD_RESPMEM_PERSISTENT); | ||
1860 | add_cors_headers (response); | ||
1861 | MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
1862 | MHD_destroy_response (response); | ||
1863 | return MHD_YES; | ||
1864 | } | ||
1865 | else if ((*upload_data_size > 0) && (sc->connected == GNUNET_YES)) | ||
1866 | { | ||
1867 | struct GNUNET_TIME_Relative delay; | ||
1868 | |||
1869 | /* (*upload_data_size > 0) for every segment received */ | ||
1870 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1871 | "Session %p / Connection %p: Peer `%s' PUT on address `%s' received %lu bytes\n", | ||
1872 | s, sc, | ||
1873 | GNUNET_i2s (&s->target), | ||
1874 | http_common_plugin_address_to_string (plugin->protocol, | ||
1875 | s->address->address, | ||
1876 | s->address->address_length), | ||
1877 | (unsigned long) *upload_data_size); | ||
1878 | delay = GNUNET_TIME_absolute_get_remaining (s->next_receive); | ||
1879 | if (0 == delay.rel_value_us) | ||
1880 | { | ||
1881 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1882 | "PUT with %lu bytes forwarded to MST\n", | ||
1883 | (unsigned long) *upload_data_size); | ||
1884 | if (s->msg_tk == NULL) | ||
1885 | { | ||
1886 | s->msg_tk = GNUNET_MST_create (&server_receive_mst_cb, | ||
1887 | s); | ||
1888 | } | ||
1889 | GNUNET_MST_from_buffer (s->msg_tk, | ||
1890 | upload_data, | ||
1891 | *upload_data_size, | ||
1892 | GNUNET_NO, GNUNET_NO); | ||
1893 | server_mhd_connection_timeout (plugin, s, | ||
1894 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT. | ||
1895 | rel_value_us / 1000LL | ||
1896 | / 1000LL); | ||
1897 | (*upload_data_size) = 0; | ||
1898 | } | ||
1899 | else | ||
1900 | { | ||
1901 | /* delay processing */ | ||
1902 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1903 | "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n", | ||
1904 | s, | ||
1905 | sc, | ||
1906 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
1907 | GNUNET_YES)); | ||
1908 | GNUNET_assert (s->server_recv->mhd_conn == mhd_connection); | ||
1909 | MHD_suspend_connection (s->server_recv->mhd_conn); | ||
1910 | s->server_recv->suspended = true; | ||
1911 | if (NULL == s->recv_wakeup_task) | ||
1912 | s->recv_wakeup_task | ||
1913 | = GNUNET_SCHEDULER_add_delayed (delay, | ||
1914 | &server_wake_up, | ||
1915 | s); | ||
1916 | } | ||
1917 | return MHD_YES; | ||
1918 | } | ||
1919 | else | ||
1920 | { | ||
1921 | GNUNET_break (0); | ||
1922 | return MHD_NO; | ||
1923 | } | ||
1924 | } | ||
1925 | return res; | ||
1926 | } | ||
1927 | |||
1928 | |||
1929 | /** | ||
1930 | * Callback from MHD when a connection disconnects | ||
1931 | * | ||
1932 | * @param cls closure with the `struct HTTP_Server_Plugin *` | ||
1933 | * @param connection the disconnected MHD connection | ||
1934 | * @param httpSessionCache the pointer to distinguish | ||
1935 | */ | ||
1936 | static void | ||
1937 | server_disconnect_cb (void *cls, | ||
1938 | struct MHD_Connection *connection, | ||
1939 | void **httpSessionCache) | ||
1940 | { | ||
1941 | struct HTTP_Server_Plugin *plugin = cls; | ||
1942 | struct ServerRequest *sc = *httpSessionCache; | ||
1943 | |||
1944 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1945 | "Disconnect for connection %p\n", | ||
1946 | sc); | ||
1947 | if (NULL == sc) | ||
1948 | { | ||
1949 | /* CORS pre-flight request finished */ | ||
1950 | return; | ||
1951 | } | ||
1952 | |||
1953 | if (NULL != sc->session) | ||
1954 | { | ||
1955 | if (sc->direction == _SEND) | ||
1956 | { | ||
1957 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1958 | "Peer `%s' connection %p, GET on address `%s' disconnected\n", | ||
1959 | GNUNET_i2s (&sc->session->target), | ||
1960 | sc->session->server_send, | ||
1961 | http_common_plugin_address_to_string (plugin->protocol, | ||
1962 | sc->session->address->address, | ||
1963 | sc->session->address-> | ||
1964 | address_length)); | ||
1965 | |||
1966 | sc->session->server_send = NULL; | ||
1967 | } | ||
1968 | else if (sc->direction == _RECEIVE) | ||
1969 | { | ||
1970 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1971 | "Peer `%s' connection %p PUT on address `%s' disconnected\n", | ||
1972 | GNUNET_i2s (&sc->session->target), | ||
1973 | sc->session->server_recv, | ||
1974 | http_common_plugin_address_to_string (plugin->protocol, | ||
1975 | sc->session->address->address, | ||
1976 | sc->session->address-> | ||
1977 | address_length)); | ||
1978 | sc->session->server_recv = NULL; | ||
1979 | if (NULL != sc->session->msg_tk) | ||
1980 | { | ||
1981 | GNUNET_MST_destroy (sc->session->msg_tk); | ||
1982 | sc->session->msg_tk = NULL; | ||
1983 | } | ||
1984 | } | ||
1985 | } | ||
1986 | GNUNET_free (sc); | ||
1987 | plugin->cur_request--; | ||
1988 | } | ||
1989 | |||
1990 | |||
1991 | /** | ||
1992 | * Callback from MHD when a connection starts/stops | ||
1993 | * | ||
1994 | * @param cls closure with the `struct HTTP_Server_Plugin *` | ||
1995 | * @param connection connection handle | ||
1996 | * @param socket_context socket-specific pointer | ||
1997 | * @param toe reason for connection notification | ||
1998 | * @see #MHD_OPTION_NOTIFY_CONNECTION | ||
1999 | */ | ||
2000 | static void | ||
2001 | server_connection_cb (void *cls, | ||
2002 | struct MHD_Connection *connection, | ||
2003 | void **socket_context, | ||
2004 | enum MHD_ConnectionNotificationCode toe) | ||
2005 | { | ||
2006 | struct HTTP_Server_Plugin *plugin = cls; | ||
2007 | const union MHD_ConnectionInfo *info; | ||
2008 | |||
2009 | if (MHD_CONNECTION_NOTIFY_STARTED == toe) | ||
2010 | return; | ||
2011 | |||
2012 | /* Reschedule to remove closed socket from our select set */ | ||
2013 | info = MHD_get_connection_info (connection, | ||
2014 | MHD_CONNECTION_INFO_DAEMON); | ||
2015 | GNUNET_assert (NULL != info); | ||
2016 | server_reschedule (plugin, | ||
2017 | info->daemon, | ||
2018 | GNUNET_YES); | ||
2019 | } | ||
2020 | |||
2021 | |||
2022 | /** | ||
2023 | * Check if incoming connection is accepted. | ||
2024 | * | ||
2025 | * @param cls plugin as closure | ||
2026 | * @param addr address of incoming connection | ||
2027 | * @param addr_len number of bytes in @a addr | ||
2028 | * @return #MHD_YES if connection is accepted, #MHD_NO if connection is rejected | ||
2029 | */ | ||
2030 | static MHD_RESULT | ||
2031 | server_accept_cb (void *cls, | ||
2032 | const struct sockaddr *addr, | ||
2033 | socklen_t addr_len) | ||
2034 | { | ||
2035 | struct HTTP_Server_Plugin *plugin = cls; | ||
2036 | |||
2037 | if (plugin->cur_request <= plugin->max_request) | ||
2038 | { | ||
2039 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2040 | _ ("Accepting connection (%u of %u) from `%s'\n"), | ||
2041 | plugin->cur_request, plugin->max_request, | ||
2042 | GNUNET_a2s (addr, addr_len)); | ||
2043 | return MHD_YES; | ||
2044 | } | ||
2045 | else | ||
2046 | { | ||
2047 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2048 | _ ( | ||
2049 | "Server reached maximum number connections (%u), rejecting new connection\n"), | ||
2050 | plugin->max_request); | ||
2051 | return MHD_NO; | ||
2052 | } | ||
2053 | } | ||
2054 | |||
2055 | |||
2056 | /** | ||
2057 | * Log function called by MHD. | ||
2058 | * | ||
2059 | * @param arg NULL | ||
2060 | * @param fmt format string | ||
2061 | * @param ap arguments for the format string (va_start() and va_end() | ||
2062 | * will be called by MHD) | ||
2063 | */ | ||
2064 | static void | ||
2065 | server_log (void *arg, | ||
2066 | const char *fmt, | ||
2067 | va_list ap) | ||
2068 | { | ||
2069 | char text[1024]; | ||
2070 | |||
2071 | vsnprintf (text, | ||
2072 | sizeof(text), | ||
2073 | fmt, | ||
2074 | ap); | ||
2075 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2076 | "Server: %s\n", | ||
2077 | text); | ||
2078 | } | ||
2079 | |||
2080 | |||
2081 | #if BUILD_HTTPS | ||
2082 | /** | ||
2083 | * Load ssl certificate from file | ||
2084 | * | ||
2085 | * @param file filename | ||
2086 | * @return content of the file | ||
2087 | */ | ||
2088 | static char * | ||
2089 | server_load_file (const char *file) | ||
2090 | { | ||
2091 | struct GNUNET_DISK_FileHandle *gn_file; | ||
2092 | uint64_t fsize; | ||
2093 | char *text = NULL; | ||
2094 | |||
2095 | if (GNUNET_OK != GNUNET_DISK_file_size (file, | ||
2096 | &fsize, GNUNET_NO, GNUNET_YES)) | ||
2097 | return NULL; | ||
2098 | text = GNUNET_malloc (fsize + 1); | ||
2099 | gn_file = | ||
2100 | GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, | ||
2101 | GNUNET_DISK_PERM_USER_READ); | ||
2102 | if (NULL == gn_file) | ||
2103 | { | ||
2104 | GNUNET_free (text); | ||
2105 | return NULL; | ||
2106 | } | ||
2107 | if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize)) | ||
2108 | { | ||
2109 | GNUNET_free (text); | ||
2110 | GNUNET_DISK_file_close (gn_file); | ||
2111 | return NULL; | ||
2112 | } | ||
2113 | text[fsize] = '\0'; | ||
2114 | GNUNET_DISK_file_close (gn_file); | ||
2115 | return text; | ||
2116 | } | ||
2117 | |||
2118 | |||
2119 | #endif | ||
2120 | |||
2121 | |||
2122 | #if BUILD_HTTPS | ||
2123 | /** | ||
2124 | * Load ssl certificate | ||
2125 | * | ||
2126 | * @param plugin the plugin | ||
2127 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
2128 | */ | ||
2129 | static int | ||
2130 | server_load_certificate (struct HTTP_Server_Plugin *plugin) | ||
2131 | { | ||
2132 | int res = GNUNET_OK; | ||
2133 | char *key_file; | ||
2134 | char *cert_file; | ||
2135 | |||
2136 | |||
2137 | if (GNUNET_OK != | ||
2138 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, | ||
2139 | plugin->name, | ||
2140 | "KEY_FILE", &key_file)) | ||
2141 | { | ||
2142 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
2143 | plugin->name, "CERT_FILE"); | ||
2144 | return GNUNET_SYSERR; | ||
2145 | } | ||
2146 | if (GNUNET_OK != | ||
2147 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, | ||
2148 | plugin->name, | ||
2149 | "CERT_FILE", &cert_file)) | ||
2150 | { | ||
2151 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
2152 | plugin->name, "CERT_FILE"); | ||
2153 | GNUNET_free (key_file); | ||
2154 | return GNUNET_SYSERR; | ||
2155 | } | ||
2156 | /* Get crypto init string from config. If not present, use | ||
2157 | * default values */ | ||
2158 | if (GNUNET_OK == | ||
2159 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, | ||
2160 | plugin->name, | ||
2161 | "CRYPTO_INIT", | ||
2162 | &plugin->crypto_init)) | ||
2163 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2164 | "Using crypto init string `%s'\n", | ||
2165 | plugin->crypto_init); | ||
2166 | else | ||
2167 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2168 | "Using default crypto init string \n"); | ||
2169 | |||
2170 | /* read key & certificates from file */ | ||
2171 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2172 | "Trying to loading TLS certificate from key-file `%s' cert-file`%s'\n", | ||
2173 | key_file, cert_file); | ||
2174 | |||
2175 | plugin->key = server_load_file (key_file); | ||
2176 | plugin->cert = server_load_file (cert_file); | ||
2177 | |||
2178 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
2179 | { | ||
2180 | struct GNUNET_OS_Process *cert_creation; | ||
2181 | |||
2182 | GNUNET_free (plugin->key); | ||
2183 | plugin->key = NULL; | ||
2184 | GNUNET_free (plugin->cert); | ||
2185 | plugin->cert = NULL; | ||
2186 | |||
2187 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2188 | "No usable TLS certificate found, creating certificate\n"); | ||
2189 | errno = 0; | ||
2190 | cert_creation = | ||
2191 | GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR, | ||
2192 | NULL, NULL, NULL, | ||
2193 | "gnunet-transport-certificate-creation", | ||
2194 | "gnunet-transport-certificate-creation", | ||
2195 | key_file, | ||
2196 | cert_file, | ||
2197 | NULL); | ||
2198 | if (NULL == cert_creation) | ||
2199 | { | ||
2200 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2201 | _ ( | ||
2202 | "Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); | ||
2203 | GNUNET_free (key_file); | ||
2204 | GNUNET_free (cert_file); | ||
2205 | |||
2206 | GNUNET_free (plugin->key); | ||
2207 | plugin->key = NULL; | ||
2208 | GNUNET_free (plugin->cert); | ||
2209 | plugin->cert = NULL; | ||
2210 | GNUNET_free (plugin->crypto_init); | ||
2211 | plugin->crypto_init = NULL; | ||
2212 | |||
2213 | return GNUNET_SYSERR; | ||
2214 | } | ||
2215 | GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); | ||
2216 | GNUNET_OS_process_destroy (cert_creation); | ||
2217 | |||
2218 | plugin->key = server_load_file (key_file); | ||
2219 | plugin->cert = server_load_file (cert_file); | ||
2220 | } | ||
2221 | |||
2222 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
2223 | { | ||
2224 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2225 | _ ( | ||
2226 | "No usable TLS certificate found and creating one at `%s/%s' failed!\n"), | ||
2227 | key_file, cert_file); | ||
2228 | GNUNET_free (key_file); | ||
2229 | GNUNET_free (cert_file); | ||
2230 | |||
2231 | GNUNET_free (plugin->key); | ||
2232 | plugin->key = NULL; | ||
2233 | GNUNET_free (plugin->cert); | ||
2234 | plugin->cert = NULL; | ||
2235 | GNUNET_free (plugin->crypto_init); | ||
2236 | plugin->crypto_init = NULL; | ||
2237 | |||
2238 | return GNUNET_SYSERR; | ||
2239 | } | ||
2240 | GNUNET_free (key_file); | ||
2241 | GNUNET_free (cert_file); | ||
2242 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2243 | "TLS certificate loaded\n"); | ||
2244 | return res; | ||
2245 | } | ||
2246 | |||
2247 | |||
2248 | #endif | ||
2249 | |||
2250 | |||
2251 | /** | ||
2252 | * Invoke `MHD_start_daemon` with the various options we need to | ||
2253 | * setup the HTTP server with the given listen address. | ||
2254 | * | ||
2255 | * @param plugin our plugin | ||
2256 | * @param addr listen address to use | ||
2257 | * @param v6 MHD_NO_FLAG or MHD_USE_IPv6, depending on context | ||
2258 | * @return NULL on error | ||
2259 | */ | ||
2260 | static struct MHD_Daemon * | ||
2261 | run_mhd_start_daemon (struct HTTP_Server_Plugin *plugin, | ||
2262 | const struct sockaddr_in *addr, | ||
2263 | int v6) | ||
2264 | { | ||
2265 | struct MHD_Daemon *server; | ||
2266 | unsigned int timeout; | ||
2267 | |||
2268 | #if MHD_VERSION >= 0x00090E00 | ||
2269 | timeout = HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL / 1000LL; | ||
2270 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2271 | "MHD can set timeout per connection! Default time out %u sec.\n", | ||
2272 | timeout); | ||
2273 | #else | ||
2274 | timeout = HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL; | ||
2275 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2276 | "MHD cannot set timeout per connection! Default time out %u sec.\n", | ||
2277 | timeout); | ||
2278 | #endif | ||
2279 | server = MHD_start_daemon ( | ||
2280 | #if VERBOSE_SERVER | ||
2281 | MHD_USE_DEBUG | | ||
2282 | #endif | ||
2283 | #if BUILD_HTTPS | ||
2284 | MHD_USE_SSL | | ||
2285 | #endif | ||
2286 | MHD_USE_SUSPEND_RESUME | ||
2287 | | v6, | ||
2288 | plugin->port, | ||
2289 | &server_accept_cb, plugin, | ||
2290 | &server_access_cb, plugin, | ||
2291 | MHD_OPTION_SOCK_ADDR, | ||
2292 | addr, | ||
2293 | MHD_OPTION_CONNECTION_LIMIT, | ||
2294 | (unsigned int) plugin->max_request, | ||
2295 | #if BUILD_HTTPS | ||
2296 | MHD_OPTION_HTTPS_PRIORITIES, | ||
2297 | plugin->crypto_init, | ||
2298 | MHD_OPTION_HTTPS_MEM_KEY, | ||
2299 | plugin->key, | ||
2300 | MHD_OPTION_HTTPS_MEM_CERT, | ||
2301 | plugin->cert, | ||
2302 | #endif | ||
2303 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
2304 | timeout, | ||
2305 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
2306 | (size_t) (2 | ||
2307 | * GNUNET_MAX_MESSAGE_SIZE), | ||
2308 | MHD_OPTION_NOTIFY_COMPLETED, | ||
2309 | &server_disconnect_cb, plugin, | ||
2310 | MHD_OPTION_NOTIFY_CONNECTION, | ||
2311 | &server_connection_cb, plugin, | ||
2312 | MHD_OPTION_EXTERNAL_LOGGER, | ||
2313 | &server_log, NULL, | ||
2314 | MHD_OPTION_END); | ||
2315 | #ifdef TCP_STEALTH | ||
2316 | if ((NULL != server) && | ||
2317 | (0 != (plugin->options & HTTP_OPTIONS_TCP_STEALTH))) | ||
2318 | { | ||
2319 | const union MHD_DaemonInfo *di; | ||
2320 | |||
2321 | di = MHD_get_daemon_info (server, | ||
2322 | MHD_DAEMON_INFO_LISTEN_FD, | ||
2323 | NULL); | ||
2324 | if ((0 != setsockopt ((int) di->listen_fd, | ||
2325 | IPPROTO_TCP, | ||
2326 | TCP_STEALTH, | ||
2327 | plugin->env->my_identity, | ||
2328 | sizeof(struct GNUNET_PeerIdentity)))) | ||
2329 | { | ||
2330 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2331 | _ ("TCP_STEALTH not supported on this platform.\n")); | ||
2332 | MHD_stop_daemon (server); | ||
2333 | server = NULL; | ||
2334 | } | ||
2335 | } | ||
2336 | #endif | ||
2337 | return server; | ||
2338 | } | ||
2339 | |||
2340 | |||
2341 | /** | ||
2342 | * Start the HTTP server | ||
2343 | * | ||
2344 | * @param plugin the plugin handle | ||
2345 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
2346 | */ | ||
2347 | static int | ||
2348 | server_start (struct HTTP_Server_Plugin *plugin) | ||
2349 | { | ||
2350 | const char *msg; | ||
2351 | |||
2352 | GNUNET_assert (NULL != plugin); | ||
2353 | #if BUILD_HTTPS | ||
2354 | if (GNUNET_SYSERR == server_load_certificate (plugin)) | ||
2355 | { | ||
2356 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2357 | _ ( | ||
2358 | "Could not load or create server certificate! Loading plugin failed!\n")); | ||
2359 | return GNUNET_SYSERR; | ||
2360 | } | ||
2361 | #endif | ||
2362 | |||
2363 | |||
2364 | plugin->server_v4 = NULL; | ||
2365 | if (GNUNET_YES == plugin->use_ipv4) | ||
2366 | { | ||
2367 | plugin->server_v4 | ||
2368 | = run_mhd_start_daemon (plugin, | ||
2369 | (const struct | ||
2370 | sockaddr_in *) plugin->server_addr_v4, | ||
2371 | MHD_NO_FLAG); | ||
2372 | |||
2373 | if (NULL == plugin->server_v4) | ||
2374 | { | ||
2375 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2376 | "Failed to start %s IPv4 server component on port %u\n", | ||
2377 | plugin->name, | ||
2378 | plugin->port); | ||
2379 | } | ||
2380 | else | ||
2381 | server_reschedule (plugin, | ||
2382 | plugin->server_v4, | ||
2383 | GNUNET_NO); | ||
2384 | } | ||
2385 | |||
2386 | |||
2387 | plugin->server_v6 = NULL; | ||
2388 | if (GNUNET_YES == plugin->use_ipv6) | ||
2389 | { | ||
2390 | plugin->server_v6 | ||
2391 | = run_mhd_start_daemon (plugin, | ||
2392 | (const struct | ||
2393 | sockaddr_in *) plugin->server_addr_v6, | ||
2394 | MHD_USE_IPv6); | ||
2395 | if (NULL == plugin->server_v6) | ||
2396 | { | ||
2397 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2398 | "Failed to start %s IPv6 server component on port %u\n", | ||
2399 | plugin->name, | ||
2400 | plugin->port); | ||
2401 | } | ||
2402 | else | ||
2403 | { | ||
2404 | server_reschedule (plugin, | ||
2405 | plugin->server_v6, | ||
2406 | GNUNET_NO); | ||
2407 | } | ||
2408 | } | ||
2409 | msg = "No"; | ||
2410 | if ((NULL == plugin->server_v6) && | ||
2411 | (NULL == plugin->server_v4)) | ||
2412 | { | ||
2413 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2414 | "%s %s server component started on port %u\n", | ||
2415 | msg, | ||
2416 | plugin->name, | ||
2417 | plugin->port); | ||
2418 | return GNUNET_SYSERR; | ||
2419 | } | ||
2420 | if ((NULL != plugin->server_v6) && | ||
2421 | (NULL != plugin->server_v4)) | ||
2422 | msg = "IPv4 and IPv6"; | ||
2423 | else if (NULL != plugin->server_v6) | ||
2424 | msg = "IPv6"; | ||
2425 | else if (NULL != plugin->server_v4) | ||
2426 | msg = "IPv4"; | ||
2427 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2428 | "%s %s server component started on port %u\n", | ||
2429 | msg, | ||
2430 | plugin->name, | ||
2431 | plugin->port); | ||
2432 | return GNUNET_OK; | ||
2433 | } | ||
2434 | |||
2435 | |||
2436 | /** | ||
2437 | * Add an address to the server's set of addresses and notify transport | ||
2438 | * | ||
2439 | * @param cls the plugin handle | ||
2440 | * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove | ||
2441 | * @param addr the address | ||
2442 | * @param addrlen address length | ||
2443 | */ | ||
2444 | static void | ||
2445 | server_add_address (void *cls, | ||
2446 | int add_remove, | ||
2447 | const struct sockaddr *addr, | ||
2448 | socklen_t addrlen) | ||
2449 | { | ||
2450 | struct HTTP_Server_Plugin *plugin = cls; | ||
2451 | struct GNUNET_HELLO_Address *address; | ||
2452 | struct HttpAddressWrapper *w = NULL; | ||
2453 | |||
2454 | w = GNUNET_new (struct HttpAddressWrapper); | ||
2455 | w->address = http_common_address_from_socket (plugin->protocol, | ||
2456 | addr, | ||
2457 | addrlen); | ||
2458 | if (NULL == w->address) | ||
2459 | { | ||
2460 | GNUNET_free (w); | ||
2461 | return; | ||
2462 | } | ||
2463 | w->addrlen = http_common_address_get_size (w->address); | ||
2464 | |||
2465 | GNUNET_CONTAINER_DLL_insert (plugin->addr_head, | ||
2466 | plugin->addr_tail, | ||
2467 | w); | ||
2468 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2469 | "Notifying transport to add address `%s'\n", | ||
2470 | http_common_plugin_address_to_string (plugin->protocol, | ||
2471 | w->address, | ||
2472 | w->addrlen)); | ||
2473 | /* modify our published address list */ | ||
2474 | #if BUILD_HTTPS | ||
2475 | address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, | ||
2476 | "https_client", w->address, | ||
2477 | w->addrlen, | ||
2478 | GNUNET_HELLO_ADDRESS_INFO_NONE); | ||
2479 | #else | ||
2480 | address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, | ||
2481 | "http_client", w->address, | ||
2482 | w->addrlen, | ||
2483 | GNUNET_HELLO_ADDRESS_INFO_NONE); | ||
2484 | #endif | ||
2485 | |||
2486 | plugin->env->notify_address (plugin->env->cls, | ||
2487 | add_remove, | ||
2488 | address); | ||
2489 | GNUNET_HELLO_address_free (address); | ||
2490 | } | ||
2491 | |||
2492 | |||
2493 | /** | ||
2494 | * Remove an address from the server's set of addresses and notify transport | ||
2495 | * | ||
2496 | * @param cls the plugin handle | ||
2497 | * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove | ||
2498 | * @param addr the address | ||
2499 | * @param addrlen address length | ||
2500 | */ | ||
2501 | static void | ||
2502 | server_remove_address (void *cls, | ||
2503 | int add_remove, | ||
2504 | const struct sockaddr *addr, | ||
2505 | socklen_t addrlen) | ||
2506 | { | ||
2507 | struct HTTP_Server_Plugin *plugin = cls; | ||
2508 | struct GNUNET_HELLO_Address *address; | ||
2509 | struct HttpAddressWrapper *w = plugin->addr_head; | ||
2510 | size_t saddr_len; | ||
2511 | void *saddr; | ||
2512 | |||
2513 | saddr = http_common_address_from_socket (plugin->protocol, | ||
2514 | addr, | ||
2515 | addrlen); | ||
2516 | if (NULL == saddr) | ||
2517 | return; | ||
2518 | saddr_len = http_common_address_get_size (saddr); | ||
2519 | |||
2520 | while (NULL != w) | ||
2521 | { | ||
2522 | if (GNUNET_YES == | ||
2523 | http_common_cmp_addresses (w->address, | ||
2524 | w->addrlen, | ||
2525 | saddr, | ||
2526 | saddr_len)) | ||
2527 | break; | ||
2528 | w = w->next; | ||
2529 | } | ||
2530 | GNUNET_free (saddr); | ||
2531 | |||
2532 | if (NULL == w) | ||
2533 | return; | ||
2534 | |||
2535 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2536 | "Notifying transport to remove address `%s'\n", | ||
2537 | http_common_plugin_address_to_string (plugin->protocol, | ||
2538 | w->address, | ||
2539 | w->addrlen)); | ||
2540 | GNUNET_CONTAINER_DLL_remove (plugin->addr_head, | ||
2541 | plugin->addr_tail, | ||
2542 | w); | ||
2543 | /* modify our published address list */ | ||
2544 | #if BUILD_HTTPS | ||
2545 | address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, | ||
2546 | "https_client", w->address, | ||
2547 | w->addrlen, | ||
2548 | GNUNET_HELLO_ADDRESS_INFO_NONE); | ||
2549 | #else | ||
2550 | address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, | ||
2551 | "http_client", w->address, | ||
2552 | w->addrlen, | ||
2553 | GNUNET_HELLO_ADDRESS_INFO_NONE); | ||
2554 | #endif | ||
2555 | plugin->env->notify_address (plugin->env->cls, add_remove, address); | ||
2556 | GNUNET_HELLO_address_free (address); | ||
2557 | GNUNET_free (w->address); | ||
2558 | GNUNET_free (w); | ||
2559 | } | ||
2560 | |||
2561 | |||
2562 | /** | ||
2563 | * Our external IP address/port mapping has changed. | ||
2564 | * | ||
2565 | * @param cls closure, the 'struct LocalAddrList' | ||
2566 | * @param app_ctx[in,out] location where the app can store stuff | ||
2567 | * on add and retrieve it on remove | ||
2568 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
2569 | * the previous (now invalid) one | ||
2570 | * @param ac address class the address belongs to | ||
2571 | * @param addr either the previous or the new public IP address | ||
2572 | * @param addrlen actual length of the address | ||
2573 | */ | ||
2574 | static void | ||
2575 | server_nat_port_map_callback (void *cls, | ||
2576 | void **app_ctx, | ||
2577 | int add_remove, | ||
2578 | enum GNUNET_NAT_AddressClass ac, | ||
2579 | const struct sockaddr *addr, | ||
2580 | socklen_t addrlen) | ||
2581 | { | ||
2582 | struct HTTP_Server_Plugin *plugin = cls; | ||
2583 | |||
2584 | (void) app_ctx; | ||
2585 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2586 | "NAT called to %s address `%s'\n", | ||
2587 | (add_remove == GNUNET_NO) ? "remove" : "add", | ||
2588 | GNUNET_a2s (addr, addrlen)); | ||
2589 | |||
2590 | if (AF_INET == addr->sa_family) | ||
2591 | { | ||
2592 | struct sockaddr_in *s4 = (struct sockaddr_in *) addr; | ||
2593 | |||
2594 | if (GNUNET_NO == plugin->use_ipv4) | ||
2595 | return; | ||
2596 | |||
2597 | if ((NULL != plugin->server_addr_v4) && | ||
2598 | (0 != memcmp (&plugin->server_addr_v4->sin_addr, | ||
2599 | &s4->sin_addr, | ||
2600 | sizeof(struct in_addr)))) | ||
2601 | { | ||
2602 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2603 | "Skipping address `%s' (not bindto address)\n", | ||
2604 | GNUNET_a2s (addr, addrlen)); | ||
2605 | return; | ||
2606 | } | ||
2607 | } | ||
2608 | |||
2609 | if (AF_INET6 == addr->sa_family) | ||
2610 | { | ||
2611 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) addr; | ||
2612 | if (GNUNET_NO == plugin->use_ipv6) | ||
2613 | return; | ||
2614 | |||
2615 | if ((NULL != plugin->server_addr_v6) && | ||
2616 | (0 != memcmp (&plugin->server_addr_v6->sin6_addr, | ||
2617 | &s6->sin6_addr, sizeof(struct in6_addr)))) | ||
2618 | { | ||
2619 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2620 | "Skipping address `%s' (not bindto address)\n", | ||
2621 | GNUNET_a2s (addr, addrlen)); | ||
2622 | return; | ||
2623 | } | ||
2624 | } | ||
2625 | |||
2626 | switch (add_remove) | ||
2627 | { | ||
2628 | case GNUNET_YES: | ||
2629 | server_add_address (cls, add_remove, addr, addrlen); | ||
2630 | break; | ||
2631 | |||
2632 | case GNUNET_NO: | ||
2633 | server_remove_address (cls, add_remove, addr, addrlen); | ||
2634 | break; | ||
2635 | } | ||
2636 | } | ||
2637 | |||
2638 | |||
2639 | /** | ||
2640 | * Get valid server addresses | ||
2641 | * | ||
2642 | * @param plugin the plugin handle | ||
2643 | * @param service_name the servicename | ||
2644 | * @param cfg configuration handle | ||
2645 | * @param addrs addresses | ||
2646 | * @param addr_lens address length | ||
2647 | * @return number of addresses | ||
2648 | */ | ||
2649 | static int | ||
2650 | server_get_addresses (struct HTTP_Server_Plugin *plugin, | ||
2651 | const char *service_name, | ||
2652 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
2653 | struct sockaddr ***addrs, | ||
2654 | socklen_t **addr_lens) | ||
2655 | { | ||
2656 | int disablev6; | ||
2657 | unsigned long long port; | ||
2658 | struct addrinfo hints; | ||
2659 | struct addrinfo *res; | ||
2660 | struct addrinfo *pos; | ||
2661 | struct addrinfo *next; | ||
2662 | unsigned int i; | ||
2663 | int resi; | ||
2664 | int ret; | ||
2665 | struct sockaddr **saddrs; | ||
2666 | socklen_t *saddrlens; | ||
2667 | char *hostname; | ||
2668 | |||
2669 | *addrs = NULL; | ||
2670 | *addr_lens = NULL; | ||
2671 | |||
2672 | disablev6 = ! plugin->use_ipv6; | ||
2673 | |||
2674 | port = 0; | ||
2675 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) | ||
2676 | { | ||
2677 | GNUNET_break (GNUNET_OK == | ||
2678 | GNUNET_CONFIGURATION_get_value_number (cfg, service_name, | ||
2679 | "PORT", &port)); | ||
2680 | if (port > 65535) | ||
2681 | { | ||
2682 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2683 | _ ( | ||
2684 | "Require valid port number for service in configuration!\n")); | ||
2685 | return GNUNET_SYSERR; | ||
2686 | } | ||
2687 | } | ||
2688 | if (0 == port) | ||
2689 | { | ||
2690 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2691 | "Starting in listen only mode\n"); | ||
2692 | return -1; /* listen only */ | ||
2693 | } | ||
2694 | |||
2695 | |||
2696 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, | ||
2697 | "BINDTO")) | ||
2698 | { | ||
2699 | GNUNET_break (GNUNET_OK == | ||
2700 | GNUNET_CONFIGURATION_get_value_string (cfg, service_name, | ||
2701 | "BINDTO", &hostname)); | ||
2702 | } | ||
2703 | else | ||
2704 | hostname = NULL; | ||
2705 | |||
2706 | if (NULL != hostname) | ||
2707 | { | ||
2708 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2709 | "Resolving `%s' since that is where `%s' will bind to.\n", | ||
2710 | hostname, service_name); | ||
2711 | memset (&hints, 0, sizeof(struct addrinfo)); | ||
2712 | if (disablev6) | ||
2713 | hints.ai_family = AF_INET; | ||
2714 | if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || | ||
2715 | (NULL == res)) | ||
2716 | { | ||
2717 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2718 | _ ("Failed to resolve `%s': %s\n"), | ||
2719 | hostname, | ||
2720 | gai_strerror (ret)); | ||
2721 | GNUNET_free (hostname); | ||
2722 | return GNUNET_SYSERR; | ||
2723 | } | ||
2724 | next = res; | ||
2725 | i = 0; | ||
2726 | while (NULL != (pos = next)) | ||
2727 | { | ||
2728 | next = pos->ai_next; | ||
2729 | if ((disablev6) && (pos->ai_family == AF_INET6)) | ||
2730 | continue; | ||
2731 | i++; | ||
2732 | } | ||
2733 | if (0 == i) | ||
2734 | { | ||
2735 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2736 | _ ("Failed to find %saddress for `%s'.\n"), | ||
2737 | disablev6 ? "IPv4 " : "", hostname); | ||
2738 | freeaddrinfo (res); | ||
2739 | GNUNET_free (hostname); | ||
2740 | return GNUNET_SYSERR; | ||
2741 | } | ||
2742 | resi = i; | ||
2743 | saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *)); | ||
2744 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t)); | ||
2745 | i = 0; | ||
2746 | next = res; | ||
2747 | while (NULL != (pos = next)) | ||
2748 | { | ||
2749 | next = pos->ai_next; | ||
2750 | if ((disablev6) && (pos->ai_family == AF_INET6)) | ||
2751 | continue; | ||
2752 | if ((pos->ai_protocol != IPPROTO_TCP) && (0 != pos->ai_protocol)) | ||
2753 | continue; /* not TCP */ | ||
2754 | if ((pos->ai_socktype != SOCK_STREAM) && (0 != pos->ai_socktype)) | ||
2755 | continue; /* huh? */ | ||
2756 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2757 | "Service will bind to `%s'\n", | ||
2758 | GNUNET_a2s (pos->ai_addr, | ||
2759 | pos->ai_addrlen)); | ||
2760 | if (pos->ai_family == AF_INET) | ||
2761 | { | ||
2762 | GNUNET_assert (pos->ai_addrlen == sizeof(struct sockaddr_in)); | ||
2763 | saddrlens[i] = pos->ai_addrlen; | ||
2764 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
2765 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | ||
2766 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
2767 | } | ||
2768 | else | ||
2769 | { | ||
2770 | GNUNET_assert (pos->ai_family == AF_INET6); | ||
2771 | GNUNET_assert (pos->ai_addrlen == sizeof(struct sockaddr_in6)); | ||
2772 | saddrlens[i] = pos->ai_addrlen; | ||
2773 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
2774 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | ||
2775 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
2776 | } | ||
2777 | i++; | ||
2778 | } | ||
2779 | GNUNET_free (hostname); | ||
2780 | freeaddrinfo (res); | ||
2781 | resi = i; | ||
2782 | } | ||
2783 | else | ||
2784 | { | ||
2785 | /* will bind against everything, just set port */ | ||
2786 | if (disablev6) | ||
2787 | { | ||
2788 | /* V4-only */ | ||
2789 | resi = 1; | ||
2790 | i = 0; | ||
2791 | saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *)); | ||
2792 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t)); | ||
2793 | |||
2794 | saddrlens[i] = sizeof(struct sockaddr_in); | ||
2795 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
2796 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
2797 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; | ||
2798 | #endif | ||
2799 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
2800 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
2801 | } | ||
2802 | else | ||
2803 | { | ||
2804 | /* dual stack */ | ||
2805 | resi = 2; | ||
2806 | saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *)); | ||
2807 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t)); | ||
2808 | i = 0; | ||
2809 | saddrlens[i] = sizeof(struct sockaddr_in6); | ||
2810 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
2811 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
2812 | ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; | ||
2813 | #endif | ||
2814 | ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; | ||
2815 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
2816 | i++; | ||
2817 | saddrlens[i] = sizeof(struct sockaddr_in); | ||
2818 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
2819 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
2820 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; | ||
2821 | #endif | ||
2822 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
2823 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
2824 | } | ||
2825 | } | ||
2826 | *addrs = saddrs; | ||
2827 | *addr_lens = saddrlens; | ||
2828 | return resi; | ||
2829 | } | ||
2830 | |||
2831 | |||
2832 | /** | ||
2833 | * Ask NAT for addresses | ||
2834 | * | ||
2835 | * @param plugin the plugin handle | ||
2836 | */ | ||
2837 | static void | ||
2838 | server_start_report_addresses (struct HTTP_Server_Plugin *plugin) | ||
2839 | { | ||
2840 | int res = GNUNET_OK; | ||
2841 | struct sockaddr **addrs; | ||
2842 | socklen_t *addrlens; | ||
2843 | |||
2844 | res = server_get_addresses (plugin, | ||
2845 | plugin->name, | ||
2846 | plugin->env->cfg, | ||
2847 | &addrs, &addrlens); | ||
2848 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2849 | _ ("Found %u addresses to report to NAT service\n"), | ||
2850 | res); | ||
2851 | |||
2852 | if (GNUNET_SYSERR == res) | ||
2853 | { | ||
2854 | plugin->nat = NULL; | ||
2855 | return; | ||
2856 | } | ||
2857 | |||
2858 | plugin->nat | ||
2859 | = GNUNET_NAT_register (plugin->env->cfg, | ||
2860 | plugin->name, | ||
2861 | IPPROTO_TCP, | ||
2862 | (unsigned int) res, | ||
2863 | (const struct sockaddr **) addrs, | ||
2864 | addrlens, | ||
2865 | &server_nat_port_map_callback, | ||
2866 | NULL, | ||
2867 | plugin); | ||
2868 | while (res > 0) | ||
2869 | { | ||
2870 | res--; | ||
2871 | GNUNET_assert (NULL != addrs[res]); | ||
2872 | GNUNET_free (addrs[res]); | ||
2873 | } | ||
2874 | GNUNET_free (addrs); | ||
2875 | GNUNET_free (addrlens); | ||
2876 | } | ||
2877 | |||
2878 | |||
2879 | /** | ||
2880 | * Stop NAT for addresses | ||
2881 | * | ||
2882 | * @param plugin the plugin handle | ||
2883 | */ | ||
2884 | static void | ||
2885 | server_stop_report_addresses (struct HTTP_Server_Plugin *plugin) | ||
2886 | { | ||
2887 | struct HttpAddressWrapper *w; | ||
2888 | |||
2889 | /* Stop NAT handle */ | ||
2890 | if (NULL != plugin->nat) | ||
2891 | { | ||
2892 | GNUNET_NAT_unregister (plugin->nat); | ||
2893 | plugin->nat = NULL; | ||
2894 | } | ||
2895 | /* Clean up addresses */ | ||
2896 | while (NULL != plugin->addr_head) | ||
2897 | { | ||
2898 | w = plugin->addr_head; | ||
2899 | GNUNET_CONTAINER_DLL_remove (plugin->addr_head, | ||
2900 | plugin->addr_tail, | ||
2901 | w); | ||
2902 | GNUNET_free (w->address); | ||
2903 | GNUNET_free (w); | ||
2904 | } | ||
2905 | } | ||
2906 | |||
2907 | |||
2908 | /** | ||
2909 | * Check if IPv6 supported on this system | ||
2910 | * | ||
2911 | * @param plugin the plugin handle | ||
2912 | * @return #GNUNET_YES on success, else #GNUNET_NO | ||
2913 | */ | ||
2914 | static int | ||
2915 | server_check_ipv6_support (struct HTTP_Server_Plugin *plugin) | ||
2916 | { | ||
2917 | struct GNUNET_NETWORK_Handle *desc = NULL; | ||
2918 | int res = GNUNET_NO; | ||
2919 | |||
2920 | /* Probe IPv6 support */ | ||
2921 | desc = GNUNET_NETWORK_socket_create (PF_INET6, | ||
2922 | SOCK_STREAM, | ||
2923 | 0); | ||
2924 | if (NULL == desc) | ||
2925 | { | ||
2926 | if ((errno == ENOBUFS) || | ||
2927 | (errno == ENOMEM) || | ||
2928 | (errno == ENFILE) || | ||
2929 | (errno == EACCES)) | ||
2930 | { | ||
2931 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
2932 | "socket"); | ||
2933 | } | ||
2934 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2935 | _ ("Disabling IPv6 since it is not supported on this system!\n")); | ||
2936 | res = GNUNET_NO; | ||
2937 | } | ||
2938 | else | ||
2939 | { | ||
2940 | GNUNET_break (GNUNET_OK == | ||
2941 | GNUNET_NETWORK_socket_close (desc)); | ||
2942 | desc = NULL; | ||
2943 | res = GNUNET_YES; | ||
2944 | } | ||
2945 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2946 | "Testing IPv6 on this system: %s\n", | ||
2947 | (res == GNUNET_YES) ? "successful" : "failed"); | ||
2948 | return res; | ||
2949 | } | ||
2950 | |||
2951 | |||
2952 | /** | ||
2953 | * Notify server about our external hostname | ||
2954 | * | ||
2955 | * @param cls plugin | ||
2956 | */ | ||
2957 | static void | ||
2958 | server_notify_external_hostname (void *cls) | ||
2959 | { | ||
2960 | struct HTTP_Server_Plugin *plugin = cls; | ||
2961 | struct HttpAddress *ext_addr; | ||
2962 | size_t ext_addr_len; | ||
2963 | unsigned int urlen; | ||
2964 | char *url; | ||
2965 | |||
2966 | plugin->notify_ext_task = NULL; | ||
2967 | GNUNET_asprintf (&url, | ||
2968 | "%s://%s", | ||
2969 | plugin->protocol, | ||
2970 | plugin->external_hostname); | ||
2971 | urlen = strlen (url) + 1; | ||
2972 | ext_addr = GNUNET_malloc (sizeof(struct HttpAddress) + urlen); | ||
2973 | ext_addr->options = htonl (plugin->options); | ||
2974 | ext_addr->urlen = htonl (urlen); | ||
2975 | ext_addr_len = sizeof(struct HttpAddress) + urlen; | ||
2976 | GNUNET_memcpy (&ext_addr[1], url, urlen); | ||
2977 | GNUNET_free (url); | ||
2978 | |||
2979 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2980 | "Notifying transport about external hostname address `%s'\n", | ||
2981 | plugin->external_hostname); | ||
2982 | |||
2983 | #if BUILD_HTTPS | ||
2984 | if (GNUNET_YES == plugin->verify_external_hostname) | ||
2985 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2986 | "Enabling SSL verification for external hostname address `%s'\n", | ||
2987 | plugin->external_hostname); | ||
2988 | plugin->ext_addr | ||
2989 | = GNUNET_HELLO_address_allocate (plugin->env->my_identity, | ||
2990 | "https_client", | ||
2991 | ext_addr, | ||
2992 | ext_addr_len, | ||
2993 | GNUNET_HELLO_ADDRESS_INFO_NONE); | ||
2994 | plugin->env->notify_address (plugin->env->cls, | ||
2995 | GNUNET_YES, | ||
2996 | plugin->ext_addr); | ||
2997 | GNUNET_free (ext_addr); | ||
2998 | #else | ||
2999 | plugin->ext_addr | ||
3000 | = GNUNET_HELLO_address_allocate (plugin->env->my_identity, | ||
3001 | "http_client", | ||
3002 | ext_addr, | ||
3003 | ext_addr_len, | ||
3004 | GNUNET_HELLO_ADDRESS_INFO_NONE); | ||
3005 | plugin->env->notify_address (plugin->env->cls, | ||
3006 | GNUNET_YES, | ||
3007 | plugin->ext_addr); | ||
3008 | GNUNET_free (ext_addr); | ||
3009 | #endif | ||
3010 | } | ||
3011 | |||
3012 | |||
3013 | /** | ||
3014 | * Configure the plugin | ||
3015 | * | ||
3016 | * @param plugin plugin handle | ||
3017 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
3018 | */ | ||
3019 | static int | ||
3020 | server_configure_plugin (struct HTTP_Server_Plugin *plugin) | ||
3021 | { | ||
3022 | unsigned long long port; | ||
3023 | unsigned long long max_connections; | ||
3024 | char *bind4_address = NULL; | ||
3025 | char *bind6_address = NULL; | ||
3026 | char *eh_tmp = NULL; | ||
3027 | int external_hostname_use_port; | ||
3028 | |||
3029 | /* Use IPv4? */ | ||
3030 | if (GNUNET_CONFIGURATION_have_value | ||
3031 | (plugin->env->cfg, plugin->name, "USE_IPv4")) | ||
3032 | { | ||
3033 | plugin->use_ipv4 = | ||
3034 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, | ||
3035 | plugin->name, | ||
3036 | "USE_IPv4"); | ||
3037 | } | ||
3038 | else | ||
3039 | plugin->use_ipv4 = GNUNET_YES; | ||
3040 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3041 | _ ("IPv4 support is %s\n"), | ||
3042 | (plugin->use_ipv4 == GNUNET_YES) ? "enabled" : "disabled"); | ||
3043 | |||
3044 | /* Use IPv6? */ | ||
3045 | if (GNUNET_CONFIGURATION_have_value | ||
3046 | (plugin->env->cfg, plugin->name, "USE_IPv6")) | ||
3047 | { | ||
3048 | plugin->use_ipv6 = | ||
3049 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, | ||
3050 | plugin->name, | ||
3051 | "USE_IPv6"); | ||
3052 | } | ||
3053 | else | ||
3054 | plugin->use_ipv6 = GNUNET_YES; | ||
3055 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3056 | _ ("IPv6 support is %s\n"), | ||
3057 | (plugin->use_ipv6 == GNUNET_YES) ? "enabled" : "disabled"); | ||
3058 | |||
3059 | if ((plugin->use_ipv4 == GNUNET_NO) && (plugin->use_ipv6 == GNUNET_NO)) | ||
3060 | { | ||
3061 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3062 | _ ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n")); | ||
3063 | return GNUNET_SYSERR; | ||
3064 | } | ||
3065 | |||
3066 | /* Reading port number from config file */ | ||
3067 | if ((GNUNET_OK != | ||
3068 | GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, | ||
3069 | plugin->name, | ||
3070 | "PORT", &port)) || (port > 65535)) | ||
3071 | { | ||
3072 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3073 | _ ("Port is required! Fix in configuration\n")); | ||
3074 | return GNUNET_SYSERR; | ||
3075 | } | ||
3076 | plugin->port = port; | ||
3077 | |||
3078 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
3079 | _ ("Using port %u\n"), plugin->port); | ||
3080 | |||
3081 | if ((plugin->use_ipv4 == GNUNET_YES) && | ||
3082 | (GNUNET_YES == | ||
3083 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, | ||
3084 | plugin->name, | ||
3085 | "BINDTO", | ||
3086 | &bind4_address))) | ||
3087 | { | ||
3088 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3089 | "Binding %s plugin to specific IPv4 address: `%s'\n", | ||
3090 | plugin->protocol, | ||
3091 | bind4_address); | ||
3092 | plugin->server_addr_v4 = GNUNET_new (struct sockaddr_in); | ||
3093 | if (1 != inet_pton (AF_INET, | ||
3094 | bind4_address, | ||
3095 | &plugin->server_addr_v4->sin_addr)) | ||
3096 | { | ||
3097 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3098 | _ ("Specific IPv4 address `%s' in configuration file is invalid!\n"), | ||
3099 | bind4_address); | ||
3100 | GNUNET_free (bind4_address); | ||
3101 | GNUNET_free (plugin->server_addr_v4); | ||
3102 | plugin->server_addr_v4 = NULL; | ||
3103 | return GNUNET_SYSERR; | ||
3104 | } | ||
3105 | else | ||
3106 | { | ||
3107 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3108 | "Binding to IPv4 address %s\n", | ||
3109 | bind4_address); | ||
3110 | plugin->server_addr_v4->sin_family = AF_INET; | ||
3111 | plugin->server_addr_v4->sin_port = htons (plugin->port); | ||
3112 | } | ||
3113 | GNUNET_free (bind4_address); | ||
3114 | } | ||
3115 | |||
3116 | if ((plugin->use_ipv6 == GNUNET_YES) && | ||
3117 | (GNUNET_YES == | ||
3118 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, | ||
3119 | plugin->name, | ||
3120 | "BINDTO6", | ||
3121 | &bind6_address))) | ||
3122 | { | ||
3123 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3124 | "Binding %s plugin to specific IPv6 address: `%s'\n", | ||
3125 | plugin->protocol, bind6_address); | ||
3126 | plugin->server_addr_v6 = GNUNET_new (struct sockaddr_in6); | ||
3127 | if (1 != | ||
3128 | inet_pton (AF_INET6, | ||
3129 | bind6_address, | ||
3130 | &plugin->server_addr_v6->sin6_addr)) | ||
3131 | { | ||
3132 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3133 | _ ("Specific IPv6 address `%s' in configuration file is invalid!\n"), | ||
3134 | bind6_address); | ||
3135 | GNUNET_free (bind6_address); | ||
3136 | GNUNET_free (plugin->server_addr_v6); | ||
3137 | plugin->server_addr_v6 = NULL; | ||
3138 | return GNUNET_SYSERR; | ||
3139 | } | ||
3140 | else | ||
3141 | { | ||
3142 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3143 | "Binding to IPv6 address %s\n", | ||
3144 | bind6_address); | ||
3145 | plugin->server_addr_v6->sin6_family = AF_INET6; | ||
3146 | plugin->server_addr_v6->sin6_port = htons (plugin->port); | ||
3147 | } | ||
3148 | GNUNET_free (bind6_address); | ||
3149 | } | ||
3150 | |||
3151 | plugin->verify_external_hostname = GNUNET_NO; | ||
3152 | #if BUILD_HTTPS | ||
3153 | plugin->verify_external_hostname | ||
3154 | = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, | ||
3155 | plugin->name, | ||
3156 | "VERIFY_EXTERNAL_HOSTNAME"); | ||
3157 | if (GNUNET_SYSERR == plugin->verify_external_hostname) | ||
3158 | plugin->verify_external_hostname = GNUNET_NO; | ||
3159 | if (GNUNET_YES == plugin->verify_external_hostname) | ||
3160 | plugin->options |= HTTP_OPTIONS_VERIFY_CERTIFICATE; | ||
3161 | #endif | ||
3162 | external_hostname_use_port | ||
3163 | = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, | ||
3164 | plugin->name, | ||
3165 | "EXTERNAL_HOSTNAME_USE_PORT"); | ||
3166 | if (GNUNET_SYSERR == external_hostname_use_port) | ||
3167 | external_hostname_use_port = GNUNET_NO; | ||
3168 | |||
3169 | |||
3170 | if (GNUNET_YES == | ||
3171 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, | ||
3172 | plugin->name, | ||
3173 | "EXTERNAL_HOSTNAME", | ||
3174 | &eh_tmp)) | ||
3175 | { | ||
3176 | char *tmp; | ||
3177 | char *pos = NULL; | ||
3178 | char *pos_url = NULL; | ||
3179 | |||
3180 | if (NULL != strstr (eh_tmp, "://")) | ||
3181 | tmp = &strstr (eh_tmp, "://")[3]; | ||
3182 | else | ||
3183 | tmp = eh_tmp; | ||
3184 | |||
3185 | if (GNUNET_YES == external_hostname_use_port) | ||
3186 | { | ||
3187 | if ((strlen (tmp) > 1) && (NULL != (pos = strchr (tmp, '/')))) | ||
3188 | { | ||
3189 | pos_url = pos + 1; | ||
3190 | pos[0] = '\0'; | ||
3191 | GNUNET_asprintf (&plugin->external_hostname, | ||
3192 | "%s:%u/%s", | ||
3193 | tmp, | ||
3194 | (uint16_t) port, | ||
3195 | pos_url); | ||
3196 | } | ||
3197 | else | ||
3198 | GNUNET_asprintf (&plugin->external_hostname, | ||
3199 | "%s:%u", | ||
3200 | tmp, | ||
3201 | (uint16_t) port); | ||
3202 | } | ||
3203 | else | ||
3204 | plugin->external_hostname = GNUNET_strdup (tmp); | ||
3205 | GNUNET_free (eh_tmp); | ||
3206 | |||
3207 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
3208 | _ ("Using external hostname `%s'\n"), | ||
3209 | plugin->external_hostname); | ||
3210 | plugin->notify_ext_task = GNUNET_SCHEDULER_add_now ( | ||
3211 | &server_notify_external_hostname, | ||
3212 | plugin); | ||
3213 | |||
3214 | /* Use only configured external hostname */ | ||
3215 | if (GNUNET_CONFIGURATION_have_value | ||
3216 | (plugin->env->cfg, | ||
3217 | plugin->name, | ||
3218 | "EXTERNAL_HOSTNAME_ONLY")) | ||
3219 | { | ||
3220 | plugin->external_only = | ||
3221 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, | ||
3222 | plugin->name, | ||
3223 | "EXTERNAL_HOSTNAME_ONLY"); | ||
3224 | } | ||
3225 | else | ||
3226 | plugin->external_only = GNUNET_NO; | ||
3227 | |||
3228 | if (GNUNET_YES == plugin->external_only) | ||
3229 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3230 | _ ("Notifying transport only about hostname `%s'\n"), | ||
3231 | plugin->external_hostname); | ||
3232 | } | ||
3233 | else | ||
3234 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3235 | "No external hostname configured\n"); | ||
3236 | |||
3237 | /* Optional parameters */ | ||
3238 | if (GNUNET_OK != | ||
3239 | GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, | ||
3240 | plugin->name, | ||
3241 | "MAX_CONNECTIONS", | ||
3242 | &max_connections)) | ||
3243 | max_connections = 128; | ||
3244 | plugin->max_request = max_connections; | ||
3245 | |||
3246 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3247 | _ ("Maximum number of connections is %u\n"), | ||
3248 | plugin->max_request); | ||
3249 | |||
3250 | plugin->peer_id_length = strlen (GNUNET_i2s_full (plugin->env->my_identity)); | ||
3251 | |||
3252 | return GNUNET_OK; | ||
3253 | } | ||
3254 | |||
3255 | |||
3256 | /** | ||
3257 | * Exit point from the plugin. | ||
3258 | * | ||
3259 | * @param cls api | ||
3260 | * @return NULL | ||
3261 | */ | ||
3262 | void * | ||
3263 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) | ||
3264 | { | ||
3265 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | ||
3266 | struct HTTP_Server_Plugin *plugin = api->cls; | ||
3267 | |||
3268 | if (NULL == api->cls) | ||
3269 | { | ||
3270 | /* Free for stub mode */ | ||
3271 | GNUNET_free (api); | ||
3272 | return NULL; | ||
3273 | } | ||
3274 | plugin->in_shutdown = GNUNET_YES; | ||
3275 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
3276 | _ ("Shutting down plugin `%s'\n"), | ||
3277 | plugin->name); | ||
3278 | |||
3279 | if (NULL != plugin->notify_ext_task) | ||
3280 | { | ||
3281 | GNUNET_SCHEDULER_cancel (plugin->notify_ext_task); | ||
3282 | plugin->notify_ext_task = NULL; | ||
3283 | } | ||
3284 | |||
3285 | if (NULL != plugin->ext_addr) | ||
3286 | { | ||
3287 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3288 | "Notifying transport to remove address `%s'\n", | ||
3289 | http_common_plugin_address_to_string (plugin->protocol, | ||
3290 | plugin->ext_addr->address, | ||
3291 | plugin->ext_addr->address_length)); | ||
3292 | #if BUILD_HTTPS | ||
3293 | plugin->env->notify_address (plugin->env->cls, | ||
3294 | GNUNET_NO, | ||
3295 | plugin->ext_addr); | ||
3296 | #else | ||
3297 | plugin->env->notify_address (plugin->env->cls, | ||
3298 | GNUNET_NO, | ||
3299 | plugin->ext_addr); | ||
3300 | #endif | ||
3301 | GNUNET_HELLO_address_free (plugin->ext_addr); | ||
3302 | plugin->ext_addr = NULL; | ||
3303 | } | ||
3304 | |||
3305 | /* Stop to report addresses to transport service */ | ||
3306 | server_stop_report_addresses (plugin); | ||
3307 | if (NULL != plugin->server_v4_task) | ||
3308 | { | ||
3309 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
3310 | plugin->server_v4_task = NULL; | ||
3311 | } | ||
3312 | |||
3313 | if (NULL != plugin->server_v6_task) | ||
3314 | { | ||
3315 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
3316 | plugin->server_v6_task = NULL; | ||
3317 | } | ||
3318 | #if BUILD_HTTPS | ||
3319 | GNUNET_free (plugin->crypto_init); | ||
3320 | GNUNET_free (plugin->cert); | ||
3321 | GNUNET_free (plugin->key); | ||
3322 | #endif | ||
3323 | GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions, | ||
3324 | &destroy_session_shutdown_cb, | ||
3325 | plugin); | ||
3326 | GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions); | ||
3327 | plugin->sessions = NULL; | ||
3328 | if (NULL != plugin->server_v4) | ||
3329 | { | ||
3330 | MHD_stop_daemon (plugin->server_v4); | ||
3331 | plugin->server_v4 = NULL; | ||
3332 | } | ||
3333 | if (NULL != plugin->server_v6) | ||
3334 | { | ||
3335 | MHD_stop_daemon (plugin->server_v6); | ||
3336 | plugin->server_v6 = NULL; | ||
3337 | } | ||
3338 | /* Clean up */ | ||
3339 | GNUNET_free (plugin->external_hostname); | ||
3340 | GNUNET_free (plugin->ext_addr); | ||
3341 | GNUNET_free (plugin->server_addr_v4); | ||
3342 | GNUNET_free (plugin->server_addr_v6); | ||
3343 | regfree (&plugin->url_regex); | ||
3344 | |||
3345 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3346 | _ ("Shutdown for plugin `%s' complete\n"), | ||
3347 | plugin->name); | ||
3348 | |||
3349 | GNUNET_free (plugin); | ||
3350 | GNUNET_free (api); | ||
3351 | return NULL; | ||
3352 | } | ||
3353 | |||
3354 | |||
3355 | /** | ||
3356 | * Function called for a quick conversion of the binary address to | ||
3357 | * a numeric address. Note that the caller must not free the | ||
3358 | * address and that the next call to this function is allowed | ||
3359 | * to override the address again. | ||
3360 | * | ||
3361 | * @param cls unused | ||
3362 | * @param addr binary address | ||
3363 | * @param addrlen length of the address | ||
3364 | * @return string representing the same address | ||
3365 | */ | ||
3366 | static const char * | ||
3367 | http_server_plugin_address_to_string (void *cls, | ||
3368 | const void *addr, | ||
3369 | size_t addrlen) | ||
3370 | { | ||
3371 | return http_common_plugin_address_to_string (PLUGIN_NAME, | ||
3372 | addr, | ||
3373 | addrlen); | ||
3374 | } | ||
3375 | |||
3376 | |||
3377 | /** | ||
3378 | * Function obtain the network type for a session | ||
3379 | * | ||
3380 | * @param cls closure (`struct HTTP_Server_Plugin *`) | ||
3381 | * @param session the session | ||
3382 | * @return the network type in HBO or #GNUNET_SYSERR | ||
3383 | */ | ||
3384 | static enum GNUNET_NetworkType | ||
3385 | http_server_plugin_get_network (void *cls, | ||
3386 | struct GNUNET_ATS_Session *session) | ||
3387 | { | ||
3388 | return session->scope; | ||
3389 | } | ||
3390 | |||
3391 | |||
3392 | /** | ||
3393 | * Function obtain the network type for an address. | ||
3394 | * | ||
3395 | * @param cls closure (`struct Plugin *`) | ||
3396 | * @param address the address | ||
3397 | * @return the network type | ||
3398 | */ | ||
3399 | static enum GNUNET_NetworkType | ||
3400 | http_server_plugin_get_network_for_address (void *cls, | ||
3401 | const struct | ||
3402 | GNUNET_HELLO_Address *address) | ||
3403 | { | ||
3404 | struct HTTP_Server_Plugin *plugin = cls; | ||
3405 | |||
3406 | return http_common_get_network_for_address (plugin->env, | ||
3407 | address); | ||
3408 | } | ||
3409 | |||
3410 | |||
3411 | /** | ||
3412 | * Function that will be called whenever the transport service wants to | ||
3413 | * notify the plugin that the inbound quota changed and that the plugin | ||
3414 | * should update it's delay for the next receive value | ||
3415 | * | ||
3416 | * @param cls closure | ||
3417 | * @param peer which peer was the session for | ||
3418 | * @param session which session is being updated | ||
3419 | * @param delay new delay to use for receiving | ||
3420 | */ | ||
3421 | static void | ||
3422 | http_server_plugin_update_inbound_delay (void *cls, | ||
3423 | const struct GNUNET_PeerIdentity *peer, | ||
3424 | struct GNUNET_ATS_Session *session, | ||
3425 | struct GNUNET_TIME_Relative delay) | ||
3426 | { | ||
3427 | session->next_receive = GNUNET_TIME_relative_to_absolute (delay); | ||
3428 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
3429 | "New inbound delay %s\n", | ||
3430 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
3431 | GNUNET_NO)); | ||
3432 | if (NULL != session->recv_wakeup_task) | ||
3433 | { | ||
3434 | GNUNET_SCHEDULER_cancel (session->recv_wakeup_task); | ||
3435 | session->recv_wakeup_task | ||
3436 | = GNUNET_SCHEDULER_add_delayed (delay, | ||
3437 | &server_wake_up, | ||
3438 | session); | ||
3439 | } | ||
3440 | } | ||
3441 | |||
3442 | |||
3443 | /** | ||
3444 | * Return information about the given session to the | ||
3445 | * monitor callback. | ||
3446 | * | ||
3447 | * @param cls the `struct Plugin` with the monitor callback (`sic`) | ||
3448 | * @param peer peer we send information about | ||
3449 | * @param value our `struct GNUNET_ATS_Session` to send information about | ||
3450 | * @return #GNUNET_OK (continue to iterate) | ||
3451 | */ | ||
3452 | static int | ||
3453 | send_session_info_iter (void *cls, | ||
3454 | const struct GNUNET_PeerIdentity *peer, | ||
3455 | void *value) | ||
3456 | { | ||
3457 | struct HTTP_Server_Plugin *plugin = cls; | ||
3458 | struct GNUNET_ATS_Session *session = value; | ||
3459 | |||
3460 | notify_session_monitor (plugin, | ||
3461 | session, | ||
3462 | GNUNET_TRANSPORT_SS_INIT); | ||
3463 | return GNUNET_OK; | ||
3464 | } | ||
3465 | |||
3466 | |||
3467 | /** | ||
3468 | * Begin monitoring sessions of a plugin. There can only | ||
3469 | * be one active monitor per plugin (i.e. if there are | ||
3470 | * multiple monitors, the transport service needs to | ||
3471 | * multiplex the generated events over all of them). | ||
3472 | * | ||
3473 | * @param cls closure of the plugin | ||
3474 | * @param sic callback to invoke, NULL to disable monitor; | ||
3475 | * plugin will being by iterating over all active | ||
3476 | * sessions immediately and then enter monitor mode | ||
3477 | * @param sic_cls closure for @a sic | ||
3478 | */ | ||
3479 | static void | ||
3480 | http_server_plugin_setup_monitor (void *cls, | ||
3481 | GNUNET_TRANSPORT_SessionInfoCallback sic, | ||
3482 | void *sic_cls) | ||
3483 | { | ||
3484 | struct HTTP_Server_Plugin *plugin = cls; | ||
3485 | |||
3486 | plugin->sic = sic; | ||
3487 | plugin->sic_cls = sic_cls; | ||
3488 | if (NULL != sic) | ||
3489 | { | ||
3490 | GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions, | ||
3491 | &send_session_info_iter, | ||
3492 | plugin); | ||
3493 | /* signal end of first iteration */ | ||
3494 | sic (sic_cls, NULL, NULL); | ||
3495 | } | ||
3496 | } | ||
3497 | |||
3498 | |||
3499 | /** | ||
3500 | * Entry point for the plugin. | ||
3501 | * | ||
3502 | * @param cls env | ||
3503 | * @return api | ||
3504 | */ | ||
3505 | void * | ||
3506 | LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) | ||
3507 | { | ||
3508 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; | ||
3509 | struct GNUNET_TRANSPORT_PluginFunctions *api; | ||
3510 | struct HTTP_Server_Plugin *plugin; | ||
3511 | |||
3512 | if (NULL == env->receive) | ||
3513 | { | ||
3514 | /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully | ||
3515 | initialize the plugin or the API */ | ||
3516 | api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); | ||
3517 | api->cls = NULL; | ||
3518 | api->address_to_string = &http_server_plugin_address_to_string; | ||
3519 | api->string_to_address = &http_common_plugin_string_to_address; | ||
3520 | api->address_pretty_printer = &http_common_plugin_address_pretty_printer; | ||
3521 | return api; | ||
3522 | } | ||
3523 | plugin = GNUNET_new (struct HTTP_Server_Plugin); | ||
3524 | plugin->env = env; | ||
3525 | plugin->sessions = GNUNET_CONTAINER_multipeermap_create (128, | ||
3526 | GNUNET_YES); | ||
3527 | |||
3528 | api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); | ||
3529 | api->cls = plugin; | ||
3530 | api->send = &http_server_plugin_send; | ||
3531 | api->disconnect_peer = &http_server_plugin_disconnect_peer; | ||
3532 | api->disconnect_session = &http_server_plugin_disconnect_session; | ||
3533 | api->query_keepalive_factor = &http_server_query_keepalive_factor; | ||
3534 | api->check_address = &http_server_plugin_address_suggested; | ||
3535 | api->get_session = &http_server_plugin_get_session; | ||
3536 | |||
3537 | api->address_to_string = &http_server_plugin_address_to_string; | ||
3538 | api->string_to_address = &http_common_plugin_string_to_address; | ||
3539 | api->address_pretty_printer = &http_common_plugin_address_pretty_printer; | ||
3540 | api->get_network = &http_server_plugin_get_network; | ||
3541 | api->get_network_for_address = &http_server_plugin_get_network_for_address; | ||
3542 | api->update_session_timeout = &http_server_plugin_update_session_timeout; | ||
3543 | api->update_inbound_delay = &http_server_plugin_update_inbound_delay; | ||
3544 | api->setup_monitor = &http_server_plugin_setup_monitor; | ||
3545 | #if BUILD_HTTPS | ||
3546 | plugin->name = "transport-https_server"; | ||
3547 | plugin->protocol = "https"; | ||
3548 | #else | ||
3549 | plugin->name = "transport-http_server"; | ||
3550 | plugin->protocol = "http"; | ||
3551 | #endif | ||
3552 | |||
3553 | if (GNUNET_YES == | ||
3554 | GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
3555 | plugin->name, | ||
3556 | "TCP_STEALTH")) | ||
3557 | { | ||
3558 | #ifdef TCP_STEALTH | ||
3559 | plugin->options |= HTTP_OPTIONS_TCP_STEALTH; | ||
3560 | #else | ||
3561 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3562 | _ ("TCP_STEALTH not supported on this platform.\n")); | ||
3563 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3564 | return NULL; | ||
3565 | #endif | ||
3566 | } | ||
3567 | |||
3568 | /* Compile URL regex */ | ||
3569 | if (regcomp (&plugin->url_regex, | ||
3570 | URL_REGEX, | ||
3571 | REG_EXTENDED)) | ||
3572 | { | ||
3573 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
3574 | _ ("Unable to compile URL regex\n")); | ||
3575 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3576 | return NULL; | ||
3577 | } | ||
3578 | |||
3579 | /* Configure plugin */ | ||
3580 | if (GNUNET_SYSERR == server_configure_plugin (plugin)) | ||
3581 | { | ||
3582 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3583 | return NULL; | ||
3584 | } | ||
3585 | |||
3586 | /* Check IPv6 support */ | ||
3587 | if (GNUNET_YES == plugin->use_ipv6) | ||
3588 | plugin->use_ipv6 = server_check_ipv6_support (plugin); | ||
3589 | |||
3590 | /* Report addresses to transport service */ | ||
3591 | if (GNUNET_NO == plugin->external_only) | ||
3592 | server_start_report_addresses (plugin); | ||
3593 | |||
3594 | if (GNUNET_SYSERR == server_start (plugin)) | ||
3595 | { | ||
3596 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3597 | return NULL; | ||
3598 | } | ||
3599 | return api; | ||
3600 | } | ||
3601 | |||
3602 | |||
3603 | /* end of plugin_transport_http_server.c */ | ||