diff options
author | Matthias Wachs <wachs@net.in.tum.de> | 2011-09-27 11:36:45 +0000 |
---|---|---|
committer | Matthias Wachs <wachs@net.in.tum.de> | 2011-09-27 11:36:45 +0000 |
commit | f85c3c37598c68e447174980117bc96328865877 (patch) | |
tree | fcba75d8039a28a5f7d5ad851f05dfc2dcd02216 /src/transport/plugin_transport_http.c | |
parent | 6cbcd301264c12f18b2b837db0297b314ce120e7 (diff) | |
download | gnunet-f85c3c37598c68e447174980117bc96328865877.tar.gz gnunet-f85c3c37598c68e447174980117bc96328865877.zip |
renaming plugin
Diffstat (limited to 'src/transport/plugin_transport_http.c')
-rw-r--r-- | src/transport/plugin_transport_http.c | 3745 |
1 files changed, 595 insertions, 3150 deletions
diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c index fb4627cfd..ca55d1d1d 100644 --- a/src/transport/plugin_transport_http.c +++ b/src/transport/plugin_transport_http.c | |||
@@ -24,54 +24,7 @@ | |||
24 | * @author Matthias Wachs | 24 | * @author Matthias Wachs |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include "platform.h" | 27 | #include "plugin_transport_http.h" |
28 | #include "gnunet_common.h" | ||
29 | #include "gnunet_constants.h" | ||
30 | #include "gnunet_protocols.h" | ||
31 | #include "gnunet_connection_lib.h" | ||
32 | #include "gnunet_service_lib.h" | ||
33 | #include "gnunet_statistics_service.h" | ||
34 | #include "gnunet_transport_service.h" | ||
35 | #include "gnunet_resolver_service.h" | ||
36 | #include "gnunet_server_lib.h" | ||
37 | #include "gnunet_container_lib.h" | ||
38 | #include "gnunet_transport_plugin.h" | ||
39 | #include "gnunet_os_lib.h" | ||
40 | #include "gnunet_nat_lib.h" | ||
41 | #include "microhttpd.h" | ||
42 | #include <curl/curl.h> | ||
43 | |||
44 | #if BUILD_HTTPS | ||
45 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init | ||
46 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_done | ||
47 | #define LIBGNUNET_PLUGIN_TRANSPORT_COMPONENT transport_https | ||
48 | #define PROTOCOL_PREFIX "https" | ||
49 | #else | ||
50 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_init | ||
51 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_done | ||
52 | #define LIBGNUNET_PLUGIN_TRANSPORT_COMPONENT transport_http | ||
53 | #define PROTOCOL_PREFIX "http" | ||
54 | #endif | ||
55 | |||
56 | #define DEBUG_HTTP GNUNET_NO | ||
57 | #define DEBUG_CURL GNUNET_NO | ||
58 | #define DEBUG_MHD GNUNET_NO | ||
59 | #define DEBUG_CONNECTIONS GNUNET_NO | ||
60 | #define DEBUG_SESSION_SELECTION GNUNET_NO | ||
61 | #define DEBUG_SCHEDULING GNUNET_NO | ||
62 | #define CURL_TCP_NODELAY GNUNET_YES | ||
63 | |||
64 | #define INBOUND GNUNET_NO | ||
65 | #define OUTBOUND GNUNET_YES | ||
66 | |||
67 | |||
68 | |||
69 | /** | ||
70 | * Text of the response sent back after the last bytes of a PUT | ||
71 | * request have been received (just to formally obey the HTTP | ||
72 | * protocol). | ||
73 | */ | ||
74 | #define HTTP_PUT_RESPONSE "Thank you!" | ||
75 | 28 | ||
76 | /** | 29 | /** |
77 | * After how long do we expire an address that we | 30 | * After how long do we expire an address that we |
@@ -81,32 +34,6 @@ | |||
81 | #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) | 34 | #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) |
82 | 35 | ||
83 | /** | 36 | /** |
84 | * Page returned if request invalid | ||
85 | */ | ||
86 | #define HTTP_ERROR_RESPONSE "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>" | ||
87 | |||
88 | /** | ||
89 | * Timeout for a http connect | ||
90 | */ | ||
91 | #define HTTP_CONNECT_TIMEOUT 30 | ||
92 | |||
93 | /** | ||
94 | * Network format for IPv4 addresses. | ||
95 | */ | ||
96 | struct IPv4HttpAddress | ||
97 | { | ||
98 | /** | ||
99 | * IPv4 address, in network byte order. | ||
100 | */ | ||
101 | uint32_t ipv4_addr GNUNET_PACKED; | ||
102 | |||
103 | /** | ||
104 | * Port number, in network byte order. | ||
105 | */ | ||
106 | uint16_t port GNUNET_PACKED; | ||
107 | }; | ||
108 | |||
109 | /** | ||
110 | * Wrapper to manage IPv4 addresses | 37 | * Wrapper to manage IPv4 addresses |
111 | */ | 38 | */ |
112 | struct IPv4HttpAddressWrapper | 39 | struct IPv4HttpAddressWrapper |
@@ -121,24 +48,7 @@ struct IPv4HttpAddressWrapper | |||
121 | */ | 48 | */ |
122 | struct IPv4HttpAddressWrapper *prev; | 49 | struct IPv4HttpAddressWrapper *prev; |
123 | 50 | ||
124 | struct IPv4HttpAddress *addr; | 51 | struct sockaddr_in addr; |
125 | }; | ||
126 | |||
127 | /** | ||
128 | * Network format for IPv6 addresses. | ||
129 | */ | ||
130 | struct IPv6HttpAddress | ||
131 | { | ||
132 | /** | ||
133 | * IPv6 address. | ||
134 | */ | ||
135 | struct in6_addr ipv6_addr GNUNET_PACKED; | ||
136 | |||
137 | /** | ||
138 | * Port number, in network byte order. | ||
139 | */ | ||
140 | uint16_t port GNUNET_PACKED; | ||
141 | |||
142 | }; | 52 | }; |
143 | 53 | ||
144 | /** | 54 | /** |
@@ -156,364 +66,13 @@ struct IPv6HttpAddressWrapper | |||
156 | */ | 66 | */ |
157 | struct IPv6HttpAddressWrapper *prev; | 67 | struct IPv6HttpAddressWrapper *prev; |
158 | 68 | ||
159 | struct IPv6HttpAddress *addr; | ||
160 | }; | ||
161 | |||
162 | /** | ||
163 | * Message to send using http | ||
164 | */ | ||
165 | struct HTTP_Message | ||
166 | { | ||
167 | /** | ||
168 | * next pointer for double linked list | ||
169 | */ | ||
170 | struct HTTP_Message *next; | ||
171 | |||
172 | /** | ||
173 | * previous pointer for double linked list | ||
174 | */ | ||
175 | struct HTTP_Message *prev; | ||
176 | |||
177 | /** | ||
178 | * buffer containing data to send | ||
179 | */ | ||
180 | char *buf; | ||
181 | |||
182 | /** | ||
183 | * amount of data already sent | ||
184 | */ | ||
185 | size_t pos; | ||
186 | |||
187 | /** | ||
188 | * buffer length | ||
189 | */ | ||
190 | size_t size; | ||
191 | |||
192 | /** | ||
193 | * Continuation function to call once the transmission buffer | ||
194 | * has again space available. NULL if there is no | ||
195 | * continuation to call. | ||
196 | */ | ||
197 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; | ||
198 | |||
199 | /** | ||
200 | * Closure for transmit_cont. | ||
201 | */ | ||
202 | void *transmit_cont_cls; | ||
203 | }; | ||
204 | |||
205 | |||
206 | struct HTTP_PeerContext | ||
207 | { | ||
208 | /** | ||
209 | * peer's identity | ||
210 | */ | ||
211 | struct GNUNET_PeerIdentity identity; | ||
212 | |||
213 | /** | ||
214 | * Pointer to the global plugin struct. | ||
215 | */ | ||
216 | struct Plugin *plugin; | ||
217 | |||
218 | /** | ||
219 | * Linked list of connections with this peer | ||
220 | * head | ||
221 | */ | ||
222 | struct Session *head; | ||
223 | |||
224 | /** | ||
225 | * Linked list of connections with this peer | ||
226 | * tail | ||
227 | */ | ||
228 | struct Session *tail; | ||
229 | |||
230 | /** | ||
231 | * id for next session | ||
232 | */ | ||
233 | size_t session_id_counter; | ||
234 | |||
235 | /** | ||
236 | * Last session used to send data | ||
237 | */ | ||
238 | struct Session *last_session; | ||
239 | |||
240 | /** | ||
241 | * The task resetting inbound quota delay | ||
242 | */ | ||
243 | GNUNET_SCHEDULER_TaskIdentifier reset_task; | ||
244 | |||
245 | /** | 69 | /** |
246 | * Delay from transport service inbound quota tracker when to receive data again | 70 | * IPv6 address. |
247 | */ | 71 | */ |
248 | struct GNUNET_TIME_Relative delay; | 72 | struct sockaddr_in6 addr GNUNET_PACKED; |
249 | }; | 73 | }; |
250 | 74 | ||
251 | 75 | ||
252 | struct Session | ||
253 | { | ||
254 | /** | ||
255 | * API requirement. | ||
256 | */ | ||
257 | struct SessionHeader header; | ||
258 | |||
259 | /** | ||
260 | * next session in linked list | ||
261 | */ | ||
262 | struct Session *next; | ||
263 | |||
264 | /** | ||
265 | * previous session in linked list | ||
266 | */ | ||
267 | struct Session *prev; | ||
268 | |||
269 | /** | ||
270 | * address of this session | ||
271 | */ | ||
272 | void *addr; | ||
273 | |||
274 | /** | ||
275 | * address length | ||
276 | */ | ||
277 | size_t addrlen; | ||
278 | |||
279 | /** | ||
280 | * target url | ||
281 | */ | ||
282 | char *url; | ||
283 | |||
284 | /** | ||
285 | * Message queue for outbound messages | ||
286 | * head of queue | ||
287 | */ | ||
288 | struct HTTP_Message *pending_msgs_head; | ||
289 | |||
290 | /** | ||
291 | * Message queue for outbound messages | ||
292 | * tail of queue | ||
293 | */ | ||
294 | struct HTTP_Message *pending_msgs_tail; | ||
295 | |||
296 | /** | ||
297 | * partner peer this connection belongs to | ||
298 | */ | ||
299 | struct HTTP_PeerContext *peercontext; | ||
300 | |||
301 | /** | ||
302 | * message stream tokenizer for incoming data | ||
303 | */ | ||
304 | struct GNUNET_SERVER_MessageStreamTokenizer *msgtok; | ||
305 | |||
306 | /** | ||
307 | * session direction | ||
308 | * outbound: OUTBOUND (GNUNET_YES) | ||
309 | * inbound : INBOUND (GNUNET_NO) | ||
310 | */ | ||
311 | unsigned int direction; | ||
312 | |||
313 | /** | ||
314 | * is session connected to send data? | ||
315 | */ | ||
316 | unsigned int send_connected; | ||
317 | |||
318 | /** | ||
319 | * is send connection active? | ||
320 | */ | ||
321 | unsigned int send_active; | ||
322 | |||
323 | /** | ||
324 | * connection disconnect forced (e.g. from transport) | ||
325 | */ | ||
326 | unsigned int send_force_disconnect; | ||
327 | |||
328 | /** | ||
329 | * is session connected to receive data? | ||
330 | */ | ||
331 | unsigned int recv_connected; | ||
332 | |||
333 | /** | ||
334 | * is receive connection active? | ||
335 | */ | ||
336 | unsigned int recv_active; | ||
337 | |||
338 | /** | ||
339 | * connection disconnect forced (e.g. from transport) | ||
340 | */ | ||
341 | unsigned int recv_force_disconnect; | ||
342 | |||
343 | |||
344 | /** | ||
345 | * id for next session | ||
346 | * NOTE: 0 is not an ID, zero is not defined. A correct ID is always > 0 | ||
347 | */ | ||
348 | size_t session_id; | ||
349 | |||
350 | /** | ||
351 | * entity managing sending data | ||
352 | * outbound session: CURL * | ||
353 | * inbound session: mhd_connection * | ||
354 | */ | ||
355 | void *send_endpoint; | ||
356 | |||
357 | /** | ||
358 | * entity managing recieving data | ||
359 | * outbound session: CURL * | ||
360 | * inbound session: mhd_connection * | ||
361 | */ | ||
362 | void *recv_endpoint; | ||
363 | |||
364 | /** | ||
365 | * Current queue size | ||
366 | */ | ||
367 | size_t queue_length_cur; | ||
368 | |||
369 | /** | ||
370 | * Max queue size | ||
371 | */ | ||
372 | size_t queue_length_max; | ||
373 | |||
374 | }; | ||
375 | |||
376 | /** | ||
377 | * Encapsulation of all of the state of the plugin. | ||
378 | */ | ||
379 | struct Plugin | ||
380 | { | ||
381 | /** | ||
382 | * Our environment. | ||
383 | */ | ||
384 | struct GNUNET_TRANSPORT_PluginEnvironment *env; | ||
385 | |||
386 | /** | ||
387 | * Handle for reporting statistics. | ||
388 | */ | ||
389 | struct GNUNET_STATISTICS_Handle *stats; | ||
390 | |||
391 | /** | ||
392 | * Plugin Port | ||
393 | */ | ||
394 | uint16_t port_inbound; | ||
395 | |||
396 | struct GNUNET_CONTAINER_MultiHashMap *peers; | ||
397 | |||
398 | /** | ||
399 | * Daemon for listening for new IPv4 connections. | ||
400 | */ | ||
401 | struct MHD_Daemon *http_server_daemon_v4; | ||
402 | |||
403 | /** | ||
404 | * Daemon for listening for new IPv6connections. | ||
405 | */ | ||
406 | struct MHD_Daemon *http_server_daemon_v6; | ||
407 | |||
408 | /** | ||
409 | * Our primary task for http daemon handling IPv4 connections | ||
410 | */ | ||
411 | GNUNET_SCHEDULER_TaskIdentifier http_server_task_v4; | ||
412 | |||
413 | /** | ||
414 | * Our primary task for http daemon handling IPv6 connections | ||
415 | */ | ||
416 | GNUNET_SCHEDULER_TaskIdentifier http_server_task_v6; | ||
417 | |||
418 | /** | ||
419 | * The task sending data | ||
420 | */ | ||
421 | GNUNET_SCHEDULER_TaskIdentifier http_curl_task; | ||
422 | |||
423 | /** | ||
424 | * cURL Multihandle | ||
425 | */ | ||
426 | CURLM *multi_handle; | ||
427 | |||
428 | /** | ||
429 | * Our handle to the NAT module. | ||
430 | */ | ||
431 | struct GNUNET_NAT_Handle *nat; | ||
432 | |||
433 | /** | ||
434 | * ipv4 DLL head | ||
435 | */ | ||
436 | struct IPv4HttpAddressWrapper *ipv4_addr_head; | ||
437 | |||
438 | /** | ||
439 | * ipv4 DLL tail | ||
440 | */ | ||
441 | struct IPv4HttpAddressWrapper *ipv4_addr_tail; | ||
442 | |||
443 | /** | ||
444 | * ipv6 DLL head | ||
445 | */ | ||
446 | struct IPv6HttpAddressWrapper *ipv6_addr_head; | ||
447 | |||
448 | /** | ||
449 | * ipv6 DLL tail | ||
450 | */ | ||
451 | struct IPv6HttpAddressWrapper *ipv6_addr_tail; | ||
452 | |||
453 | /** | ||
454 | * Our ASCII encoded, hashed peer identity | ||
455 | * This string is used to distinguish between connections and is added to the urls | ||
456 | */ | ||
457 | struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident; | ||
458 | |||
459 | /** | ||
460 | * IPv4 Address the plugin binds to | ||
461 | */ | ||
462 | struct sockaddr_in *bind4_address; | ||
463 | |||
464 | /** | ||
465 | * IPv6 Address the plugins binds to | ||
466 | */ | ||
467 | struct sockaddr_in6 *bind6_address; | ||
468 | |||
469 | /** | ||
470 | * Hostname to bind to | ||
471 | */ | ||
472 | char *bind_hostname; | ||
473 | |||
474 | /** | ||
475 | * Is IPv4 enabled? | ||
476 | */ | ||
477 | int use_ipv6; | ||
478 | |||
479 | /** | ||
480 | * Is IPv6 enabled? | ||
481 | */ | ||
482 | int use_ipv4; | ||
483 | |||
484 | /** | ||
485 | * use local addresses? | ||
486 | */ | ||
487 | int use_localaddresses; | ||
488 | |||
489 | /** | ||
490 | * maximum number of connections | ||
491 | */ | ||
492 | int max_connect_per_transport; | ||
493 | |||
494 | /** | ||
495 | * Current number of connections; | ||
496 | */ | ||
497 | int current_connections; | ||
498 | |||
499 | /** | ||
500 | * Closure passed by MHD to the mhd_logger function | ||
501 | */ | ||
502 | void *mhd_log; | ||
503 | |||
504 | /* only needed for HTTPS plugin */ | ||
505 | #if BUILD_HTTPS | ||
506 | /* The certificate MHD uses as an \0 terminated string */ | ||
507 | char *cert; | ||
508 | |||
509 | /* The private key MHD uses as an \0 terminated string */ | ||
510 | char *key; | ||
511 | |||
512 | /* crypto init string */ | ||
513 | char *crypto_init; | ||
514 | #endif | ||
515 | }; | ||
516 | |||
517 | /** | 76 | /** |
518 | * Context for address to string conversion. | 77 | * Context for address to string conversion. |
519 | */ | 78 | */ |
@@ -525,6 +84,11 @@ struct PrettyPrinterContext | |||
525 | GNUNET_TRANSPORT_AddressStringCallback asc; | 84 | GNUNET_TRANSPORT_AddressStringCallback asc; |
526 | 85 | ||
527 | /** | 86 | /** |
87 | * Plugin | ||
88 | */ | ||
89 | struct Plugin *plugin; | ||
90 | |||
91 | /** | ||
528 | * Clsoure for 'asc'. | 92 | * Clsoure for 'asc'. |
529 | */ | 93 | */ |
530 | void *asc_cls; | 94 | void *asc_cls; |
@@ -537,1933 +101,344 @@ struct PrettyPrinterContext | |||
537 | 101 | ||
538 | 102 | ||
539 | /** | 103 | /** |
540 | * Function called for a quick conversion of the binary address to | 104 | * Encapsulation of all of the state of the plugin. |
541 | * a numeric address. Note that the caller must not free the | ||
542 | * address and that the next call to this function is allowed | ||
543 | * to override the address again. | ||
544 | * | ||
545 | * @param cls closure | ||
546 | * @param addr binary address | ||
547 | * @param addrlen length of the address | ||
548 | * @return string representing the same address | ||
549 | */ | 105 | */ |
550 | static const char * | 106 | struct Plugin; |
551 | http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen); | ||
552 | 107 | ||
553 | 108 | ||
554 | /** | ||
555 | * Call MHD to process pending ipv4 requests and then go back | ||
556 | * and schedule the next run. | ||
557 | */ | ||
558 | static void | ||
559 | http_server_daemon_v4_run (void *cls, | ||
560 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
561 | /** | ||
562 | * Call MHD to process pending ipv6 requests and then go back | ||
563 | * and schedule the next run. | ||
564 | */ | ||
565 | static void | ||
566 | http_server_daemon_v6_run (void *cls, | ||
567 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
568 | |||
569 | /** | ||
570 | * Function setting up curl handle and selecting message to send | ||
571 | * | ||
572 | * @param plugin plugin | ||
573 | * @param ps session | ||
574 | * @return GNUNET_SYSERR on failure, GNUNET_NO if connecting, GNUNET_YES if ok | ||
575 | */ | ||
576 | static int | ||
577 | send_check_connections (struct Plugin *plugin, struct Session *ps); | ||
578 | 109 | ||
579 | /** | 110 | /** |
580 | * Function setting up file descriptors and scheduling task to run | 111 | * Append our port and forward the result. |
581 | * | 112 | * |
582 | * @param plugin plugin as closure | 113 | * @param cls the 'struct PrettyPrinterContext*' |
583 | * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok | 114 | * @param hostname hostname part of the address |
584 | */ | ||
585 | static int | ||
586 | curl_schedule (struct Plugin *plugin); | ||
587 | |||
588 | /** | ||
589 | * Task scheduled to reset the inbound quota delay for a specific peer | ||
590 | * @param cls plugin as closure | ||
591 | * @param tc task context | ||
592 | */ | 115 | */ |
593 | static void | 116 | static void |
594 | reset_inbound_quota_delay (void *cls, | 117 | append_port (void *cls, const char *hostname) |
595 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
596 | { | ||
597 | struct HTTP_PeerContext *pc = cls; | ||
598 | |||
599 | GNUNET_assert (cls != NULL); | ||
600 | pc->reset_task = GNUNET_SCHEDULER_NO_TASK; | ||
601 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
602 | return; | ||
603 | pc->delay = GNUNET_TIME_relative_get_zero (); | ||
604 | } | ||
605 | |||
606 | |||
607 | /** | ||
608 | * Creates a valid url from passed address and id | ||
609 | * @param plugin plugin | ||
610 | * @param addr address to create url from | ||
611 | * @param addrlen address lenth | ||
612 | * @param id session id | ||
613 | * @return the created url | ||
614 | */ | ||
615 | static char * | ||
616 | create_url (struct Plugin *plugin, const void *addr, size_t addrlen, size_t id) | ||
617 | { | ||
618 | char *url = NULL; | ||
619 | char *addr_str = (char *) http_plugin_address_to_string (NULL, addr, addrlen); | ||
620 | |||
621 | GNUNET_assert ((addr != NULL) && (addrlen != 0)); | ||
622 | GNUNET_asprintf (&url, "%s://%s/%s;%u", PROTOCOL_PREFIX, addr_str, | ||
623 | (char *) (&plugin->my_ascii_hash_ident), id); | ||
624 | return url; | ||
625 | } | ||
626 | |||
627 | |||
628 | /** | ||
629 | * Removes a message from the linked list of messages | ||
630 | * @param ps session | ||
631 | * @param msg message | ||
632 | * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success | ||
633 | */ | ||
634 | static int | ||
635 | remove_http_message (struct Session *ps, struct HTTP_Message *msg) | ||
636 | { | ||
637 | GNUNET_CONTAINER_DLL_remove (ps->pending_msgs_head, ps->pending_msgs_tail, | ||
638 | msg); | ||
639 | GNUNET_free (msg); | ||
640 | return GNUNET_OK; | ||
641 | } | ||
642 | |||
643 | /** | ||
644 | * Iterator to remove peer context | ||
645 | * @param cls the plugin | ||
646 | * @param key the peers public key hashcode | ||
647 | * @param value the peer context | ||
648 | * @return GNUNET_YES on success | ||
649 | */ | ||
650 | static int | ||
651 | remove_peer_context_Iterator (void *cls, const GNUNET_HashCode * key, | ||
652 | void *value) | ||
653 | { | 118 | { |
654 | struct Plugin *plugin = cls; | 119 | struct PrettyPrinterContext *ppc = cls; |
655 | struct HTTP_PeerContext *pc = value; | 120 | char *ret; |
656 | struct Session *ps = pc->head; | ||
657 | struct Session *tmp = NULL; | ||
658 | struct HTTP_Message *msg = NULL; | ||
659 | struct HTTP_Message *msg_tmp = NULL; | ||
660 | 121 | ||
661 | #if DEBUG_HTTP | 122 | if (hostname == NULL) |
662 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Freeing context for peer `%s'\n", | ||
663 | GNUNET_i2s (&pc->identity)); | ||
664 | #endif | ||
665 | GNUNET_assert (GNUNET_YES == | ||
666 | GNUNET_CONTAINER_multihashmap_remove (plugin->peers, | ||
667 | &pc->identity.hashPubKey, | ||
668 | pc)); | ||
669 | while (ps != NULL) | ||
670 | { | 123 | { |
671 | plugin->env->session_end (plugin, &pc->identity, ps); | 124 | ppc->asc (ppc->asc_cls, NULL); |
672 | tmp = ps->next; | 125 | GNUNET_free (ppc); |
673 | 126 | return; | |
674 | GNUNET_free_non_null (ps->addr); | ||
675 | GNUNET_free (ps->url); | ||
676 | if (ps->msgtok != NULL) | ||
677 | GNUNET_SERVER_mst_destroy (ps->msgtok); | ||
678 | |||
679 | msg = ps->pending_msgs_head; | ||
680 | while (msg != NULL) | ||
681 | { | ||
682 | msg_tmp = msg->next; | ||
683 | GNUNET_free (msg); | ||
684 | msg = msg_tmp; | ||
685 | } | ||
686 | if (ps->direction == OUTBOUND) | ||
687 | { | ||
688 | if (ps->send_endpoint != NULL) | ||
689 | curl_easy_cleanup (ps->send_endpoint); | ||
690 | if (ps->recv_endpoint != NULL) | ||
691 | curl_easy_cleanup (ps->recv_endpoint); | ||
692 | } | ||
693 | GNUNET_free (ps); | ||
694 | ps = tmp; | ||
695 | } | 127 | } |
696 | GNUNET_free (pc); | 128 | GNUNET_asprintf (&ret, "%s://%s:%d", ppc->plugin->protocol, hostname, |
697 | GNUNET_STATISTICS_update (plugin->env->stats, | 129 | ppc->plugin->port); |
698 | gettext_noop ("# HTTP peers active"), -1, | 130 | ppc->asc (ppc->asc_cls, ret); |
699 | GNUNET_NO); | 131 | GNUNET_free (ret); |
700 | return GNUNET_YES; | ||
701 | } | 132 | } |
702 | 133 | ||
703 | 134 | ||
704 | /** | 135 | /** |
705 | * Removes a session from the linked list of sessions | 136 | * Convert the transports address to a nice, human-readable |
706 | * @param pc peer context | 137 | * format. |
707 | * @param ps session | 138 | * |
708 | * @param call_msg_cont GNUNET_YES to call pending message continuations, otherwise no | 139 | * @param cls closure |
709 | * @param call_msg_cont_result result to call message continuations with | 140 | * @param type name of the transport that generated the address |
710 | * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success | 141 | * @param addr one of the addresses of the host, NULL for the last address |
142 | * the specific address format depends on the transport | ||
143 | * @param addrlen length of the address | ||
144 | * @param numeric should (IP) addresses be displayed in numeric form? | ||
145 | * @param timeout after how long should we give up? | ||
146 | * @param asc function to call on each string | ||
147 | * @param asc_cls closure for asc | ||
711 | */ | 148 | */ |
712 | static int | 149 | static void |
713 | remove_session (struct HTTP_PeerContext *pc, struct Session *ps, | 150 | http_plugin_address_pretty_printer (void *cls, const char *type, |
714 | int call_msg_cont, int call_msg_cont_result) | 151 | const void *addr, size_t addrlen, |
152 | int numeric, | ||
153 | struct GNUNET_TIME_Relative timeout, | ||
154 | GNUNET_TRANSPORT_AddressStringCallback asc, | ||
155 | void *asc_cls) | ||
715 | { | 156 | { |
716 | struct HTTP_Message *msg; | 157 | GNUNET_assert (cls != NULL); |
717 | struct Plugin *plugin = ps->peercontext->plugin; | 158 | struct PrettyPrinterContext *ppc; |
718 | 159 | const void *sb; | |
719 | #if DEBUG_CONNECTIONS | 160 | size_t sbs; |
720 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 161 | uint16_t port = 0 ; |
721 | "Connection %X: removing %s session %X with id %u\n", ps, | ||
722 | (ps->direction == INBOUND) ? "inbound" : "outbound", ps, | ||
723 | ps->session_id); | ||
724 | #endif | ||
725 | plugin->env->session_end (plugin, &pc->identity, ps); | ||
726 | GNUNET_free_non_null (ps->addr); | ||
727 | GNUNET_SERVER_mst_destroy (ps->msgtok); | ||
728 | GNUNET_free (ps->url); | ||
729 | if (ps->direction == INBOUND) | ||
730 | { | ||
731 | if (ps->recv_endpoint != NULL) | ||
732 | { | ||
733 | curl_easy_cleanup (ps->recv_endpoint); | ||
734 | ps->recv_endpoint = NULL; | ||
735 | } | ||
736 | if (ps->send_endpoint != NULL) | ||
737 | { | ||
738 | curl_easy_cleanup (ps->send_endpoint); | ||
739 | ps->send_endpoint = NULL; | ||
740 | } | ||
741 | } | ||
742 | 162 | ||
743 | msg = ps->pending_msgs_head; | 163 | if (addrlen == sizeof (struct sockaddr_in6)) |
744 | while (msg != NULL) | ||
745 | { | 164 | { |
746 | if ((call_msg_cont == GNUNET_YES) && (msg->transmit_cont != NULL)) | 165 | sb = addr; |
747 | { | 166 | sbs = sizeof (struct sockaddr_in6); |
748 | msg->transmit_cont (msg->transmit_cont_cls, &pc->identity, | ||
749 | call_msg_cont_result); | ||
750 | } | ||
751 | GNUNET_CONTAINER_DLL_remove (ps->pending_msgs_head, ps->pending_msgs_head, | ||
752 | msg); | ||
753 | GNUNET_free (msg); | ||
754 | msg = ps->pending_msgs_head; | ||
755 | } | ||
756 | 167 | ||
757 | GNUNET_CONTAINER_DLL_remove (pc->head, pc->tail, ps); | 168 | port = ntohs (((struct sockaddr_in6 *)addr)->sin6_port); |
758 | GNUNET_free (ps); | ||
759 | ps = NULL; | ||
760 | |||
761 | /* no sessions left remove peer */ | ||
762 | if (pc->head == NULL) | ||
763 | { | ||
764 | #if DEBUG_HTTP | ||
765 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
766 | "No sessions left for peer `%s', removing context\n", | ||
767 | GNUNET_i2s (&pc->identity)); | ||
768 | #endif | ||
769 | remove_peer_context_Iterator (plugin, &pc->identity.hashPubKey, pc); | ||
770 | } | 169 | } |
771 | 170 | else if (addrlen == sizeof (struct sockaddr_in)) | |
772 | return GNUNET_OK; | ||
773 | } | ||
774 | |||
775 | |||
776 | #if 0 | ||
777 | static int | ||
778 | check_localaddress (const struct sockaddr *addr, socklen_t addrlen) | ||
779 | { | ||
780 | uint32_t res = 0; | ||
781 | int local = GNUNET_NO; | ||
782 | int af = addr->sa_family; | ||
783 | |||
784 | switch (af) | ||
785 | { | 171 | { |
786 | case AF_INET: | 172 | sb = &addr; |
787 | { | 173 | sbs = sizeof (struct sockaddr_in); |
788 | uint32_t netmask = 0x7F000000; | 174 | port = ntohs (((struct sockaddr_in *)addr)->sin_port); |
789 | uint32_t address = ntohl (((struct sockaddr_in *) addr)->sin_addr.s_addr); | ||
790 | |||
791 | res = (address >> 24) ^ (netmask >> 24); | ||
792 | if (res != 0) | ||
793 | local = GNUNET_NO; | ||
794 | else | ||
795 | local = GNUNET_YES; | ||
796 | #if DEBUG_HTTP | ||
797 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking IPv4 address `%s': %s\n", | ||
798 | GNUNET_a2s (addr, addrlen), | ||
799 | (local == GNUNET_YES) ? "local" : "global"); | ||
800 | #endif | ||
801 | break; | ||
802 | } | 175 | } |
803 | case AF_INET6: | 176 | else |
804 | { | 177 | { |
805 | if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr) || | 178 | /* invalid address */ |
806 | IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) | 179 | GNUNET_break_op (0); |
807 | local = GNUNET_YES; | 180 | asc (asc_cls, NULL); |
808 | else | 181 | return; |
809 | local = GNUNET_NO; | ||
810 | #if DEBUG_HTTP | ||
811 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking IPv6 address `%s' : %s\n", | ||
812 | GNUNET_a2s (addr, addrlen), | ||
813 | (local == GNUNET_YES) ? "local" : "global"); | ||
814 | #endif | ||
815 | break; | ||
816 | } | ||
817 | } | 182 | } |
818 | return local; | 183 | ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); |
184 | ppc->asc = asc; | ||
185 | ppc->asc_cls = asc_cls; | ||
186 | ppc->port = port; | ||
187 | ppc->plugin = cls; | ||
188 | GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); | ||
819 | } | 189 | } |
820 | 190 | ||
821 | 191 | ||
192 | |||
822 | /** | 193 | /** |
823 | * Add the IP of our network interface to the list of | 194 | * Another peer has suggested an address for this |
824 | * our external IP addresses. | 195 | * peer and transport plugin. Check that this could be a valid |
196 | * address. If so, consider adding it to the list | ||
197 | * of addresses. | ||
825 | * | 198 | * |
826 | * @param cls the 'struct Plugin*' | 199 | * @param cls closure |
827 | * @param name name of the interface | 200 | * @param addr pointer to the address |
828 | * @param isDefault do we think this may be our default interface | 201 | * @param addrlen length of addr |
829 | * @param addr address of the interface | 202 | * @return GNUNET_OK if this is a plausible address for this peer |
830 | * @param addrlen number of bytes in addr | 203 | * and transport |
831 | * @return GNUNET_OK to continue iterating | ||
832 | */ | 204 | */ |
833 | static int | 205 | static int |
834 | process_interfaces (void *cls, const char *name, int isDefault, | 206 | http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) |
835 | const struct sockaddr *addr, socklen_t addrlen) | ||
836 | { | 207 | { |
837 | struct Plugin *plugin = cls; | ||
838 | struct IPv4HttpAddress *t4; | ||
839 | struct IPv6HttpAddress *t6; | ||
840 | int af; | ||
841 | |||
842 | if (plugin->use_localaddresses == GNUNET_NO) | ||
843 | { | ||
844 | if (GNUNET_YES == check_localaddress (addr, addrlen)) | ||
845 | { | ||
846 | #if DEBUG_HTTP | ||
847 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PROTOCOL_PREFIX, | ||
848 | "Not notifying transport of address `%s' (local address)\n", | ||
849 | GNUNET_a2s (addr, addrlen)); | ||
850 | #endif | ||
851 | return GNUNET_OK; | ||
852 | } | ||
853 | } | ||
854 | 208 | ||
209 | struct Plugin *plugin = cls; | ||
210 | struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head; | ||
211 | struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head; | ||
855 | 212 | ||
856 | GNUNET_assert (cls != NULL); | 213 | GNUNET_assert (cls != NULL); |
857 | af = addr->sa_family; | 214 | if ((addrlen != sizeof (struct sockaddr_in)) || |
858 | if ((af == AF_INET) && (plugin->use_ipv4 == GNUNET_YES) && | 215 | (addrlen != sizeof (struct sockaddr_in6))) |
859 | (plugin->bind6_address == NULL)) | 216 | return GNUNET_SYSERR; |
860 | { | ||
861 | |||
862 | struct in_addr bnd_cmp = ((struct sockaddr_in *) addr)->sin_addr; | ||
863 | |||
864 | t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddress)); | ||
865 | // Not skipping loopback addresses | ||
866 | |||
867 | 217 | ||
868 | t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | 218 | if (addrlen == sizeof (struct sockaddr_in)) |
869 | t4->port = htons (plugin->port_inbound); | 219 | { |
870 | if (plugin->bind4_address != NULL) | 220 | while (w_tv4 != NULL) |
871 | { | 221 | { |
872 | if (0 == | 222 | if (0 == memcmp (&w_tv4->addr, addr, sizeof (struct sockaddr_in))) |
873 | memcmp (&plugin->bind4_address->sin_addr, &bnd_cmp, | 223 | break; |
874 | sizeof (struct in_addr))) | 224 | w_tv4 = w_tv4->next; |
875 | { | ||
876 | GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, | ||
877 | plugin->ipv4_addr_tail, t4); | ||
878 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, t4, | ||
879 | sizeof (struct IPv4HttpAddress)); | ||
880 | return GNUNET_OK; | ||
881 | } | ||
882 | GNUNET_free (t4); | ||
883 | return GNUNET_OK; | ||
884 | } | 225 | } |
885 | else | 226 | if (w_tv4 != NULL) |
886 | { | ||
887 | GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, | ||
888 | plugin->ipv4_addr_tail, t4); | ||
889 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, t4, | ||
890 | sizeof (struct IPv4HttpAddress)); | ||
891 | return GNUNET_OK; | 227 | return GNUNET_OK; |
892 | } | 228 | else |
229 | return GNUNET_SYSERR; | ||
893 | } | 230 | } |
894 | if ((af == AF_INET6) && (plugin->use_ipv6 == GNUNET_YES) && | 231 | if (addrlen == sizeof (struct sockaddr_in6)) |
895 | (plugin->bind4_address == NULL)) | ||
896 | { | 232 | { |
897 | 233 | while (w_tv6 != NULL) | |
898 | struct in6_addr bnd_cmp6 = ((struct sockaddr_in6 *) addr)->sin6_addr; | ||
899 | |||
900 | t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddress)); | ||
901 | GNUNET_assert (t6 != NULL); | ||
902 | |||
903 | if (plugin->bind6_address != NULL) | ||
904 | { | 234 | { |
905 | if (0 == | 235 | if (0 == |
906 | memcmp (&plugin->bind6_address->sin6_addr, &bnd_cmp6, | 236 | memcmp (&w_tv6->addr, addr, |
907 | sizeof (struct in6_addr))) | 237 | sizeof (struct sockaddr_in6))) |
908 | { | 238 | break; |
909 | memcpy (&t6->ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, | 239 | w_tv6 = w_tv6->next; |
910 | sizeof (struct in6_addr)); | ||
911 | t6->port = htons (plugin->port_inbound); | ||
912 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, t6, | ||
913 | sizeof (struct IPv6HttpAddress)); | ||
914 | GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, | ||
915 | plugin->ipv6_addr_tail, t6); | ||
916 | return GNUNET_OK; | ||
917 | } | ||
918 | GNUNET_free (t6); | ||
919 | return GNUNET_OK; | ||
920 | } | 240 | } |
921 | memcpy (&t6->ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, | 241 | if (w_tv6 != NULL) |
922 | sizeof (struct in6_addr)); | 242 | return GNUNET_OK; |
923 | t6->port = htons (plugin->port_inbound); | 243 | else |
924 | GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, | 244 | return GNUNET_SYSERR; |
925 | t6); | ||
926 | |||
927 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, t6, | ||
928 | sizeof (struct IPv6HttpAddress)); | ||
929 | } | 245 | } |
930 | return GNUNET_OK; | 246 | return GNUNET_OK; |
931 | } | 247 | } |
932 | #endif | ||
933 | |||
934 | /** | ||
935 | * External logging function for MHD | ||
936 | * @param arg arguments | ||
937 | * @param fmt format string | ||
938 | * @param ap list of arguments | ||
939 | */ | ||
940 | static void | ||
941 | mhd_logger (void *arg, const char *fmt, va_list ap) | ||
942 | { | ||
943 | char text[1024]; | ||
944 | |||
945 | vsnprintf (text, sizeof (text), fmt, ap); | ||
946 | va_end (ap); | ||
947 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MHD: %s\n", text); | ||
948 | } | ||
949 | |||
950 | |||
951 | static void | ||
952 | mhd_termination_cb (void *cls, struct MHD_Connection *connection, | ||
953 | void **httpSessionCache) | ||
954 | { | ||
955 | struct Session *ps = *httpSessionCache; | ||
956 | |||
957 | if (ps == NULL) | ||
958 | return; | ||
959 | struct HTTP_PeerContext *pc = ps->peercontext; | ||
960 | struct Plugin *plugin = cls; | ||
961 | |||
962 | GNUNET_assert (cls != NULL); | ||
963 | plugin->current_connections--; | ||
964 | |||
965 | if (connection == ps->recv_endpoint) | ||
966 | { | ||
967 | #if DEBUG_CONNECTIONS | ||
968 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
969 | "Connection %X: inbound connection from peer `%s' was terminated\n", | ||
970 | ps, GNUNET_i2s (&pc->identity)); | ||
971 | #endif | ||
972 | ps->recv_active = GNUNET_NO; | ||
973 | ps->recv_connected = GNUNET_NO; | ||
974 | ps->recv_endpoint = NULL; | ||
975 | } | ||
976 | if (connection == ps->send_endpoint) | ||
977 | { | ||
978 | ps->send_active = GNUNET_NO; | ||
979 | ps->send_connected = GNUNET_NO; | ||
980 | ps->send_endpoint = NULL; | ||
981 | #if DEBUG_CONNECTIONS | ||
982 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
983 | "Connection %X: outbound connection from peer `%s' was terminated\n", | ||
984 | ps, GNUNET_i2s (&pc->identity)); | ||
985 | #endif | ||
986 | } | ||
987 | |||
988 | /* if both connections disconnected, remove session */ | ||
989 | if ((ps->send_connected == GNUNET_NO) && (ps->recv_connected == GNUNET_NO)) | ||
990 | { | ||
991 | GNUNET_STATISTICS_update (pc->plugin->env->stats, | ||
992 | gettext_noop | ||
993 | ("# HTTP inbound sessions for peers active"), -1, | ||
994 | GNUNET_NO); | ||
995 | remove_session (pc, ps, GNUNET_YES, GNUNET_SYSERR); | ||
996 | } | ||
997 | } | ||
998 | |||
999 | 248 | ||
1000 | /** | 249 | struct GNUNET_TIME_Relative |
1001 | * Callback called by MessageStreamTokenizer when a message has arrived | 250 | http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity * peer, |
1002 | * @param cls current session as closure | 251 | const struct GNUNET_MessageHeader * message, |
1003 | * @param client clien | 252 | struct Session * session, |
1004 | * @param message the message to be forwarded to transport service | 253 | const char *sender_address, |
1005 | */ | 254 | uint16_t sender_address_len) |
1006 | static void | ||
1007 | mhd_write_mst_cb (void *cls, void *client, | ||
1008 | const struct GNUNET_MessageHeader *message) | ||
1009 | { | 255 | { |
1010 | struct Session *ps = cls; | 256 | struct Session *s = cls; |
1011 | struct HTTP_PeerContext *pc; | 257 | struct Plugin *plugin = s->plugin; |
1012 | struct GNUNET_TIME_Relative delay; | ||
1013 | |||
1014 | GNUNET_assert (ps != NULL); | ||
1015 | pc = ps->peercontext; | ||
1016 | GNUNET_assert (pc != NULL); | ||
1017 | #if DEBUG_HTTP | ||
1018 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1019 | "Connection %X: Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n", | ||
1020 | ps, ntohs (message->type), ntohs (message->size), | ||
1021 | GNUNET_i2s (&(ps->peercontext)->identity), | ||
1022 | http_plugin_address_to_string (NULL, ps->addr, ps->addrlen)); | ||
1023 | #endif | ||
1024 | struct GNUNET_TRANSPORT_ATS_Information distance[2]; | 258 | struct GNUNET_TRANSPORT_ATS_Information distance[2]; |
259 | struct GNUNET_TIME_Relative delay; | ||
1025 | 260 | ||
1026 | distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE); | 261 | distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE); |
1027 | distance[0].value = htonl (1); | 262 | distance[0].value = htonl (1); |
1028 | distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); | 263 | distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); |
1029 | distance[1].value = htonl (0); | 264 | distance[1].value = htonl (0); |
1030 | delay = | ||
1031 | pc->plugin->env->receive (ps->peercontext->plugin->env->cls, | ||
1032 | &pc->identity, message, | ||
1033 | (const struct GNUNET_TRANSPORT_ATS_Information | ||
1034 | *) &distance, 2, ps, NULL, 0); | ||
1035 | pc->delay = delay; | ||
1036 | if (pc->reset_task != GNUNET_SCHEDULER_NO_TASK) | ||
1037 | GNUNET_SCHEDULER_cancel (pc->reset_task); | ||
1038 | |||
1039 | if (delay.rel_value > 0) | ||
1040 | { | ||
1041 | #if DEBUG_HTTP | ||
1042 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1043 | "Connection %X: Inbound quota management: delay next read for %llu ms \n", | ||
1044 | ps, delay.rel_value); | ||
1045 | #endif | ||
1046 | pc->reset_task = | ||
1047 | GNUNET_SCHEDULER_add_delayed (delay, &reset_inbound_quota_delay, pc); | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1051 | 265 | ||
1052 | /** | 266 | delay = plugin->env->receive (plugin->env->cls, &s->target, message, (const struct GNUNET_TRANSPORT_ATS_Information*) &distance, 2, s, s->addr, s->addrlen); |
1053 | * Check if incoming connection is accepted. | 267 | return delay; |
1054 | * NOTE: Here every connection is accepted | ||
1055 | * @param cls plugin as closure | ||
1056 | * @param addr address of incoming connection | ||
1057 | * @param addr_len address length of incoming connection | ||
1058 | * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected | ||
1059 | * | ||
1060 | */ | ||
1061 | static int | ||
1062 | mhd_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) | ||
1063 | { | ||
1064 | struct Plugin *plugin = cls; | ||
1065 | |||
1066 | GNUNET_assert (cls != NULL); | ||
1067 | |||
1068 | if (plugin->max_connect_per_transport > plugin->current_connections) | ||
1069 | { | ||
1070 | plugin->current_connections++; | ||
1071 | return MHD_YES; | ||
1072 | } | ||
1073 | else | ||
1074 | return MHD_NO; | ||
1075 | } | 268 | } |
1076 | 269 | ||
1077 | |||
1078 | /** | 270 | /** |
1079 | * Callback called by MHD when it needs data to send | 271 | * Function called for a quick conversion of the binary address to |
1080 | * @param cls current session | 272 | * a numeric address. Note that the caller must not free the |
1081 | * @param pos position in buffer | 273 | * address and that the next call to this function is allowed |
1082 | * @param buf the buffer to write data to | 274 | * to override the address again. |
1083 | * @param max max number of bytes available in buffer | 275 | * |
1084 | * @return bytes written to buffer | 276 | * @param cls closure |
1085 | */ | 277 | * @param addr binary address |
1086 | static ssize_t | 278 | * @param addrlen length of the address |
1087 | mhd_send_callback (void *cls, uint64_t pos, char *buf, size_t max) | 279 | * @return string representing the same address |
1088 | { | ||
1089 | struct Session *ps = cls; | ||
1090 | struct HTTP_PeerContext *pc; | ||
1091 | struct HTTP_Message *msg; | ||
1092 | int bytes_read = 0; | ||
1093 | |||
1094 | GNUNET_assert (ps != NULL); | ||
1095 | |||
1096 | pc = ps->peercontext; | ||
1097 | msg = ps->pending_msgs_tail; | ||
1098 | if (ps->send_force_disconnect == GNUNET_YES) | ||
1099 | { | ||
1100 | #if DEBUG_CONNECTIONS | ||
1101 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1102 | "Connection %X: outbound forced to disconnect\n", ps); | ||
1103 | #endif | ||
1104 | return -1; | ||
1105 | } | ||
1106 | |||
1107 | if (msg != NULL) | ||
1108 | { | ||
1109 | /* sending */ | ||
1110 | if ((msg->size - msg->pos) <= max) | ||
1111 | { | ||
1112 | memcpy (buf, &msg->buf[msg->pos], (msg->size - msg->pos)); | ||
1113 | bytes_read = msg->size - msg->pos; | ||
1114 | msg->pos += (msg->size - msg->pos); | ||
1115 | } | ||
1116 | else | ||
1117 | { | ||
1118 | memcpy (buf, &msg->buf[msg->pos], max); | ||
1119 | msg->pos += max; | ||
1120 | bytes_read = max; | ||
1121 | } | ||
1122 | |||
1123 | /* removing message */ | ||
1124 | if (msg->pos == msg->size) | ||
1125 | { | ||
1126 | if (NULL != msg->transmit_cont) | ||
1127 | msg->transmit_cont (msg->transmit_cont_cls, &pc->identity, GNUNET_OK); | ||
1128 | ps->queue_length_cur -= msg->size; | ||
1129 | remove_http_message (ps, msg); | ||
1130 | } | ||
1131 | } | ||
1132 | #if DEBUG_CONNECTIONS | ||
1133 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection %X: MHD has sent %u bytes\n", | ||
1134 | ps, bytes_read); | ||
1135 | #endif | ||
1136 | return bytes_read; | ||
1137 | } | ||
1138 | |||
1139 | |||
1140 | /** | ||
1141 | * Process GET or PUT request received via MHD. For | ||
1142 | * GET, queue response that will send back our pending | ||
1143 | * messages. For PUT, process incoming data and send | ||
1144 | * to GNUnet core. In either case, check if a session | ||
1145 | * already exists and create a new one if not. | ||
1146 | */ | ||
1147 | static int | ||
1148 | mhd_access_cb (void *cls, struct MHD_Connection *mhd_connection, | ||
1149 | const char *url, const char *method, const char *version, | ||
1150 | const char *upload_data, size_t * upload_data_size, | ||
1151 | void **httpSessionCache) | ||
1152 | { | ||
1153 | struct Plugin *plugin = cls; | ||
1154 | struct MHD_Response *response; | ||
1155 | const union MHD_ConnectionInfo *conn_info; | ||
1156 | const struct sockaddr *client_addr; | ||
1157 | const struct sockaddr_in *addrin; | ||
1158 | const struct sockaddr_in6 *addrin6; | ||
1159 | char address[INET6_ADDRSTRLEN + 14]; | ||
1160 | struct GNUNET_PeerIdentity pi_in; | ||
1161 | size_t id_num = 0; | ||
1162 | struct IPv4HttpAddress ipv4addr; | ||
1163 | struct IPv6HttpAddress ipv6addr; | ||
1164 | struct HTTP_PeerContext *pc = NULL; | ||
1165 | struct Session *ps = NULL; | ||
1166 | struct Session *ps_tmp = NULL; | ||
1167 | int res = GNUNET_NO; | ||
1168 | void *addr = NULL; | ||
1169 | size_t addr_len = 0; | ||
1170 | |||
1171 | GNUNET_assert (cls != NULL); | ||
1172 | |||
1173 | if (NULL == *httpSessionCache) | ||
1174 | { | ||
1175 | /* check url for peer identity , if invalid send HTTP 404 */ | ||
1176 | size_t len = strlen (&url[1]); | ||
1177 | char *peer = GNUNET_malloc (104 + 1); | ||
1178 | |||
1179 | if ((len > 104) && (url[104] == ';')) | ||
1180 | { | ||
1181 | char *id = GNUNET_malloc ((len - 104) + 1); | ||
1182 | |||
1183 | strcpy (id, &url[105]); | ||
1184 | memcpy (peer, &url[1], 103); | ||
1185 | peer[103] = '\0'; | ||
1186 | id_num = strtoul (id, NULL, 10); | ||
1187 | GNUNET_free (id); | ||
1188 | } | ||
1189 | res = GNUNET_CRYPTO_hash_from_string (peer, &(pi_in.hashPubKey)); | ||
1190 | GNUNET_free (peer); | ||
1191 | if (GNUNET_SYSERR == res) | ||
1192 | { | ||
1193 | response = | ||
1194 | MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), | ||
1195 | HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); | ||
1196 | res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response); | ||
1197 | MHD_destroy_response (response); | ||
1198 | #if DEBUG_CONNECTIONS | ||
1199 | if (res == MHD_YES) | ||
1200 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1201 | "Peer has no valid ident, sent HTTP 1.1/404\n"); | ||
1202 | else | ||
1203 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1204 | "Peer has no valid ident, could not send error\n"); | ||
1205 | #endif | ||
1206 | return res; | ||
1207 | } | ||
1208 | } | ||
1209 | else | ||
1210 | { | ||
1211 | ps = *httpSessionCache; | ||
1212 | pc = ps->peercontext; | ||
1213 | } | ||
1214 | |||
1215 | if (NULL == *httpSessionCache) | ||
1216 | { | ||
1217 | /* get peer context */ | ||
1218 | pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &pi_in.hashPubKey); | ||
1219 | /* Peer unknown */ | ||
1220 | if (pc == NULL) | ||
1221 | { | ||
1222 | pc = GNUNET_malloc (sizeof (struct HTTP_PeerContext)); | ||
1223 | pc->plugin = plugin; | ||
1224 | pc->session_id_counter = 1; | ||
1225 | pc->last_session = NULL; | ||
1226 | memcpy (&pc->identity, &pi_in, sizeof (struct GNUNET_PeerIdentity)); | ||
1227 | GNUNET_CONTAINER_multihashmap_put (plugin->peers, | ||
1228 | &pc->identity.hashPubKey, pc, | ||
1229 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1230 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1231 | gettext_noop ("# HTTP peers active"), 1, | ||
1232 | GNUNET_NO); | ||
1233 | } | ||
1234 | |||
1235 | conn_info = | ||
1236 | MHD_get_connection_info (mhd_connection, | ||
1237 | MHD_CONNECTION_INFO_CLIENT_ADDRESS); | ||
1238 | /* Incoming IPv4 connection */ | ||
1239 | /* cast required for legacy MHD API < 0.9.6 */ | ||
1240 | client_addr = (const struct sockaddr *) conn_info->client_addr; | ||
1241 | if (AF_INET == client_addr->sa_family) | ||
1242 | { | ||
1243 | addrin = (const struct sockaddr_in *) client_addr; | ||
1244 | inet_ntop (addrin->sin_family, &(addrin->sin_addr), address, | ||
1245 | INET_ADDRSTRLEN); | ||
1246 | memcpy (&ipv4addr.ipv4_addr, &(addrin->sin_addr), | ||
1247 | sizeof (struct in_addr)); | ||
1248 | ipv4addr.port = addrin->sin_port; | ||
1249 | addr = &ipv4addr; | ||
1250 | addr_len = sizeof (struct IPv4HttpAddress); | ||
1251 | } | ||
1252 | /* Incoming IPv6 connection */ | ||
1253 | if (AF_INET6 == client_addr->sa_family) | ||
1254 | { | ||
1255 | addrin6 = (const struct sockaddr_in6 *) client_addr; | ||
1256 | inet_ntop (addrin6->sin6_family, &(addrin6->sin6_addr), address, | ||
1257 | INET6_ADDRSTRLEN); | ||
1258 | memcpy (&ipv6addr.ipv6_addr, &(addrin6->sin6_addr), | ||
1259 | sizeof (struct in6_addr)); | ||
1260 | ipv6addr.port = addrin6->sin6_port; | ||
1261 | addr = &ipv6addr; | ||
1262 | addr_len = sizeof (struct IPv6HttpAddress); | ||
1263 | } | ||
1264 | |||
1265 | GNUNET_assert (addr != NULL); | ||
1266 | GNUNET_assert (addr_len != 0); | ||
1267 | |||
1268 | ps = NULL; | ||
1269 | /* only inbound sessions here */ | ||
1270 | |||
1271 | ps_tmp = pc->head; | ||
1272 | while (ps_tmp != NULL) | ||
1273 | { | ||
1274 | if ((ps_tmp->direction == INBOUND) && (ps_tmp->session_id == id_num) && | ||
1275 | (id_num != 0)) | ||
1276 | { | ||
1277 | if ((ps_tmp->recv_force_disconnect != GNUNET_YES) && | ||
1278 | (ps_tmp->send_force_disconnect != GNUNET_YES)) | ||
1279 | ps = ps_tmp; | ||
1280 | break; | ||
1281 | } | ||
1282 | ps_tmp = ps_tmp->next; | ||
1283 | } | ||
1284 | |||
1285 | if (ps == NULL) | ||
1286 | { | ||
1287 | ps = GNUNET_malloc (sizeof (struct Session)); | ||
1288 | ps->addr = GNUNET_malloc (addr_len); | ||
1289 | memcpy (ps->addr, addr, addr_len); | ||
1290 | ps->addrlen = addr_len; | ||
1291 | ps->direction = INBOUND; | ||
1292 | ps->pending_msgs_head = NULL; | ||
1293 | ps->pending_msgs_tail = NULL; | ||
1294 | ps->send_connected = GNUNET_NO; | ||
1295 | ps->send_active = GNUNET_NO; | ||
1296 | ps->recv_connected = GNUNET_NO; | ||
1297 | ps->recv_active = GNUNET_NO; | ||
1298 | ps->peercontext = pc; | ||
1299 | ps->session_id = id_num; | ||
1300 | ps->queue_length_cur = 0; | ||
1301 | ps->queue_length_max = GNUNET_SERVER_MAX_MESSAGE_SIZE; | ||
1302 | ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id); | ||
1303 | GNUNET_CONTAINER_DLL_insert (pc->head, pc->tail, ps); | ||
1304 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1305 | gettext_noop | ||
1306 | ("# HTTP inbound sessions for peers active"), 1, | ||
1307 | GNUNET_NO); | ||
1308 | } | ||
1309 | |||
1310 | *httpSessionCache = ps; | ||
1311 | if (ps->msgtok == NULL) | ||
1312 | ps->msgtok = GNUNET_SERVER_mst_create (&mhd_write_mst_cb, ps); | ||
1313 | #if DEBUG_HTTP | ||
1314 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1315 | "Connection %X: HTTP Daemon has new an incoming `%s' request from peer `%s' (`%s')\n", | ||
1316 | ps, method, GNUNET_i2s (&pc->identity), | ||
1317 | http_plugin_address_to_string (NULL, ps->addr, ps->addrlen)); | ||
1318 | #endif | ||
1319 | } | ||
1320 | |||
1321 | /* Is it a PUT or a GET request */ | ||
1322 | if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) | ||
1323 | { | ||
1324 | if (ps->recv_force_disconnect == GNUNET_YES) | ||
1325 | { | ||
1326 | #if DEBUG_CONNECTIONS | ||
1327 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1328 | "Connection %X: inbound connection was forced to disconnect\n", | ||
1329 | ps); | ||
1330 | #endif | ||
1331 | ps->recv_active = GNUNET_NO; | ||
1332 | return MHD_NO; | ||
1333 | } | ||
1334 | if ((*upload_data_size == 0) && (ps->recv_active == GNUNET_NO)) | ||
1335 | { | ||
1336 | ps->recv_endpoint = mhd_connection; | ||
1337 | ps->recv_connected = GNUNET_YES; | ||
1338 | ps->recv_active = GNUNET_YES; | ||
1339 | ps->recv_force_disconnect = GNUNET_NO; | ||
1340 | #if DEBUG_CONNECTIONS | ||
1341 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1342 | "Connection %X: inbound PUT connection connected\n", ps); | ||
1343 | #endif | ||
1344 | return MHD_YES; | ||
1345 | } | ||
1346 | |||
1347 | /* Transmission of all data complete */ | ||
1348 | if ((*upload_data_size == 0) && (ps->recv_active == GNUNET_YES)) | ||
1349 | { | ||
1350 | response = | ||
1351 | MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE), | ||
1352 | HTTP_PUT_RESPONSE, MHD_NO, MHD_NO); | ||
1353 | res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
1354 | #if DEBUG_CONNECTIONS | ||
1355 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1356 | "Connection %X: Sent HTTP/1.1: 200 OK as PUT Response\n", ps); | ||
1357 | #endif | ||
1358 | MHD_destroy_response (response); | ||
1359 | ps->recv_active = GNUNET_NO; | ||
1360 | return MHD_YES; | ||
1361 | } | ||
1362 | |||
1363 | /* Recieving data */ | ||
1364 | if ((*upload_data_size > 0) && (ps->recv_active == GNUNET_YES)) | ||
1365 | { | ||
1366 | if (pc->delay.rel_value == 0) | ||
1367 | { | ||
1368 | #if DEBUG_HTTP | ||
1369 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1370 | "Connection %X: PUT with %u bytes forwarded to MST\n", ps, | ||
1371 | *upload_data_size); | ||
1372 | #endif | ||
1373 | res = | ||
1374 | GNUNET_SERVER_mst_receive (ps->msgtok, ps, upload_data, | ||
1375 | *upload_data_size, GNUNET_NO, GNUNET_NO); | ||
1376 | (*upload_data_size) = 0; | ||
1377 | } | ||
1378 | else | ||
1379 | { | ||
1380 | #if DEBUG_HTTP | ||
1381 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1382 | "Connection %X: no inbound bandwidth available! Next read was delayed for %llu ms\n", | ||
1383 | ps, ps->peercontext->delay.rel_value); | ||
1384 | #endif | ||
1385 | } | ||
1386 | return MHD_YES; | ||
1387 | } | ||
1388 | else | ||
1389 | return MHD_NO; | ||
1390 | } | ||
1391 | if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) | ||
1392 | { | ||
1393 | if (ps->send_force_disconnect == GNUNET_YES) | ||
1394 | { | ||
1395 | #if DEBUG_CONNECTIONS | ||
1396 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1397 | "Connection %X: outbound connection was forced to disconnect\n", | ||
1398 | ps); | ||
1399 | #endif | ||
1400 | ps->send_active = GNUNET_NO; | ||
1401 | return MHD_NO; | ||
1402 | } | ||
1403 | ps->send_connected = GNUNET_YES; | ||
1404 | ps->send_active = GNUNET_YES; | ||
1405 | ps->send_endpoint = mhd_connection; | ||
1406 | ps->send_force_disconnect = GNUNET_NO; | ||
1407 | #if DEBUG_CONNECTIONS | ||
1408 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1409 | "Connection %X: inbound GET connection connected\n", ps); | ||
1410 | #endif | ||
1411 | response = | ||
1412 | MHD_create_response_from_callback (-1, 32 * 1024, &mhd_send_callback, | ||
1413 | ps, NULL); | ||
1414 | res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
1415 | MHD_destroy_response (response); | ||
1416 | return MHD_YES; | ||
1417 | } | ||
1418 | return MHD_NO; | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | /** | ||
1423 | * Function that queries MHD's select sets and | ||
1424 | * starts the task waiting for them. | ||
1425 | * @param plugin plugin | ||
1426 | * @param daemon_handle the MHD daemon handle | ||
1427 | * @return gnunet task identifier | ||
1428 | */ | ||
1429 | static GNUNET_SCHEDULER_TaskIdentifier | ||
1430 | http_server_daemon_prepare (struct Plugin *plugin, | ||
1431 | struct MHD_Daemon *daemon_handle) | ||
1432 | { | ||
1433 | GNUNET_SCHEDULER_TaskIdentifier ret; | ||
1434 | fd_set rs; | ||
1435 | fd_set ws; | ||
1436 | fd_set es; | ||
1437 | struct GNUNET_NETWORK_FDSet *wrs; | ||
1438 | struct GNUNET_NETWORK_FDSet *wws; | ||
1439 | struct GNUNET_NETWORK_FDSet *wes; | ||
1440 | int max; | ||
1441 | unsigned long long timeout; | ||
1442 | int haveto; | ||
1443 | struct GNUNET_TIME_Relative tv; | ||
1444 | |||
1445 | ret = GNUNET_SCHEDULER_NO_TASK; | ||
1446 | FD_ZERO (&rs); | ||
1447 | FD_ZERO (&ws); | ||
1448 | FD_ZERO (&es); | ||
1449 | wrs = GNUNET_NETWORK_fdset_create (); | ||
1450 | wes = GNUNET_NETWORK_fdset_create (); | ||
1451 | wws = GNUNET_NETWORK_fdset_create (); | ||
1452 | max = -1; | ||
1453 | GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); | ||
1454 | haveto = MHD_get_timeout (daemon_handle, &timeout); | ||
1455 | if (haveto == MHD_YES) | ||
1456 | tv.rel_value = (uint64_t) timeout; | ||
1457 | else | ||
1458 | tv = GNUNET_TIME_UNIT_SECONDS; | ||
1459 | GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); | ||
1460 | GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); | ||
1461 | GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); | ||
1462 | if (daemon_handle == plugin->http_server_daemon_v4) | ||
1463 | { | ||
1464 | if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK) | ||
1465 | { | ||
1466 | GNUNET_SCHEDULER_cancel (plugin->http_server_task_v4); | ||
1467 | plugin->http_server_daemon_v4 = GNUNET_SCHEDULER_NO_TASK; | ||
1468 | } | ||
1469 | |||
1470 | ret = | ||
1471 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1472 | GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, | ||
1473 | &http_server_daemon_v4_run, plugin); | ||
1474 | } | ||
1475 | if (daemon_handle == plugin->http_server_daemon_v6) | ||
1476 | { | ||
1477 | if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) | ||
1478 | { | ||
1479 | GNUNET_SCHEDULER_cancel (plugin->http_server_task_v6); | ||
1480 | plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK; | ||
1481 | } | ||
1482 | |||
1483 | ret = | ||
1484 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1485 | GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, | ||
1486 | &http_server_daemon_v6_run, plugin); | ||
1487 | } | ||
1488 | GNUNET_NETWORK_fdset_destroy (wrs); | ||
1489 | GNUNET_NETWORK_fdset_destroy (wws); | ||
1490 | GNUNET_NETWORK_fdset_destroy (wes); | ||
1491 | return ret; | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | /** | ||
1496 | * Call MHD IPv4 to process pending requests and then go back | ||
1497 | * and schedule the next run. | ||
1498 | * @param cls plugin as closure | ||
1499 | * @param tc task context | ||
1500 | */ | ||
1501 | static void | ||
1502 | http_server_daemon_v4_run (void *cls, | ||
1503 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1504 | { | ||
1505 | struct Plugin *plugin = cls; | ||
1506 | |||
1507 | #if DEBUG_SCHEDULING | ||
1508 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) | ||
1509 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1510 | "http_server_daemon_v4_run: GNUNET_SCHEDULER_REASON_READ_READY\n"); | ||
1511 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) | ||
1512 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1513 | "http_server_daemon_v4_run: GNUNET_SCHEDULER_REASON_WRITE_READY\n"); | ||
1514 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) | ||
1515 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1516 | "http_server_daemon_v4_run: GNUNET_SCHEDULER_REASON_TIMEOUT\n"); | ||
1517 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_STARTUP)) | ||
1518 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1519 | "http_server_daemon_v4_run: GGNUNET_SCHEDULER_REASON_STARTUP\n"); | ||
1520 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1521 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1522 | "http_server_daemon_v4_run: GGNUNET_SCHEDULER_REASON_SHUTDOWN\n"); | ||
1523 | #endif | ||
1524 | |||
1525 | GNUNET_assert (cls != NULL); | ||
1526 | plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK; | ||
1527 | |||
1528 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1529 | return; | ||
1530 | |||
1531 | GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v4)); | ||
1532 | plugin->http_server_task_v4 = | ||
1533 | http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4); | ||
1534 | } | ||
1535 | |||
1536 | |||
1537 | /** | ||
1538 | * Call MHD IPv6 to process pending requests and then go back | ||
1539 | * and schedule the next run. | ||
1540 | * @param cls plugin as closure | ||
1541 | * @param tc task context | ||
1542 | */ | ||
1543 | static void | ||
1544 | http_server_daemon_v6_run (void *cls, | ||
1545 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1546 | { | ||
1547 | struct Plugin *plugin = cls; | ||
1548 | |||
1549 | #if DEBUG_SCHEDULING | ||
1550 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) | ||
1551 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1552 | "http_server_daemon_v6_run: GNUNET_SCHEDULER_REASON_READ_READY\n"); | ||
1553 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) | ||
1554 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1555 | "http_server_daemon_v6_run: GNUNET_SCHEDULER_REASON_WRITE_READY\n"); | ||
1556 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) | ||
1557 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1558 | "http_server_daemon_v6_run: GNUNET_SCHEDULER_REASON_TIMEOUT\n"); | ||
1559 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_STARTUP)) | ||
1560 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1561 | "http_server_daemon_v6_run: GGNUNET_SCHEDULER_REASON_STARTUP\n"); | ||
1562 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1563 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1564 | "http_server_daemon_v6_run: GGNUNET_SCHEDULER_REASON_SHUTDOWN\n"); | ||
1565 | #endif | ||
1566 | |||
1567 | GNUNET_assert (cls != NULL); | ||
1568 | plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK; | ||
1569 | |||
1570 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1571 | return; | ||
1572 | |||
1573 | GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v6)); | ||
1574 | plugin->http_server_task_v6 = | ||
1575 | http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6); | ||
1576 | } | ||
1577 | |||
1578 | |||
1579 | static size_t | ||
1580 | curl_get_header_cb (void *ptr, size_t size, size_t nmemb, void *stream) | ||
1581 | { | ||
1582 | struct Session *ps = stream; | ||
1583 | |||
1584 | long http_result = 0; | ||
1585 | int res; | ||
1586 | |||
1587 | /* Getting last http result code */ | ||
1588 | GNUNET_assert (NULL != ps); | ||
1589 | if (ps->recv_connected == GNUNET_NO) | ||
1590 | { | ||
1591 | res = | ||
1592 | curl_easy_getinfo (ps->recv_endpoint, CURLINFO_RESPONSE_CODE, | ||
1593 | &http_result); | ||
1594 | if (CURLE_OK == res) | ||
1595 | { | ||
1596 | if (http_result == 200) | ||
1597 | { | ||
1598 | ps->recv_connected = GNUNET_YES; | ||
1599 | ps->recv_active = GNUNET_YES; | ||
1600 | #if DEBUG_CONNECTIONS | ||
1601 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1602 | "Connection %X: connected to recieve data\n", ps); | ||
1603 | #endif | ||
1604 | // Calling send_check_connections again since receive is established | ||
1605 | send_check_connections (ps->peercontext->plugin, ps); | ||
1606 | } | ||
1607 | } | ||
1608 | } | ||
1609 | |||
1610 | #if DEBUG_CURL | ||
1611 | char *tmp; | ||
1612 | size_t len = size * nmemb; | ||
1613 | |||
1614 | tmp = NULL; | ||
1615 | if ((size * nmemb) < SIZE_MAX) | ||
1616 | tmp = GNUNET_malloc (len + 1); | ||
1617 | |||
1618 | if ((tmp != NULL) && (len > 0)) | ||
1619 | { | ||
1620 | memcpy (tmp, ptr, len); | ||
1621 | if (len >= 2) | ||
1622 | { | ||
1623 | if (tmp[len - 2] == 13) | ||
1624 | tmp[len - 2] = '\0'; | ||
1625 | } | ||
1626 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection %X: Header: %s\n", ps, | ||
1627 | tmp); | ||
1628 | } | ||
1629 | GNUNET_free_non_null (tmp); | ||
1630 | #endif | ||
1631 | |||
1632 | return size * nmemb; | ||
1633 | } | ||
1634 | |||
1635 | |||
1636 | /** | ||
1637 | * Callback called by libcurl when new headers arrive | ||
1638 | * Used to get HTTP result for curl operations | ||
1639 | * @param ptr stream to read from | ||
1640 | * @param size size of one char element | ||
1641 | * @param nmemb number of char elements | ||
1642 | * @param stream closure set by user | ||
1643 | * @return bytes read by function | ||
1644 | */ | 280 | */ |
1645 | static size_t | 281 | const char * |
1646 | curl_put_header_cb (void *ptr, size_t size, size_t nmemb, void *stream) | 282 | http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) |
1647 | { | 283 | { |
1648 | struct Session *ps = stream; | ||
1649 | |||
1650 | char *tmp; | ||
1651 | size_t len = size * nmemb; | ||
1652 | long http_result = 0; | ||
1653 | int res; | ||
1654 | |||
1655 | /* Getting last http result code */ | ||
1656 | GNUNET_assert (NULL != ps); | ||
1657 | res = | ||
1658 | curl_easy_getinfo (ps->send_endpoint, CURLINFO_RESPONSE_CODE, | ||
1659 | &http_result); | ||
1660 | if (CURLE_OK == res) | ||
1661 | { | ||
1662 | if ((http_result == 100) && (ps->send_connected == GNUNET_NO)) | ||
1663 | { | ||
1664 | ps->send_connected = GNUNET_YES; | ||
1665 | ps->send_active = GNUNET_YES; | ||
1666 | #if DEBUG_CONNECTIONS | ||
1667 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1668 | "Connection %X: connected to send data\n", ps); | ||
1669 | #endif | ||
1670 | } | ||
1671 | if ((http_result == 200) && (ps->send_connected == GNUNET_YES)) | ||
1672 | { | ||
1673 | ps->send_connected = GNUNET_NO; | ||
1674 | ps->send_active = GNUNET_NO; | ||
1675 | #if DEBUG_CONNECTIONS | ||
1676 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1677 | "Connection %X: sending disconnected\n", ps); | ||
1678 | #endif | ||
1679 | } | ||
1680 | } | ||
1681 | 284 | ||
1682 | tmp = NULL; | 285 | struct sockaddr_in *a4; |
1683 | if ((size * nmemb) < SIZE_MAX) | 286 | struct sockaddr_in6 *a6; |
1684 | tmp = GNUNET_malloc (len + 1); | 287 | char *address; |
1685 | 288 | static char rbuf[INET6_ADDRSTRLEN + 13]; | |
1686 | if ((tmp != NULL) && (len > 0)) | 289 | uint16_t port; |
1687 | { | 290 | int res = 0; |
1688 | memcpy (tmp, ptr, len); | ||
1689 | if (len >= 2) | ||
1690 | { | ||
1691 | if (tmp[len - 2] == 13) | ||
1692 | tmp[len - 2] = '\0'; | ||
1693 | } | ||
1694 | } | ||
1695 | GNUNET_free_non_null (tmp); | ||
1696 | return size * nmemb; | ||
1697 | } | ||
1698 | 291 | ||
1699 | /** | 292 | if (addrlen == sizeof (struct sockaddr_in6)) |
1700 | * Callback method used with libcurl | ||
1701 | * Method is called when libcurl needs to read data during sending | ||
1702 | * @param stream pointer where to write data | ||
1703 | * @param size size of an individual element | ||
1704 | * @param nmemb count of elements that can be written to the buffer | ||
1705 | * @param ptr source pointer, passed to the libcurl handle | ||
1706 | * @return bytes written to stream | ||
1707 | */ | ||
1708 | static size_t | ||
1709 | curl_send_cb (void *stream, size_t size, size_t nmemb, void *ptr) | ||
1710 | { | ||
1711 | struct Session *ps = ptr; | ||
1712 | struct HTTP_Message *msg = ps->pending_msgs_tail; | ||
1713 | size_t bytes_sent; | ||
1714 | size_t len; | ||
1715 | |||
1716 | if (ps->send_active == GNUNET_NO) | ||
1717 | return CURL_READFUNC_PAUSE; | ||
1718 | if ((ps->pending_msgs_tail == NULL) && (ps->send_active == GNUNET_YES)) | ||
1719 | { | 293 | { |
1720 | #if DEBUG_CONNECTIONS | 294 | a6 = (struct sockaddr_in6 *) addr; |
1721 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 295 | address = GNUNET_malloc (INET6_ADDRSTRLEN); |
1722 | "Connection %X: No Message to send, pausing connection\n", ps); | 296 | inet_ntop (AF_INET6, &(a6->sin6_addr), address, INET6_ADDRSTRLEN); |
1723 | #endif | 297 | port = ntohs (a6->sin6_port); |
1724 | ps->send_active = GNUNET_NO; | ||
1725 | return CURL_READFUNC_PAUSE; | ||
1726 | } | 298 | } |
1727 | 299 | else if (addrlen == sizeof (struct sockaddr_in)) | |
1728 | GNUNET_assert (msg != NULL); | ||
1729 | |||
1730 | /* data to send */ | ||
1731 | if (msg->pos < msg->size) | ||
1732 | { | 300 | { |
1733 | /* data fit in buffer */ | 301 | a4 = (struct sockaddr_in *) addr; |
1734 | if ((msg->size - msg->pos) <= (size * nmemb)) | 302 | address = GNUNET_malloc (INET_ADDRSTRLEN); |
1735 | { | 303 | inet_ntop (AF_INET, &(a4->sin_addr), address, INET_ADDRSTRLEN); |
1736 | len = (msg->size - msg->pos); | 304 | port = ntohs (a4->sin_port); |
1737 | memcpy (stream, &msg->buf[msg->pos], len); | ||
1738 | msg->pos += len; | ||
1739 | bytes_sent = len; | ||
1740 | } | ||
1741 | else | ||
1742 | { | ||
1743 | len = size * nmemb; | ||
1744 | memcpy (stream, &msg->buf[msg->pos], len); | ||
1745 | msg->pos += len; | ||
1746 | bytes_sent = len; | ||
1747 | } | ||
1748 | } | 305 | } |
1749 | /* no data to send */ | ||
1750 | else | 306 | else |
1751 | { | 307 | { |
1752 | bytes_sent = 0; | 308 | /* invalid address */ |
1753 | } | 309 | return NULL; |
1754 | |||
1755 | if (msg->pos == msg->size) | ||
1756 | { | ||
1757 | #if DEBUG_CONNECTIONS | ||
1758 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1759 | "Connection %X: Message with %u bytes sent, removing message from queue\n", | ||
1760 | ps, msg->pos); | ||
1761 | #endif | ||
1762 | /* Calling transmit continuation */ | ||
1763 | if (NULL != ps->pending_msgs_tail->transmit_cont) | ||
1764 | msg->transmit_cont (ps->pending_msgs_tail->transmit_cont_cls, | ||
1765 | &(ps->peercontext)->identity, GNUNET_OK); | ||
1766 | ps->queue_length_cur -= msg->size; | ||
1767 | remove_http_message (ps, msg); | ||
1768 | } | 310 | } |
1769 | return bytes_sent; | 311 | #if !BUILD_HTTPS |
1770 | } | 312 | char * protocol = "http"; |
1771 | 313 | #else | |
1772 | 314 | char * protocol = "https"; | |
1773 | static void | ||
1774 | curl_receive_mst_cb (void *cls, void *client, | ||
1775 | const struct GNUNET_MessageHeader *message) | ||
1776 | { | ||
1777 | struct Session *ps = cls; | ||
1778 | struct GNUNET_TIME_Relative delay; | ||
1779 | |||
1780 | GNUNET_assert (ps != NULL); | ||
1781 | |||
1782 | struct HTTP_PeerContext *pc = ps->peercontext; | ||
1783 | |||
1784 | GNUNET_assert (pc != NULL); | ||
1785 | #if DEBUG_HTTP | ||
1786 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1787 | "Connection %X: Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n", | ||
1788 | ps, ntohs (message->type), ntohs (message->size), | ||
1789 | GNUNET_i2s (&(pc->identity)), http_plugin_address_to_string (NULL, | ||
1790 | ps->addr, | ||
1791 | ps->addrlen)); | ||
1792 | #endif | 315 | #endif |
1793 | struct GNUNET_TRANSPORT_ATS_Information distance[2]; | ||
1794 | 316 | ||
1795 | distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE); | 317 | GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13)); |
1796 | distance[0].value = htonl (1); | 318 | if (addrlen == sizeof (struct sockaddr_in6)) |
1797 | distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); | 319 | res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, address, port); |
1798 | distance[1].value = htonl (0); | 320 | else if (addrlen == sizeof (struct sockaddr_in)) |
1799 | 321 | res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, address, port); | |
1800 | delay = | ||
1801 | pc->plugin->env->receive (pc->plugin->env->cls, &pc->identity, message, | ||
1802 | (const struct GNUNET_TRANSPORT_ATS_Information | ||
1803 | *) &distance, 2, ps, ps->addr, ps->addrlen); | ||
1804 | pc->delay = delay; | ||
1805 | if (pc->reset_task != GNUNET_SCHEDULER_NO_TASK) | ||
1806 | GNUNET_SCHEDULER_cancel (pc->reset_task); | ||
1807 | 322 | ||
1808 | if (delay.rel_value > 0) | 323 | GNUNET_free (address); |
1809 | { | 324 | GNUNET_assert (res != 0); |
1810 | #if DEBUG_HTTP | 325 | return rbuf; |
1811 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1812 | "Connection %X: Inbound quota management: delay next read for %llu ms\n", | ||
1813 | ps, delay.rel_value); | ||
1814 | #endif | ||
1815 | pc->reset_task = | ||
1816 | GNUNET_SCHEDULER_add_delayed (delay, &reset_inbound_quota_delay, pc); | ||
1817 | } | ||
1818 | } | 326 | } |
1819 | 327 | ||
1820 | 328 | struct Session * | |
1821 | /** | 329 | lookup_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, |
1822 | * Callback method used with libcurl | 330 | struct Session * session, |
1823 | * Method is called when libcurl needs to write data during sending | 331 | const void *addr, size_t addrlen, int force_address) |
1824 | * @param stream pointer where to write data | ||
1825 | * @param size size of an individual element | ||
1826 | * @param nmemb count of elements that can be written to the buffer | ||
1827 | * @param ptr destination pointer, passed to the libcurl handle | ||
1828 | * @return bytes read from stream | ||
1829 | */ | ||
1830 | static size_t | ||
1831 | curl_receive_cb (void *stream, size_t size, size_t nmemb, void *ptr) | ||
1832 | { | 332 | { |
1833 | struct Session *ps = ptr; | 333 | struct Session *s = NULL; |
334 | struct Session *t = NULL; | ||
335 | int e_peer; | ||
336 | int e_addr; | ||
1834 | 337 | ||
1835 | if (ps->peercontext->delay.rel_value > 0) | 338 | t = plugin->head; |
339 | if (t == NULL) | ||
340 | return NULL; | ||
341 | while (t != NULL) | ||
1836 | { | 342 | { |
1837 | #if DEBUG_HTTP | 343 | #if 0 |
1838 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 344 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, |
1839 | "Connection %X: no inbound bandwidth available! Next read was delayed for %llu ms\n", | 345 | "Comparing peer `%s' address `%s' len %i session %X to \n", GNUNET_i2s(target), GNUNET_a2s(addr,addrlen), addrlen, session); |
1840 | ps, ps->peercontext->delay.rel_value); | 346 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,"peer `%s' address `%s' len %i session %X \n\n", GNUNET_i2s(&t->target), GNUNET_a2s(t->addr,t->addrlen), t->addrlen, t); |
1841 | #endif | 347 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,"memcmp %i \n", memcmp (addr, t->addr, addrlen)); |
1842 | return 0; | ||
1843 | } | ||
1844 | #if DEBUG_CONNECTIONS | ||
1845 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection %X: %u bytes received\n", ps, | ||
1846 | size * nmemb); | ||
1847 | #endif | 348 | #endif |
1848 | GNUNET_SERVER_mst_receive (ps->msgtok, ps, stream, size * nmemb, GNUNET_NO, | 349 | e_peer = GNUNET_NO; |
1849 | GNUNET_NO); | 350 | e_addr = GNUNET_NO; |
1850 | return (size * nmemb); | ||
1851 | } | ||
1852 | |||
1853 | 351 | ||
1854 | static void | 352 | if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity))) |
1855 | curl_handle_finished (struct Plugin *plugin) | ||
1856 | { | ||
1857 | struct Session *ps = NULL; | ||
1858 | struct HTTP_PeerContext *pc = NULL; | ||
1859 | struct CURLMsg *msg; | ||
1860 | struct HTTP_Message *cur_msg = NULL; | ||
1861 | int msgs_in_queue; | ||
1862 | char *tmp; | ||
1863 | long http_result; | ||
1864 | |||
1865 | do | ||
1866 | { | ||
1867 | msg = curl_multi_info_read (plugin->multi_handle, &msgs_in_queue); | ||
1868 | if ((msgs_in_queue == 0) || (msg == NULL)) | ||
1869 | break; | ||
1870 | /* get session for affected curl handle */ | ||
1871 | GNUNET_assert (msg->easy_handle != NULL); | ||
1872 | curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, &tmp); | ||
1873 | ps = (struct Session *) tmp; | ||
1874 | GNUNET_assert (ps != NULL); | ||
1875 | pc = ps->peercontext; | ||
1876 | GNUNET_assert (pc != NULL); | ||
1877 | switch (msg->msg) | ||
1878 | { | 353 | { |
1879 | case CURLMSG_DONE: | 354 | e_peer = GNUNET_YES; |
1880 | if ((msg->data.result != CURLE_OK) && | 355 | if (addrlen == t->addrlen) |
1881 | (msg->data.result != CURLE_GOT_NOTHING)) | ||
1882 | { | 356 | { |
1883 | /* sending msg failed */ | 357 | if (0 == memcmp (addr, t->addr, addrlen)) |
1884 | if (msg->easy_handle == ps->send_endpoint) | ||
1885 | { | ||
1886 | #if DEBUG_CONNECTIONS | ||
1887 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1888 | _ | ||
1889 | ("Connection %X: HTTP PUT to peer `%s' (`%s') failed: `%s' `%s'\n"), | ||
1890 | ps, GNUNET_i2s (&pc->identity), | ||
1891 | http_plugin_address_to_string (NULL, ps->addr, | ||
1892 | ps->addrlen), | ||
1893 | "curl_multi_perform", | ||
1894 | curl_easy_strerror (msg->data.result)); | ||
1895 | #endif | ||
1896 | ps->send_connected = GNUNET_NO; | ||
1897 | ps->send_active = GNUNET_NO; | ||
1898 | curl_multi_remove_handle (plugin->multi_handle, ps->send_endpoint); | ||
1899 | while (ps->pending_msgs_tail != NULL) | ||
1900 | { | ||
1901 | cur_msg = ps->pending_msgs_tail; | ||
1902 | if (NULL != cur_msg->transmit_cont) | ||
1903 | cur_msg->transmit_cont (cur_msg->transmit_cont_cls, &pc->identity, | ||
1904 | GNUNET_SYSERR); | ||
1905 | ps->queue_length_cur -= cur_msg->size; | ||
1906 | remove_http_message (ps, cur_msg); | ||
1907 | } | ||
1908 | } | ||
1909 | /* GET connection failed */ | ||
1910 | if (msg->easy_handle == ps->recv_endpoint) | ||
1911 | { | 358 | { |
1912 | #if DEBUG_CONNECTIONS | 359 | e_addr = GNUNET_YES; |
1913 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1914 | _ | ||
1915 | ("Connection %X: HTTP GET to peer `%s' (`%s') failed: `%s' `%s'\n"), | ||
1916 | ps, GNUNET_i2s (&pc->identity), | ||
1917 | http_plugin_address_to_string (NULL, ps->addr, | ||
1918 | ps->addrlen), | ||
1919 | "curl_multi_perform", | ||
1920 | curl_easy_strerror (msg->data.result)); | ||
1921 | #endif | ||
1922 | ps->recv_connected = GNUNET_NO; | ||
1923 | ps->recv_active = GNUNET_NO; | ||
1924 | curl_multi_remove_handle (plugin->multi_handle, ps->recv_endpoint); | ||
1925 | } | 360 | } |
1926 | } | 361 | } |
1927 | else | 362 | if ((t == session)) |
1928 | { | 363 | { |
1929 | if (msg->easy_handle == ps->send_endpoint) | 364 | if(t->addrlen == session->addrlen) |
1930 | { | 365 | { |
1931 | GNUNET_assert (CURLE_OK == | 366 | if (0 == memcmp (session->addr, t->addr, t->addrlen)) |
1932 | curl_easy_getinfo (msg->easy_handle, | ||
1933 | CURLINFO_RESPONSE_CODE, | ||
1934 | &http_result)); | ||
1935 | #if DEBUG_CONNECTIONS | ||
1936 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1937 | "Connection %X: HTTP PUT connection to peer `%s' (`%s') was closed with HTTP code %u\n", | ||
1938 | ps, GNUNET_i2s (&pc->identity), | ||
1939 | http_plugin_address_to_string (NULL, ps->addr, | ||
1940 | ps->addrlen), http_result); | ||
1941 | #endif | ||
1942 | /* Calling transmit continuation */ | ||
1943 | while (ps->pending_msgs_tail != NULL) | ||
1944 | { | ||
1945 | cur_msg = ps->pending_msgs_tail; | ||
1946 | if (NULL != cur_msg->transmit_cont) | ||
1947 | { | ||
1948 | /* HTTP 1xx : Last message before here was informational */ | ||
1949 | if ((http_result >= 100) && (http_result < 200)) | ||
1950 | cur_msg->transmit_cont (cur_msg->transmit_cont_cls, | ||
1951 | &pc->identity, GNUNET_OK); | ||
1952 | /* HTTP 2xx: successful operations */ | ||
1953 | if ((http_result >= 200) && (http_result < 300)) | ||
1954 | cur_msg->transmit_cont (cur_msg->transmit_cont_cls, | ||
1955 | &pc->identity, GNUNET_OK); | ||
1956 | /* HTTP 3xx..5xx: error */ | ||
1957 | if ((http_result >= 300) && (http_result < 600)) | ||
1958 | cur_msg->transmit_cont (cur_msg->transmit_cont_cls, | ||
1959 | &pc->identity, GNUNET_SYSERR); | ||
1960 | } | ||
1961 | ps->queue_length_cur -= cur_msg->size; | ||
1962 | remove_http_message (ps, cur_msg); | ||
1963 | } | ||
1964 | |||
1965 | ps->send_connected = GNUNET_NO; | ||
1966 | ps->send_active = GNUNET_NO; | ||
1967 | curl_multi_remove_handle (plugin->multi_handle, ps->send_endpoint); | ||
1968 | } | ||
1969 | if (msg->easy_handle == ps->recv_endpoint) | ||
1970 | { | 367 | { |
1971 | #if DEBUG_CONNECTIONS | 368 | e_addr = GNUNET_YES; |
1972 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1973 | "Connection %X: HTTP GET connection to peer `%s' (`%s') was closed with HTTP code %u\n", | ||
1974 | ps, GNUNET_i2s (&pc->identity), | ||
1975 | http_plugin_address_to_string (NULL, ps->addr, | ||
1976 | ps->addrlen), http_result); | ||
1977 | #endif | ||
1978 | ps->recv_connected = GNUNET_NO; | ||
1979 | ps->recv_active = GNUNET_NO; | ||
1980 | curl_multi_remove_handle (plugin->multi_handle, ps->recv_endpoint); | ||
1981 | } | 369 | } |
1982 | plugin->current_connections--; | 370 | } |
1983 | } | 371 | } |
1984 | if ((ps->recv_connected == GNUNET_NO) && | 372 | } |
1985 | (ps->send_connected == GNUNET_NO)) | 373 | |
1986 | remove_session (pc, ps, GNUNET_YES, GNUNET_SYSERR); | 374 | if ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) |
375 | { | ||
376 | s = t; | ||
377 | break; | ||
378 | } | ||
379 | if ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES)) | ||
380 | { | ||
381 | s = t; | ||
1987 | break; | 382 | break; |
1988 | default: | 383 | } |
384 | if ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) | ||
385 | { | ||
386 | s = t; | ||
1989 | break; | 387 | break; |
1990 | } | 388 | } |
389 | if (s != NULL) | ||
390 | break; | ||
391 | t = t->next; | ||
1991 | } | 392 | } |
1992 | while ((msgs_in_queue > 0)); | ||
1993 | } | ||
1994 | |||
1995 | 393 | ||
1996 | /** | ||
1997 | * Task performing curl operations | ||
1998 | * @param cls plugin as closure | ||
1999 | * @param tc gnunet scheduler task context | ||
2000 | */ | ||
2001 | static void | ||
2002 | curl_perform (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
2003 | { | ||
2004 | struct Plugin *plugin = cls; | ||
2005 | static unsigned int handles_last_run; | ||
2006 | int running; | ||
2007 | CURLMcode mret; | ||
2008 | 394 | ||
2009 | GNUNET_assert (cls != NULL); | 395 | return s; |
2010 | |||
2011 | plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK; | ||
2012 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
2013 | return; | ||
2014 | do | ||
2015 | { | ||
2016 | running = 0; | ||
2017 | mret = curl_multi_perform (plugin->multi_handle, &running); | ||
2018 | if ((running < handles_last_run) && (running > 0)) | ||
2019 | curl_handle_finished (plugin); | ||
2020 | handles_last_run = running; | ||
2021 | } | ||
2022 | while (mret == CURLM_CALL_MULTI_PERFORM); | ||
2023 | curl_schedule (plugin); | ||
2024 | } | 396 | } |
2025 | 397 | ||
2026 | 398 | void | |
2027 | /** | 399 | delete_session (struct Session *s) |
2028 | * Function setting up file descriptors and scheduling task to run | ||
2029 | * | ||
2030 | * @param plugin plugin as closure | ||
2031 | * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok | ||
2032 | */ | ||
2033 | static int | ||
2034 | curl_schedule (struct Plugin *plugin) | ||
2035 | { | 400 | { |
2036 | fd_set rs; | 401 | if (s->msg_tk != NULL) |
2037 | fd_set ws; | ||
2038 | fd_set es; | ||
2039 | int max; | ||
2040 | struct GNUNET_NETWORK_FDSet *grs; | ||
2041 | struct GNUNET_NETWORK_FDSet *gws; | ||
2042 | long to; | ||
2043 | CURLMcode mret; | ||
2044 | |||
2045 | /* Cancel previous scheduled task */ | ||
2046 | if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK) | ||
2047 | { | 402 | { |
2048 | GNUNET_SCHEDULER_cancel (plugin->http_curl_task); | 403 | GNUNET_SERVER_mst_destroy (s->msg_tk); |
2049 | plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK; | 404 | s->msg_tk = NULL; |
2050 | } | 405 | } |
2051 | 406 | GNUNET_free (s->addr); | |
2052 | max = -1; | 407 | GNUNET_free_non_null(s->server_recv); |
2053 | FD_ZERO (&rs); | 408 | GNUNET_free_non_null(s->server_send); |
2054 | FD_ZERO (&ws); | 409 | GNUNET_free (s); |
2055 | FD_ZERO (&es); | ||
2056 | mret = curl_multi_fdset (plugin->multi_handle, &rs, &ws, &es, &max); | ||
2057 | if (mret != CURLM_OK) | ||
2058 | { | ||
2059 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | ||
2060 | "curl_multi_fdset", __FILE__, __LINE__, | ||
2061 | curl_multi_strerror (mret)); | ||
2062 | return GNUNET_SYSERR; | ||
2063 | } | ||
2064 | mret = curl_multi_timeout (plugin->multi_handle, &to); | ||
2065 | if (mret != CURLM_OK) | ||
2066 | { | ||
2067 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | ||
2068 | "curl_multi_timeout", __FILE__, __LINE__, | ||
2069 | curl_multi_strerror (mret)); | ||
2070 | return GNUNET_SYSERR; | ||
2071 | } | ||
2072 | |||
2073 | grs = GNUNET_NETWORK_fdset_create (); | ||
2074 | gws = GNUNET_NETWORK_fdset_create (); | ||
2075 | GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); | ||
2076 | GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); | ||
2077 | plugin->http_curl_task = | ||
2078 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
2079 | GNUNET_SCHEDULER_NO_TASK, | ||
2080 | (to == | ||
2081 | -1) ? | ||
2082 | GNUNET_TIME_relative_multiply | ||
2083 | (GNUNET_TIME_UNIT_SECONDS, | ||
2084 | 5) : | ||
2085 | GNUNET_TIME_relative_multiply | ||
2086 | (GNUNET_TIME_UNIT_MILLISECONDS, to), grs, | ||
2087 | gws, &curl_perform, plugin); | ||
2088 | GNUNET_NETWORK_fdset_destroy (gws); | ||
2089 | GNUNET_NETWORK_fdset_destroy (grs); | ||
2090 | return GNUNET_OK; | ||
2091 | } | 410 | } |
2092 | 411 | ||
2093 | 412 | struct Session * | |
2094 | #if DEBUG_CURL | 413 | create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, |
2095 | /** | 414 | const void *addr, size_t addrlen, |
2096 | * Function to log curl debug messages with GNUNET_log | 415 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) |
2097 | * @param curl handle | ||
2098 | * @param type curl_infotype | ||
2099 | * @param data data | ||
2100 | * @param size size | ||
2101 | * @param cls closure | ||
2102 | * @return 0 | ||
2103 | */ | ||
2104 | static int | ||
2105 | curl_logger (CURL * curl, curl_infotype type, char *data, size_t size, | ||
2106 | void *cls) | ||
2107 | { | 416 | { |
2108 | if (type == CURLINFO_TEXT) | 417 | struct Session *s = NULL; |
2109 | { | 418 | |
2110 | char text[size + 2]; | 419 | s = GNUNET_malloc (sizeof (struct Session)); |
2111 | 420 | memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity)); | |
2112 | memcpy (text, data, size); | 421 | s->plugin = plugin; |
2113 | if (text[size - 1] == '\n') | 422 | s->addr = GNUNET_malloc (addrlen); |
2114 | text[size] = '\0'; | 423 | memcpy (s->addr, addr, addrlen); |
2115 | else | 424 | s->addrlen = addrlen; |
2116 | { | 425 | s->transmit_cont = cont; |
2117 | text[size] = '\n'; | 426 | s->transmit_cont_cls = cont_cls; |
2118 | text[size + 1] = '\0'; | 427 | s->next = NULL; |
2119 | } | 428 | s->next_receive = GNUNET_TIME_absolute_get_forever(); |
2120 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CURL: Connection %X - %s", cls, text); | 429 | return s; |
2121 | } | ||
2122 | return 0; | ||
2123 | } | 430 | } |
2124 | #endif | ||
2125 | 431 | ||
2126 | 432 | void | |
2127 | /** | 433 | notify_session_end (void *cls, |
2128 | * Function setting up curl handle and selecting message to send | 434 | const struct GNUNET_PeerIdentity * |
2129 | * | 435 | peer, struct Session * s) |
2130 | * @param plugin plugin | ||
2131 | * @param ps session | ||
2132 | * @return GNUNET_SYSERR on failure, GNUNET_NO if connecting, GNUNET_YES if ok | ||
2133 | */ | ||
2134 | static int | ||
2135 | send_check_connections (struct Plugin *plugin, struct Session *ps) | ||
2136 | { | 436 | { |
2137 | CURLMcode mret; | 437 | struct Plugin *plugin = cls; |
2138 | struct GNUNET_TIME_Relative timeout = | ||
2139 | GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT; | ||
2140 | |||
2141 | if ((ps->direction == OUTBOUND) && | ||
2142 | (plugin->current_connections < plugin->max_connect_per_transport)) | ||
2143 | { | ||
2144 | /* RECV DIRECTION */ | ||
2145 | /* Check if session is connected to receive data, otherwise connect to peer */ | ||
2146 | |||
2147 | if (ps->recv_connected == GNUNET_NO) | ||
2148 | { | ||
2149 | int fresh = GNUNET_NO; | ||
2150 | |||
2151 | if (ps->recv_endpoint == NULL) | ||
2152 | { | ||
2153 | fresh = GNUNET_YES; | ||
2154 | ps->recv_endpoint = curl_easy_init (); | ||
2155 | } | ||
2156 | #if DEBUG_CURL | ||
2157 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_VERBOSE, 1L); | ||
2158 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_DEBUGFUNCTION, &curl_logger); | ||
2159 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_DEBUGDATA, | ||
2160 | ps->recv_endpoint); | ||
2161 | #endif | ||
2162 | #if BUILD_HTTPS | ||
2163 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSLVERSION, | ||
2164 | CURL_SSLVERSION_TLSv1); | ||
2165 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSL_VERIFYPEER, 0); | ||
2166 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSL_VERIFYHOST, 0); | ||
2167 | #endif | ||
2168 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_URL, ps->url); | ||
2169 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_HEADERFUNCTION, | ||
2170 | &curl_get_header_cb); | ||
2171 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_WRITEHEADER, ps); | ||
2172 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_READFUNCTION, curl_send_cb); | ||
2173 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_READDATA, ps); | ||
2174 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_WRITEFUNCTION, | ||
2175 | curl_receive_cb); | ||
2176 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_WRITEDATA, ps); | ||
2177 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_TIMEOUT, | ||
2178 | (long) timeout.rel_value); | ||
2179 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_PRIVATE, ps); | ||
2180 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, | ||
2181 | HTTP_CONNECT_TIMEOUT); | ||
2182 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_BUFFERSIZE, | ||
2183 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
2184 | #if CURL_TCP_NODELAY | ||
2185 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); | ||
2186 | #endif | ||
2187 | if (fresh == GNUNET_YES) | ||
2188 | { | ||
2189 | mret = curl_multi_add_handle (plugin->multi_handle, ps->recv_endpoint); | ||
2190 | if (mret != CURLM_OK) | ||
2191 | { | ||
2192 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2193 | _("Connection: %X: %s failed at %s:%d: `%s'\n"), ps, | ||
2194 | "curl_multi_add_handle", __FILE__, __LINE__, | ||
2195 | curl_multi_strerror (mret)); | ||
2196 | return GNUNET_SYSERR; | ||
2197 | } | ||
2198 | } | ||
2199 | if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK) | ||
2200 | { | ||
2201 | GNUNET_SCHEDULER_cancel (plugin->http_curl_task); | ||
2202 | plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK; | ||
2203 | } | ||
2204 | plugin->current_connections++; | ||
2205 | plugin->http_curl_task = GNUNET_SCHEDULER_add_now (&curl_perform, plugin); | ||
2206 | } | ||
2207 | |||
2208 | /* waiting for receive direction */ | ||
2209 | if (ps->recv_connected == GNUNET_NO) | ||
2210 | return GNUNET_NO; | ||
2211 | |||
2212 | /* SEND DIRECTION */ | ||
2213 | /* Check if session is connected to send data, otherwise connect to peer */ | ||
2214 | if ((ps->send_connected == GNUNET_YES) && (ps->send_endpoint != NULL)) | ||
2215 | { | ||
2216 | if (ps->send_active == GNUNET_YES) | ||
2217 | { | ||
2218 | #if DEBUG_CONNECTIONS | ||
2219 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2220 | "Connection %X: outbound active, enqueueing message\n", ps); | ||
2221 | #endif | ||
2222 | return GNUNET_YES; | ||
2223 | } | ||
2224 | if (ps->send_active == GNUNET_NO) | ||
2225 | { | ||
2226 | #if DEBUG_CONNECTIONS | ||
2227 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2228 | "Connection %X: outbound paused, unpausing existing connection and enqueueing message\n", | ||
2229 | ps); | ||
2230 | #endif | ||
2231 | if (CURLE_OK == curl_easy_pause (ps->send_endpoint, CURLPAUSE_CONT)) | ||
2232 | { | ||
2233 | ps->send_active = GNUNET_YES; | ||
2234 | if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK) | ||
2235 | { | ||
2236 | GNUNET_SCHEDULER_cancel (plugin->http_curl_task); | ||
2237 | plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK; | ||
2238 | } | ||
2239 | plugin->http_curl_task = | ||
2240 | GNUNET_SCHEDULER_add_now (&curl_perform, plugin); | ||
2241 | return GNUNET_YES; | ||
2242 | } | ||
2243 | else | ||
2244 | return GNUNET_SYSERR; | ||
2245 | } | ||
2246 | } | ||
2247 | /* not connected, initiate connection */ | ||
2248 | if ((ps->send_connected == GNUNET_NO) && | ||
2249 | (plugin->current_connections < plugin->max_connect_per_transport)) | ||
2250 | { | ||
2251 | int fresh = GNUNET_NO; | ||
2252 | |||
2253 | if (NULL == ps->send_endpoint) | ||
2254 | { | ||
2255 | ps->send_endpoint = curl_easy_init (); | ||
2256 | fresh = GNUNET_YES; | ||
2257 | } | ||
2258 | GNUNET_assert (ps->send_endpoint != NULL); | ||
2259 | GNUNET_assert (NULL != ps->pending_msgs_tail); | ||
2260 | #if DEBUG_CONNECTIONS | ||
2261 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2262 | "Connection %X: outbound not connected, initiating connection\n", | ||
2263 | ps); | ||
2264 | #endif | ||
2265 | ps->send_active = GNUNET_NO; | ||
2266 | |||
2267 | #if DEBUG_CURL | ||
2268 | curl_easy_setopt (ps->send_endpoint, CURLOPT_VERBOSE, 1L); | ||
2269 | curl_easy_setopt (ps->send_endpoint, CURLOPT_DEBUGFUNCTION, &curl_logger); | ||
2270 | curl_easy_setopt (ps->send_endpoint, CURLOPT_DEBUGDATA, | ||
2271 | ps->send_endpoint); | ||
2272 | #endif | ||
2273 | #if BUILD_HTTPS | ||
2274 | curl_easy_setopt (ps->send_endpoint, CURLOPT_SSLVERSION, | ||
2275 | CURL_SSLVERSION_TLSv1); | ||
2276 | curl_easy_setopt (ps->send_endpoint, CURLOPT_SSL_VERIFYPEER, 0); | ||
2277 | curl_easy_setopt (ps->send_endpoint, CURLOPT_SSL_VERIFYHOST, 0); | ||
2278 | #endif | ||
2279 | curl_easy_setopt (ps->send_endpoint, CURLOPT_URL, ps->url); | ||
2280 | curl_easy_setopt (ps->send_endpoint, CURLOPT_PUT, 1L); | ||
2281 | curl_easy_setopt (ps->send_endpoint, CURLOPT_HEADERFUNCTION, | ||
2282 | &curl_put_header_cb); | ||
2283 | curl_easy_setopt (ps->send_endpoint, CURLOPT_WRITEHEADER, ps); | ||
2284 | curl_easy_setopt (ps->send_endpoint, CURLOPT_READFUNCTION, curl_send_cb); | ||
2285 | curl_easy_setopt (ps->send_endpoint, CURLOPT_READDATA, ps); | ||
2286 | curl_easy_setopt (ps->send_endpoint, CURLOPT_WRITEFUNCTION, | ||
2287 | curl_receive_cb); | ||
2288 | curl_easy_setopt (ps->send_endpoint, CURLOPT_READDATA, ps); | ||
2289 | curl_easy_setopt (ps->send_endpoint, CURLOPT_TIMEOUT, | ||
2290 | (long) timeout.rel_value); | ||
2291 | curl_easy_setopt (ps->send_endpoint, CURLOPT_PRIVATE, ps); | ||
2292 | curl_easy_setopt (ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, | ||
2293 | HTTP_CONNECT_TIMEOUT); | ||
2294 | curl_easy_setopt (ps->send_endpoint, CURLOPT_BUFFERSIZE, | ||
2295 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
2296 | #if CURL_TCP_NODELAY | ||
2297 | curl_easy_setopt (ps->send_endpoint, CURLOPT_TCP_NODELAY, 1); | ||
2298 | #endif | ||
2299 | if (fresh == GNUNET_YES) | ||
2300 | { | ||
2301 | mret = curl_multi_add_handle (plugin->multi_handle, ps->send_endpoint); | ||
2302 | if (mret != CURLM_OK) | ||
2303 | { | ||
2304 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2305 | _("Connection: %X: %s failed at %s:%d: `%s'\n"), ps, | ||
2306 | "curl_multi_add_handle", __FILE__, __LINE__, | ||
2307 | curl_multi_strerror (mret)); | ||
2308 | return GNUNET_SYSERR; | ||
2309 | } | ||
2310 | } | ||
2311 | } | ||
2312 | if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK) | ||
2313 | { | ||
2314 | GNUNET_SCHEDULER_cancel (plugin->http_curl_task); | ||
2315 | plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK; | ||
2316 | } | ||
2317 | plugin->current_connections++; | ||
2318 | plugin->http_curl_task = GNUNET_SCHEDULER_add_now (&curl_perform, plugin); | ||
2319 | return GNUNET_YES; | ||
2320 | } | ||
2321 | if (ps->direction == INBOUND) | ||
2322 | { | ||
2323 | GNUNET_assert (NULL != ps->pending_msgs_tail); | ||
2324 | if ((ps->recv_connected == GNUNET_YES) && (ps->send_connected == GNUNET_YES) | ||
2325 | && (ps->recv_force_disconnect == GNUNET_NO) && | ||
2326 | (ps->recv_force_disconnect == GNUNET_NO)) | ||
2327 | return GNUNET_YES; | ||
2328 | } | ||
2329 | return GNUNET_SYSERR; | ||
2330 | } | ||
2331 | |||
2332 | |||
2333 | /** | ||
2334 | * select best session to transmit data to peer | ||
2335 | * | ||
2336 | * @param pc peer context of target peer | ||
2337 | * @param addr address of target peer | ||
2338 | * @param addrlen address length | ||
2339 | * @param force_address does transport service enforce address? | ||
2340 | * @param session session passed by transport service | ||
2341 | * @return selected session | ||
2342 | * | ||
2343 | */ | ||
2344 | static struct Session * | ||
2345 | send_select_session (struct HTTP_PeerContext *pc, const void *addr, | ||
2346 | size_t addrlen, int force_address, struct Session *session) | ||
2347 | { | ||
2348 | struct Session *tmp = NULL; | ||
2349 | int addr_given = GNUNET_NO; | ||
2350 | |||
2351 | if ((addr != NULL) && (addrlen > 0)) | ||
2352 | addr_given = GNUNET_YES; | ||
2353 | 438 | ||
2354 | if (force_address == GNUNET_YES) | 439 | plugin->env->session_end (NULL, peer, s); |
2355 | { | 440 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); |
2356 | /* check session given as argument */ | 441 | delete_session (s); |
2357 | if ((session != NULL) && (addr_given == GNUNET_YES)) | ||
2358 | { | ||
2359 | if (0 == memcmp (session->addr, addr, addrlen)) | ||
2360 | { | ||
2361 | /* connection can not be used, since it is disconnected */ | ||
2362 | if ((session->recv_force_disconnect == GNUNET_NO) && | ||
2363 | (session->send_force_disconnect == GNUNET_NO)) | ||
2364 | { | ||
2365 | #if DEBUG_SESSION_SELECTION | ||
2366 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2367 | "Session %X selected: Using session passed by transport to send to forced address \n", | ||
2368 | session); | ||
2369 | #endif | ||
2370 | return session; | ||
2371 | } | ||
2372 | } | ||
2373 | } | ||
2374 | /* check last session used */ | ||
2375 | if ((pc->last_session != NULL) && (addr_given == GNUNET_YES)) | ||
2376 | { | ||
2377 | if (0 == memcmp (pc->last_session->addr, addr, addrlen)) | ||
2378 | { | ||
2379 | /* connection can not be used, since it is disconnected */ | ||
2380 | if ((pc->last_session->recv_force_disconnect == GNUNET_NO) && | ||
2381 | (pc->last_session->send_force_disconnect == GNUNET_NO)) | ||
2382 | { | ||
2383 | #if DEBUG_SESSION_SELECTION | ||
2384 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2385 | "Session %X selected: Using last session used to send to forced address \n", | ||
2386 | pc->last_session); | ||
2387 | #endif | ||
2388 | return pc->last_session; | ||
2389 | } | ||
2390 | } | ||
2391 | } | ||
2392 | /* find session in existing sessions */ | ||
2393 | tmp = pc->head; | ||
2394 | while ((tmp != NULL) && (addr_given == GNUNET_YES)) | ||
2395 | { | ||
2396 | if (0 == memcmp (tmp->addr, addr, addrlen)) | ||
2397 | { | ||
2398 | /* connection can not be used, since it is disconnected */ | ||
2399 | if ((tmp->recv_force_disconnect == GNUNET_NO) && | ||
2400 | (tmp->send_force_disconnect == GNUNET_NO)) | ||
2401 | { | ||
2402 | #if DEBUG_SESSION_SELECTION | ||
2403 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2404 | "Session %X selected: Using existing session to send to forced address \n", | ||
2405 | session); | ||
2406 | #endif | ||
2407 | return session; | ||
2408 | } | ||
2409 | } | ||
2410 | tmp = tmp->next; | ||
2411 | } | ||
2412 | /* no session to use */ | ||
2413 | return NULL; | ||
2414 | } | ||
2415 | if ((force_address == GNUNET_NO) || (force_address == GNUNET_SYSERR)) | ||
2416 | { | ||
2417 | /* check session given as argument */ | ||
2418 | if (session != NULL) | ||
2419 | { | ||
2420 | /* connection can not be used, since it is disconnected */ | ||
2421 | if ((session->recv_force_disconnect == GNUNET_NO) && | ||
2422 | (session->send_force_disconnect == GNUNET_NO)) | ||
2423 | { | ||
2424 | #if DEBUG_SESSION_SELECTION | ||
2425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2426 | "Session %X selected: Using session passed by transport to send not-forced address\n", | ||
2427 | session); | ||
2428 | #endif | ||
2429 | return session; | ||
2430 | } | ||
2431 | } | ||
2432 | /* check last session used */ | ||
2433 | if (pc->last_session != NULL) | ||
2434 | { | ||
2435 | /* connection can not be used, since it is disconnected */ | ||
2436 | if ((pc->last_session->recv_force_disconnect == GNUNET_NO) && | ||
2437 | (pc->last_session->send_force_disconnect == GNUNET_NO)) | ||
2438 | { | ||
2439 | #if DEBUG_SESSION_SELECTION | ||
2440 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2441 | "Session %X selected: Using last session to send to not-forced address\n", | ||
2442 | pc->last_session); | ||
2443 | #endif | ||
2444 | return pc->last_session; | ||
2445 | } | ||
2446 | } | ||
2447 | /* find session in existing sessions */ | ||
2448 | tmp = pc->head; | ||
2449 | while (tmp != NULL) | ||
2450 | { | ||
2451 | /* connection can not be used, since it is disconnected */ | ||
2452 | if ((tmp->recv_force_disconnect == GNUNET_NO) && | ||
2453 | (tmp->send_force_disconnect == GNUNET_NO)) | ||
2454 | { | ||
2455 | #if DEBUG_SESSION_SELECTION | ||
2456 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2457 | "Session %X selected: Using existing session to send to not-forced address\n", | ||
2458 | tmp); | ||
2459 | #endif | ||
2460 | return tmp; | ||
2461 | } | ||
2462 | tmp = tmp->next; | ||
2463 | } | ||
2464 | return NULL; | ||
2465 | } | ||
2466 | return NULL; | ||
2467 | } | 442 | } |
2468 | 443 | ||
2469 | 444 | ||
@@ -2512,106 +487,53 @@ http_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target, | |||
2512 | { | 487 | { |
2513 | struct Plugin *plugin = cls; | 488 | struct Plugin *plugin = cls; |
2514 | struct HTTP_Message *msg; | 489 | struct HTTP_Message *msg; |
2515 | struct HTTP_PeerContext *pc; | 490 | GNUNET_assert (plugin != NULL); |
2516 | struct Session *ps = NULL; | ||
2517 | 491 | ||
2518 | GNUNET_assert (cls != NULL); | 492 | int res = GNUNET_SYSERR; |
2519 | 493 | ||
2520 | #if DEBUG_HTTP | 494 | #if DEBUG_HTTP |
2521 | char *force; | 495 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
2522 | 496 | "Sending %u bytes to peer `%s' on address `%s' %X %i\n", msgbuf_size, | |
2523 | if (force_address == GNUNET_YES) | 497 | GNUNET_i2s (target), ((addr != NULL) && (addrlen != 0)) ? http_plugin_address_to_string(plugin, addr, addrlen) : "<inbound>", session, force_address); |
2524 | GNUNET_asprintf (&force, "forced addr."); | ||
2525 | else if (force_address == GNUNET_NO) | ||
2526 | GNUNET_asprintf (&force, "any addr."); | ||
2527 | else if (force_address == GNUNET_SYSERR) | ||
2528 | GNUNET_asprintf (&force, "reliable bi-direc. address addr."); | ||
2529 | else | ||
2530 | GNUNET_assert (0); | ||
2531 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2532 | "Transport tells me to send %u bytes to `%s' using %s (%s) and session: %X\n", | ||
2533 | msgbuf_size, GNUNET_i2s (target), force, | ||
2534 | http_plugin_address_to_string (NULL, addr, addrlen), session); | ||
2535 | GNUNET_free (force); | ||
2536 | #endif | 498 | #endif |
2537 | 499 | ||
2538 | pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey); | 500 | struct Session *s = NULL; |
2539 | /* Peer unknown */ | 501 | |
2540 | if (pc == NULL) | 502 | /* look for existing connection */ |
2541 | { | 503 | s = lookup_session (plugin, target, session, addr, addrlen, 1); |
2542 | pc = GNUNET_malloc (sizeof (struct HTTP_PeerContext)); | 504 | #if DEBUG_HTTP |
2543 | pc->plugin = plugin; | 505 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
2544 | pc->session_id_counter = 1; | 506 | "%s existing session: %s\n", (s!=NULL) ? "Found" : "NOT Found", ((s != NULL) && (s->inbound == GNUNET_YES)) ? "inbound" : "outbound"); |
2545 | pc->last_session = NULL; | 507 | #endif |
2546 | memcpy (&pc->identity, target, sizeof (struct GNUNET_PeerIdentity)); | 508 | |
2547 | GNUNET_CONTAINER_multihashmap_put (plugin->peers, &pc->identity.hashPubKey, | 509 | /* create new outbound connection */ |
2548 | pc, | 510 | if (s == NULL) |
2549 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
2550 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
2551 | gettext_noop ("# HTTP peers active"), 1, | ||
2552 | GNUNET_NO); | ||
2553 | } | ||
2554 | ps = send_select_session (pc, addr, addrlen, force_address, session); | ||
2555 | /* session not existing, but address forced -> creating new session */ | ||
2556 | if (ps == NULL) | ||
2557 | { | 511 | { |
2558 | if ((addr != NULL) && (addrlen != 0)) | 512 | if (plugin->max_connections <= plugin->cur_connections) |
2559 | { | 513 | { |
2560 | ps = GNUNET_malloc (sizeof (struct Session)); | 514 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, |
2561 | #if DEBUG_SESSION_SELECTION | 515 | "Maximum number of connections reached, " |
2562 | if (force_address == GNUNET_YES) | 516 | "cannot connect to peer `%s'\n", |
2563 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 517 | GNUNET_i2s (target)); |
2564 | "No existing connection & forced address: creating new session %X to peer %s\n", | 518 | return res; |
2565 | ps, GNUNET_i2s (target)); | ||
2566 | if (force_address != GNUNET_YES) | ||
2567 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2568 | "No existing connection: creating new session %X to peer %s\n", | ||
2569 | ps, GNUNET_i2s (target)); | ||
2570 | #endif | ||
2571 | ps->addr = GNUNET_malloc (addrlen); | ||
2572 | memcpy (ps->addr, addr, addrlen); | ||
2573 | ps->addrlen = addrlen; | ||
2574 | ps->direction = OUTBOUND; | ||
2575 | ps->recv_connected = GNUNET_NO; | ||
2576 | ps->recv_force_disconnect = GNUNET_NO; | ||
2577 | ps->send_connected = GNUNET_NO; | ||
2578 | ps->send_force_disconnect = GNUNET_NO; | ||
2579 | ps->pending_msgs_head = NULL; | ||
2580 | ps->pending_msgs_tail = NULL; | ||
2581 | ps->peercontext = pc; | ||
2582 | ps->session_id = pc->session_id_counter; | ||
2583 | ps->queue_length_cur = 0; | ||
2584 | ps->queue_length_max = GNUNET_SERVER_MAX_MESSAGE_SIZE; | ||
2585 | pc->session_id_counter++; | ||
2586 | ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id); | ||
2587 | if (ps->msgtok == NULL) | ||
2588 | ps->msgtok = GNUNET_SERVER_mst_create (&curl_receive_mst_cb, ps); | ||
2589 | GNUNET_CONTAINER_DLL_insert (pc->head, pc->tail, ps); | ||
2590 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
2591 | gettext_noop | ||
2592 | ("# HTTP outbound sessions for peers active"), | ||
2593 | 1, GNUNET_NO); | ||
2594 | } | 519 | } |
2595 | else | 520 | |
2596 | { | ||
2597 | #if DEBUG_HTTP | 521 | #if DEBUG_HTTP |
2598 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 522 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
2599 | "No existing session found & and no address given: no way to send this message to peer `%s'!\n", | 523 | "Initiiating new connection to peer `%s'\n", |
2600 | GNUNET_i2s (target)); | 524 | GNUNET_i2s (target)); |
2601 | #endif | 525 | #endif |
526 | s = create_session (plugin, target, addr, addrlen, cont, cont_cls); | ||
527 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
528 | // initiate new connection | ||
529 | if (GNUNET_SYSERR == (res = client_connect (s))) | ||
530 | { | ||
531 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); | ||
532 | delete_session (s); | ||
2602 | return GNUNET_SYSERR; | 533 | return GNUNET_SYSERR; |
2603 | } | 534 | } |
2604 | } | 535 | } |
2605 | 536 | ||
2606 | if (msgbuf_size >= (ps->queue_length_max - ps->queue_length_cur)) | ||
2607 | { | ||
2608 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2609 | "Queue %X full: %u bytes in queue available, message with %u is too big\n", | ||
2610 | ps, (ps->queue_length_max - ps->queue_length_cur), msgbuf_size); | ||
2611 | //return GNUNET_SYSERR; | ||
2612 | } | ||
2613 | |||
2614 | /* create msg */ | ||
2615 | msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size); | 537 | msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size); |
2616 | msg->next = NULL; | 538 | msg->next = NULL; |
2617 | msg->size = msgbuf_size; | 539 | msg->size = msgbuf_size; |
@@ -2620,324 +542,69 @@ http_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target, | |||
2620 | msg->transmit_cont = cont; | 542 | msg->transmit_cont = cont; |
2621 | msg->transmit_cont_cls = cont_cls; | 543 | msg->transmit_cont_cls = cont_cls; |
2622 | memcpy (msg->buf, msgbuf, msgbuf_size); | 544 | memcpy (msg->buf, msgbuf, msgbuf_size); |
2623 | GNUNET_CONTAINER_DLL_insert (ps->pending_msgs_head, ps->pending_msgs_tail, | ||
2624 | msg); | ||
2625 | ps->queue_length_cur += msgbuf_size; | ||
2626 | if (send_check_connections (plugin, ps) == GNUNET_SYSERR) | ||
2627 | return GNUNET_SYSERR; | ||
2628 | if (force_address != GNUNET_YES) | ||
2629 | pc->last_session = ps; | ||
2630 | if (pc->last_session == NULL) | ||
2631 | pc->last_session = ps; | ||
2632 | return msg->size; | ||
2633 | } | ||
2634 | |||
2635 | |||
2636 | /** | ||
2637 | * Function that can be used to force the plugin to disconnect | ||
2638 | * from the given peer and cancel all previous transmissions | ||
2639 | * (and their continuationc). | ||
2640 | * | ||
2641 | * @param cls closure | ||
2642 | * @param target peer from which to disconnect | ||
2643 | */ | ||
2644 | static void | ||
2645 | http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) | ||
2646 | { | ||
2647 | struct Plugin *plugin = cls; | ||
2648 | struct HTTP_PeerContext *pc = NULL; | ||
2649 | struct Session *ps = NULL; | ||
2650 | 545 | ||
2651 | pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey); | 546 | if (s->inbound == GNUNET_NO) |
2652 | if (pc == NULL) | ||
2653 | return; | ||
2654 | ps = pc->head; | ||
2655 | while (ps != NULL) | ||
2656 | { | 547 | { |
2657 | /* Telling transport that session is getting disconnected */ | 548 | #if DEBUG_HTTP |
2658 | plugin->env->session_end (plugin, target, ps); | 549 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
2659 | if (ps->direction == OUTBOUND) | 550 | "Using outbound client session to send to `%s'\n", |
2660 | { | 551 | GNUNET_i2s (target)); |
2661 | if (ps->send_endpoint != NULL) | 552 | #endif |
2662 | { | 553 | client_send (s, msg); |
2663 | //GNUNET_assert(CURLM_OK == curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint)); | 554 | res = msgbuf_size; |
2664 | //curl_easy_cleanup(ps->send_endpoint); | ||
2665 | //ps->send_endpoint=NULL; | ||
2666 | ps->send_force_disconnect = GNUNET_YES; | ||
2667 | } | ||
2668 | if (ps->recv_endpoint != NULL) | ||
2669 | { | ||
2670 | //GNUNET_assert(CURLM_OK == curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint)); | ||
2671 | //curl_easy_cleanup(ps->recv_endpoint); | ||
2672 | //ps->recv_endpoint=NULL; | ||
2673 | ps->recv_force_disconnect = GNUNET_YES; | ||
2674 | } | ||
2675 | } | ||
2676 | if (ps->direction == INBOUND) | ||
2677 | { | ||
2678 | ps->recv_force_disconnect = GNUNET_YES; | ||
2679 | ps->send_force_disconnect = GNUNET_YES; | ||
2680 | } | ||
2681 | while (ps->pending_msgs_head != NULL) | ||
2682 | remove_http_message (ps, ps->pending_msgs_head); | ||
2683 | ps->recv_active = GNUNET_NO; | ||
2684 | ps->send_active = GNUNET_NO; | ||
2685 | ps = ps->next; | ||
2686 | } | 555 | } |
2687 | } | 556 | if (s->inbound == GNUNET_YES) |
2688 | |||
2689 | |||
2690 | /** | ||
2691 | * Append our port and forward the result. | ||
2692 | * | ||
2693 | * @param cls the 'struct PrettyPrinterContext*' | ||
2694 | * @param hostname hostname part of the address | ||
2695 | */ | ||
2696 | static void | ||
2697 | append_port (void *cls, const char *hostname) | ||
2698 | { | ||
2699 | struct PrettyPrinterContext *ppc = cls; | ||
2700 | char *ret; | ||
2701 | |||
2702 | if (hostname == NULL) | ||
2703 | { | 557 | { |
2704 | ppc->asc (ppc->asc_cls, NULL); | 558 | server_send (s, msg); |
2705 | GNUNET_free (ppc); | 559 | res = msgbuf_size; |
2706 | return; | 560 | #if DEBUG_HTTP |
2707 | } | 561 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
2708 | GNUNET_asprintf (&ret, "%s://%s:%d", PROTOCOL_PREFIX, hostname, ppc->port); | 562 | "Using inbound server session to send to `%s'\n", |
2709 | 563 | GNUNET_i2s (target)); | |
2710 | ppc->asc (ppc->asc_cls, ret); | 564 | #endif |
2711 | GNUNET_free (ret); | ||
2712 | } | ||
2713 | |||
2714 | |||
2715 | |||
2716 | /** | ||
2717 | * Convert the transports address to a nice, human-readable | ||
2718 | * format. | ||
2719 | * | ||
2720 | * @param cls closure | ||
2721 | * @param type name of the transport that generated the address | ||
2722 | * @param addr one of the addresses of the host, NULL for the last address | ||
2723 | * the specific address format depends on the transport | ||
2724 | * @param addrlen length of the address | ||
2725 | * @param numeric should (IP) addresses be displayed in numeric form? | ||
2726 | * @param timeout after how long should we give up? | ||
2727 | * @param asc function to call on each string | ||
2728 | * @param asc_cls closure for asc | ||
2729 | */ | ||
2730 | static void | ||
2731 | http_plugin_address_pretty_printer (void *cls, const char *type, | ||
2732 | const void *addr, size_t addrlen, | ||
2733 | int numeric, | ||
2734 | struct GNUNET_TIME_Relative timeout, | ||
2735 | GNUNET_TRANSPORT_AddressStringCallback asc, | ||
2736 | void *asc_cls) | ||
2737 | { | ||
2738 | struct PrettyPrinterContext *ppc; | ||
2739 | const void *sb; | ||
2740 | size_t sbs; | ||
2741 | struct sockaddr_in a4; | ||
2742 | struct sockaddr_in6 a6; | ||
2743 | const struct IPv4HttpAddress *t4; | ||
2744 | const struct IPv6HttpAddress *t6; | ||
2745 | uint16_t port; | ||
2746 | 565 | ||
2747 | if (addrlen == sizeof (struct IPv6HttpAddress)) | ||
2748 | { | ||
2749 | t6 = addr; | ||
2750 | memset (&a6, 0, sizeof (a6)); | ||
2751 | a6.sin6_family = AF_INET6; | ||
2752 | a6.sin6_port = t6->port; | ||
2753 | memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); | ||
2754 | port = ntohs (t6->port); | ||
2755 | sb = &a6; | ||
2756 | sbs = sizeof (a6); | ||
2757 | } | ||
2758 | else if (addrlen == sizeof (struct IPv4HttpAddress)) | ||
2759 | { | ||
2760 | t4 = addr; | ||
2761 | memset (&a4, 0, sizeof (a4)); | ||
2762 | a4.sin_family = AF_INET; | ||
2763 | a4.sin_port = t4->port; | ||
2764 | a4.sin_addr.s_addr = t4->ipv4_addr; | ||
2765 | port = ntohs (t4->ipv4_addr); | ||
2766 | sb = &a4; | ||
2767 | sbs = sizeof (a4); | ||
2768 | } | ||
2769 | else | ||
2770 | { | ||
2771 | /* invalid address */ | ||
2772 | GNUNET_break_op (0); | ||
2773 | asc (asc_cls, NULL); | ||
2774 | return; | ||
2775 | } | 566 | } |
2776 | ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); | 567 | return res; |
2777 | ppc->asc = asc; | ||
2778 | ppc->asc_cls = asc_cls; | ||
2779 | ppc->port = port; | ||
2780 | GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); | ||
2781 | } | 568 | } |
2782 | 569 | ||
2783 | 570 | ||
2784 | |||
2785 | /** | 571 | /** |
2786 | * Another peer has suggested an address for this | 572 | * Function that can be used to force the plugin to disconnect |
2787 | * peer and transport plugin. Check that this could be a valid | 573 | * from the given peer and cancel all previous transmissions |
2788 | * address. If so, consider adding it to the list | 574 | * (and their continuationc). |
2789 | * of addresses. | ||
2790 | * | 575 | * |
2791 | * @param cls closure | 576 | * @param cls closure |
2792 | * @param addr pointer to the address | 577 | * @param target peer from which to disconnect |
2793 | * @param addrlen length of addr | ||
2794 | * @return GNUNET_OK if this is a plausible address for this peer | ||
2795 | * and transport | ||
2796 | */ | 578 | */ |
2797 | static int | 579 | static void |
2798 | http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) | 580 | http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) |
2799 | { | 581 | { |
2800 | struct Plugin *plugin = cls; | 582 | struct Plugin *plugin = cls; |
2801 | struct IPv4HttpAddress *v4; | 583 | struct Session *next = NULL; |
2802 | struct IPv6HttpAddress *v6; | 584 | struct Session *s = plugin->head; |
2803 | struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head; | ||
2804 | struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head; | ||
2805 | 585 | ||
2806 | GNUNET_assert (cls != NULL); | 586 | while (s != NULL) |
2807 | if ((addrlen != sizeof (struct IPv4HttpAddress)) && | ||
2808 | (addrlen != sizeof (struct IPv6HttpAddress))) | ||
2809 | return GNUNET_SYSERR; | ||
2810 | if (addrlen == sizeof (struct IPv4HttpAddress)) | ||
2811 | { | ||
2812 | v4 = (struct IPv4HttpAddress *) addr; | ||
2813 | if (plugin->bind4_address != NULL) | ||
2814 | { | ||
2815 | if (0 == | ||
2816 | memcmp (&plugin->bind4_address->sin_addr, &v4->ipv4_addr, | ||
2817 | sizeof (uint32_t))) | ||
2818 | return GNUNET_OK; | ||
2819 | else | ||
2820 | return GNUNET_SYSERR; | ||
2821 | } | ||
2822 | while (w_tv4 != NULL) | ||
2823 | { | ||
2824 | if (0 == | ||
2825 | memcmp (&w_tv4->addr->ipv4_addr, &v4->ipv4_addr, sizeof (uint32_t))) | ||
2826 | break; | ||
2827 | w_tv4 = w_tv4->next; | ||
2828 | } | ||
2829 | if (w_tv4 != NULL) | ||
2830 | return GNUNET_OK; | ||
2831 | else | ||
2832 | return GNUNET_SYSERR; | ||
2833 | } | ||
2834 | if (addrlen == sizeof (struct IPv6HttpAddress)) | ||
2835 | { | 587 | { |
2836 | v6 = (struct IPv6HttpAddress *) addr; | 588 | next = s->next; |
2837 | if (plugin->bind6_address != NULL) | 589 | if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity))) |
2838 | { | 590 | { |
2839 | if (0 == | 591 | if (s->inbound == GNUNET_NO) |
2840 | memcmp (&plugin->bind6_address->sin6_addr, &v6->ipv6_addr, | 592 | GNUNET_assert (GNUNET_OK == client_disconnect (s)); |
2841 | sizeof (struct in6_addr))) | ||
2842 | return GNUNET_OK; | ||
2843 | else | 593 | else |
2844 | return GNUNET_SYSERR; | 594 | GNUNET_assert (GNUNET_OK == server_disconnect (s)); |
595 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); | ||
596 | delete_session (s); | ||
2845 | } | 597 | } |
2846 | while (w_tv6 != NULL) | 598 | s = next; |
2847 | { | ||
2848 | if (0 == | ||
2849 | memcmp (&w_tv6->addr->ipv6_addr, &v6->ipv6_addr, | ||
2850 | sizeof (struct in6_addr))) | ||
2851 | break; | ||
2852 | w_tv6 = w_tv6->next; | ||
2853 | } | ||
2854 | if (w_tv6 != NULL) | ||
2855 | return GNUNET_OK; | ||
2856 | else | ||
2857 | return GNUNET_SYSERR; | ||
2858 | } | ||
2859 | return GNUNET_SYSERR; | ||
2860 | } | ||
2861 | |||
2862 | |||
2863 | /** | ||
2864 | * Function called for a quick conversion of the binary address to | ||
2865 | * a numeric address. Note that the caller must not free the | ||
2866 | * address and that the next call to this function is allowed | ||
2867 | * to override the address again. | ||
2868 | * | ||
2869 | * @param cls closure | ||
2870 | * @param addr binary address | ||
2871 | * @param addrlen length of the address | ||
2872 | * @return string representing the same address | ||
2873 | */ | ||
2874 | static const char * | ||
2875 | http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) | ||
2876 | { | ||
2877 | const struct IPv4HttpAddress *t4; | ||
2878 | const struct IPv6HttpAddress *t6; | ||
2879 | struct sockaddr_in a4; | ||
2880 | struct sockaddr_in6 a6; | ||
2881 | char *address; | ||
2882 | static char rbuf[INET6_ADDRSTRLEN + 13]; | ||
2883 | uint16_t port; | ||
2884 | int res; | ||
2885 | |||
2886 | if (addrlen == sizeof (struct IPv6HttpAddress)) | ||
2887 | { | ||
2888 | address = GNUNET_malloc (INET6_ADDRSTRLEN); | ||
2889 | t6 = addr; | ||
2890 | a6.sin6_addr = t6->ipv6_addr; | ||
2891 | inet_ntop (AF_INET6, &(a6.sin6_addr), address, INET6_ADDRSTRLEN); | ||
2892 | port = ntohs (t6->port); | ||
2893 | } | ||
2894 | else if (addrlen == sizeof (struct IPv4HttpAddress)) | ||
2895 | { | ||
2896 | address = GNUNET_malloc (INET_ADDRSTRLEN); | ||
2897 | t4 = addr; | ||
2898 | a4.sin_addr.s_addr = t4->ipv4_addr; | ||
2899 | inet_ntop (AF_INET, &(a4.sin_addr), address, INET_ADDRSTRLEN); | ||
2900 | port = ntohs (t4->port); | ||
2901 | } | ||
2902 | else | ||
2903 | { | ||
2904 | /* invalid address */ | ||
2905 | return NULL; | ||
2906 | } | 599 | } |
2907 | |||
2908 | res = GNUNET_snprintf (rbuf, sizeof (rbuf), | ||
2909 | (addrlen == sizeof (struct IPv6HttpAddress)) ? "[%s]:%u" : "%s:%u", | ||
2910 | address, port); | ||
2911 | |||
2912 | GNUNET_free (address); | ||
2913 | GNUNET_assert (res != 0); | ||
2914 | return rbuf; | ||
2915 | } | 600 | } |
2916 | 601 | ||
2917 | /** | ||
2918 | * Function called by the NAT subsystem suggesting another peer wants | ||
2919 | * to connect to us via connection reversal. Try to connect back to the | ||
2920 | * given IP. | ||
2921 | * | ||
2922 | * @param cls closure | ||
2923 | * @param addr address to try | ||
2924 | * @param addrlen number of bytes in addr | ||
2925 | */ | ||
2926 | static void | 602 | static void |
2927 | try_connection_reversal (void *cls, const struct sockaddr *addr, | 603 | nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, |
2928 | socklen_t addrlen) | 604 | socklen_t addrlen) |
2929 | { | ||
2930 | |||
2931 | } | ||
2932 | |||
2933 | static void | ||
2934 | tcp_nat_cb_add_addr (void *cls, int add_remove, const struct sockaddr *addr, | ||
2935 | socklen_t addrlen) | ||
2936 | { | 605 | { |
2937 | struct Plugin *plugin = cls; | 606 | struct Plugin *plugin = cls; |
2938 | struct IPv4HttpAddress *t4 = NULL; | ||
2939 | struct IPv4HttpAddressWrapper *w_t4 = NULL; | 607 | struct IPv4HttpAddressWrapper *w_t4 = NULL; |
2940 | struct IPv6HttpAddress *t6 = NULL; | ||
2941 | struct IPv6HttpAddressWrapper *w_t6 = NULL; | 608 | struct IPv6HttpAddressWrapper *w_t6 = NULL; |
2942 | int af; | 609 | int af; |
2943 | 610 | ||
@@ -2948,9 +615,9 @@ tcp_nat_cb_add_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
2948 | w_t4 = plugin->ipv4_addr_head; | 615 | w_t4 = plugin->ipv4_addr_head; |
2949 | while (w_t4 != NULL) | 616 | while (w_t4 != NULL) |
2950 | { | 617 | { |
2951 | int res = memcmp (&w_t4->addr->ipv4_addr, | 618 | int res = memcmp (&w_t4->addr, |
2952 | &((struct sockaddr_in *) addr)->sin_addr, | 619 | (struct sockaddr_in *) addr, |
2953 | sizeof (struct in_addr)); | 620 | sizeof (struct sockaddr_in)); |
2954 | 621 | ||
2955 | if (0 == res) | 622 | if (0 == res) |
2956 | break; | 623 | break; |
@@ -2959,27 +626,27 @@ tcp_nat_cb_add_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
2959 | if (w_t4 == NULL) | 626 | if (w_t4 == NULL) |
2960 | { | 627 | { |
2961 | w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); | 628 | w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); |
2962 | t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddress)); | 629 | memcpy (&w_t4->addr, (struct sockaddr_in *) addr, |
2963 | memcpy (&t4->ipv4_addr, &((struct sockaddr_in *) addr)->sin_addr, | 630 | sizeof (struct sockaddr_in)); |
2964 | sizeof (struct in_addr)); | ||
2965 | t4->port = htons (plugin->port_inbound); | ||
2966 | |||
2967 | w_t4->addr = t4; | ||
2968 | 631 | ||
2969 | GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, | 632 | GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, |
2970 | plugin->ipv4_addr_tail, w_t4); | 633 | plugin->ipv4_addr_tail, w_t4); |
2971 | } | 634 | } |
2972 | plugin->env->notify_address (plugin->env->cls, add_remove, w_t4->addr, | 635 | #if DEBUG_HTTP |
2973 | sizeof (struct IPv4HttpAddress)); | 636 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
637 | "Notifying transport to add IPv4 address `%s'\n", | ||
638 | http_plugin_address_to_string(NULL, &w_t4->addr, sizeof (struct sockaddr_in))); | ||
639 | #endif | ||
640 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, sizeof (struct sockaddr_in)); | ||
2974 | 641 | ||
2975 | break; | 642 | break; |
2976 | case AF_INET6: | 643 | case AF_INET6: |
2977 | w_t6 = plugin->ipv6_addr_head; | 644 | w_t6 = plugin->ipv6_addr_head; |
2978 | while (w_t6) | 645 | while (w_t6) |
2979 | { | 646 | { |
2980 | int res = memcmp (&w_t6->addr->ipv6_addr, | 647 | int res = memcmp (&w_t6->addr, |
2981 | &((struct sockaddr_in6 *) addr)->sin6_addr, | 648 | (struct sockaddr_in6 *) addr, |
2982 | sizeof (struct in6_addr)); | 649 | sizeof (struct sockaddr_in6)); |
2983 | 650 | ||
2984 | if (0 == res) | 651 | if (0 == res) |
2985 | break; | 652 | break; |
@@ -2988,19 +655,18 @@ tcp_nat_cb_add_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
2988 | if (w_t6 == NULL) | 655 | if (w_t6 == NULL) |
2989 | { | 656 | { |
2990 | w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); | 657 | w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); |
2991 | t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddress)); | 658 | memcpy (&w_t6->addr, (struct sockaddr_in6 *) addr, |
2992 | 659 | sizeof (struct sockaddr_in6)); | |
2993 | memcpy (&t6->ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
2994 | sizeof (struct in6_addr)); | ||
2995 | t6->port = htons (plugin->port_inbound); | ||
2996 | |||
2997 | w_t6->addr = t6; | ||
2998 | 660 | ||
2999 | GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, | 661 | GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, |
3000 | plugin->ipv6_addr_tail, w_t6); | 662 | plugin->ipv6_addr_tail, w_t6); |
3001 | } | 663 | } |
3002 | plugin->env->notify_address (plugin->env->cls, add_remove, w_t6->addr, | 664 | #if DEBUG_HTTP |
3003 | sizeof (struct IPv6HttpAddress)); | 665 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
666 | "Notifying transport to add IPv6 address `%s'\n", | ||
667 | http_plugin_address_to_string(NULL, &w_t6->addr, sizeof (struct sockaddr_in6))); | ||
668 | #endif | ||
669 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr, sizeof (struct sockaddr_in6)); | ||
3004 | break; | 670 | break; |
3005 | default: | 671 | default: |
3006 | return; | 672 | return; |
@@ -3009,8 +675,8 @@ tcp_nat_cb_add_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
3009 | } | 675 | } |
3010 | 676 | ||
3011 | static void | 677 | static void |
3012 | tcp_nat_cb_remove_addr (void *cls, int add_remove, const struct sockaddr *addr, | 678 | nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, |
3013 | socklen_t addrlen) | 679 | socklen_t addrlen) |
3014 | { | 680 | { |
3015 | struct Plugin *plugin = cls; | 681 | struct Plugin *plugin = cls; |
3016 | struct IPv4HttpAddressWrapper *w_t4 = NULL; | 682 | struct IPv4HttpAddressWrapper *w_t4 = NULL; |
@@ -3024,7 +690,7 @@ tcp_nat_cb_remove_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
3024 | w_t4 = plugin->ipv4_addr_head; | 690 | w_t4 = plugin->ipv4_addr_head; |
3025 | while (w_t4 != NULL) | 691 | while (w_t4 != NULL) |
3026 | { | 692 | { |
3027 | int res = memcmp (&w_t4->addr->ipv4_addr, | 693 | int res = memcmp (&(w_t4->addr.sin_addr), |
3028 | &((struct sockaddr_in *) addr)->sin_addr, | 694 | &((struct sockaddr_in *) addr)->sin_addr, |
3029 | sizeof (struct in_addr)); | 695 | sizeof (struct in_addr)); |
3030 | 696 | ||
@@ -3034,19 +700,24 @@ tcp_nat_cb_remove_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
3034 | } | 700 | } |
3035 | if (w_t4 == NULL) | 701 | if (w_t4 == NULL) |
3036 | return; | 702 | return; |
3037 | plugin->env->notify_address (plugin->env->cls, add_remove, w_t4->addr, | 703 | |
3038 | sizeof (struct IPv4HttpAddress)); | 704 | #if DEBUG_HTTP |
705 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
706 | "Notifying transport to remove IPv4 address `%s'\n", | ||
707 | http_plugin_address_to_string(NULL, &w_t4->addr, sizeof (struct sockaddr_in))); | ||
708 | #endif | ||
709 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, | ||
710 | sizeof (struct sockaddr_in)); | ||
3039 | 711 | ||
3040 | GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, | 712 | GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, |
3041 | w_t4); | 713 | w_t4); |
3042 | GNUNET_free (w_t4->addr); | ||
3043 | GNUNET_free (w_t4); | 714 | GNUNET_free (w_t4); |
3044 | break; | 715 | break; |
3045 | case AF_INET6: | 716 | case AF_INET6: |
3046 | w_t6 = plugin->ipv6_addr_head; | 717 | w_t6 = plugin->ipv6_addr_head; |
3047 | while (w_t6 != NULL) | 718 | while (w_t6 != NULL) |
3048 | { | 719 | { |
3049 | int res = memcmp (&w_t6->addr->ipv6_addr, | 720 | int res = memcmp (&(w_t6->addr.sin6_addr), |
3050 | &((struct sockaddr_in6 *) addr)->sin6_addr, | 721 | &((struct sockaddr_in6 *) addr)->sin6_addr, |
3051 | sizeof (struct in6_addr)); | 722 | sizeof (struct in6_addr)); |
3052 | 723 | ||
@@ -3056,12 +727,16 @@ tcp_nat_cb_remove_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
3056 | } | 727 | } |
3057 | if (w_t6 == NULL) | 728 | if (w_t6 == NULL) |
3058 | return; | 729 | return; |
3059 | plugin->env->notify_address (plugin->env->cls, add_remove, w_t6->addr, | 730 | #if DEBUG_HTTP |
3060 | sizeof (struct IPv6HttpAddress)); | 731 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
732 | "Notifying transport to remove IPv6 address `%s'\n", | ||
733 | http_plugin_address_to_string(NULL, &w_t6->addr, sizeof (struct sockaddr_in6))); | ||
734 | #endif | ||
735 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr, | ||
736 | sizeof (struct sockaddr_in6 )); | ||
3061 | 737 | ||
3062 | GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, | 738 | GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, |
3063 | w_t6); | 739 | w_t6); |
3064 | GNUNET_free (w_t6->addr); | ||
3065 | GNUNET_free (w_t6); | 740 | GNUNET_free (w_t6); |
3066 | break; | 741 | break; |
3067 | default: | 742 | default: |
@@ -3080,71 +755,97 @@ tcp_nat_cb_remove_addr (void *cls, int add_remove, const struct sockaddr *addr, | |||
3080 | * @param addrlen actual lenght of the address | 755 | * @param addrlen actual lenght of the address |
3081 | */ | 756 | */ |
3082 | static void | 757 | static void |
3083 | tcp_nat_port_map_callback (void *cls, int add_remove, | 758 | nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, |
3084 | const struct sockaddr *addr, socklen_t addrlen) | 759 | socklen_t addrlen) |
3085 | { | 760 | { |
3086 | GNUNET_assert (cls != NULL); | 761 | GNUNET_assert (cls != NULL); |
3087 | #if DEBUG_HTTP | 762 | #if DEBUG_HTTP |
3088 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NPMC called to %s address `%s'\n", | 763 | struct Plugin *plugin = cls; |
3089 | (add_remove == GNUNET_YES) ? "remove" : "add", | 764 | #endif |
765 | static int limit; | ||
766 | #if DEBUG_HTTP | ||
767 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
768 | "NPMC called %s to address `%s'\n", | ||
769 | (add_remove == GNUNET_NO) ? "remove" : "add", | ||
3090 | GNUNET_a2s (addr, addrlen)); | 770 | GNUNET_a2s (addr, addrlen)); |
3091 | #endif | 771 | #endif |
3092 | /* convert 'addr' to our internal format */ | 772 | /* convert 'addr' to our internal format */ |
3093 | switch (add_remove) | 773 | switch (add_remove) |
3094 | { | 774 | { |
3095 | case GNUNET_YES: | 775 | case GNUNET_YES: |
3096 | tcp_nat_cb_add_addr (cls, add_remove, addr, addrlen); | 776 | // FIXME DEBUGGING |
777 | if (limit < 1) | ||
778 | nat_add_address (cls, add_remove, addr, addrlen); | ||
779 | limit++; | ||
780 | // FIXME END | ||
3097 | break; | 781 | break; |
3098 | case GNUNET_NO: | 782 | case GNUNET_NO: |
3099 | tcp_nat_cb_remove_addr (cls, add_remove, addr, addrlen); | 783 | nat_remove_address (cls, add_remove, addr, addrlen); |
3100 | break; | 784 | break; |
3101 | } | 785 | } |
3102 | } | 786 | } |
3103 | 787 | ||
3104 | /** | ||
3105 | * Exit point from the plugin. | ||
3106 | */ | ||
3107 | void * | ||
3108 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) | ||
3109 | { | ||
3110 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | ||
3111 | struct Plugin *plugin = api->cls; | ||
3112 | CURLMcode mret; | ||
3113 | struct IPv4HttpAddressWrapper *w_t4; | ||
3114 | struct IPv6HttpAddressWrapper *w_t6; | ||
3115 | 788 | ||
3116 | GNUNET_assert (cls != NULL); | 789 | static void |
790 | start_report_addresses (struct Plugin *plugin) | ||
791 | { | ||
792 | int res = GNUNET_OK; | ||
793 | struct sockaddr **addrs; | ||
794 | socklen_t *addrlens; | ||
3117 | 795 | ||
3118 | if (plugin->nat != NULL) | 796 | res = |
3119 | GNUNET_NAT_unregister (plugin->nat); | 797 | GNUNET_SERVICE_get_server_addresses (plugin->name, plugin->env->cfg, |
798 | &addrs, &addrlens); | ||
799 | #if 0 | ||
800 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
801 | _("FOUND %u addresses\n"),res); | ||
802 | #endif | ||
3120 | 803 | ||
3121 | if (plugin->http_server_daemon_v4 != NULL) | 804 | if (res != GNUNET_SYSERR) |
3122 | { | ||
3123 | MHD_stop_daemon (plugin->http_server_daemon_v4); | ||
3124 | plugin->http_server_daemon_v4 = NULL; | ||
3125 | } | ||
3126 | if (plugin->http_server_daemon_v6 != NULL) | ||
3127 | { | 805 | { |
3128 | MHD_stop_daemon (plugin->http_server_daemon_v6); | 806 | plugin->nat = |
3129 | plugin->http_server_daemon_v6 = NULL; | 807 | GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, |
3130 | } | 808 | (unsigned int) res, |
3131 | if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK) | 809 | (const struct sockaddr **) addrs, addrlens, |
3132 | { | 810 | &nat_port_map_callback, NULL, |
3133 | GNUNET_SCHEDULER_cancel (plugin->http_server_task_v4); | 811 | plugin); |
3134 | plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK; | 812 | while (res > 0) |
813 | { | ||
814 | res--; | ||
815 | #if 0 | ||
816 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
817 | _("FREEING %s\n"), | ||
818 | GNUNET_a2s (addrs[res], addrlens[res])); | ||
819 | #endif | ||
820 | GNUNET_assert (addrs[res] != NULL); | ||
821 | GNUNET_free (addrs[res]); | ||
822 | } | ||
823 | GNUNET_free_non_null (addrs); | ||
824 | GNUNET_free_non_null (addrlens); | ||
3135 | } | 825 | } |
3136 | if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) | 826 | else |
3137 | { | 827 | { |
3138 | GNUNET_SCHEDULER_cancel (plugin->http_server_task_v6); | 828 | plugin->nat = |
3139 | plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK; | 829 | GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL, |
830 | NULL, NULL, plugin); | ||
3140 | } | 831 | } |
832 | } | ||
833 | |||
834 | static void | ||
835 | stop_report_addresses (struct Plugin *plugin) | ||
836 | { | ||
837 | /* Stop NAT handle */ | ||
838 | GNUNET_NAT_unregister (plugin->nat); | ||
839 | |||
840 | /* Clean up addresses */ | ||
841 | struct IPv4HttpAddressWrapper *w_t4; | ||
842 | struct IPv6HttpAddressWrapper *w_t6; | ||
3141 | 843 | ||
3142 | while (plugin->ipv4_addr_head != NULL) | 844 | while (plugin->ipv4_addr_head != NULL) |
3143 | { | 845 | { |
3144 | w_t4 = plugin->ipv4_addr_head; | 846 | w_t4 = plugin->ipv4_addr_head; |
3145 | GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, | 847 | GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, |
3146 | w_t4); | 848 | w_t4); |
3147 | GNUNET_free (w_t4->addr); | ||
3148 | GNUNET_free (w_t4); | 849 | GNUNET_free (w_t4); |
3149 | } | 850 | } |
3150 | 851 | ||
@@ -3153,84 +854,126 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) | |||
3153 | w_t6 = plugin->ipv6_addr_head; | 854 | w_t6 = plugin->ipv6_addr_head; |
3154 | GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, | 855 | GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, |
3155 | w_t6); | 856 | w_t6); |
3156 | GNUNET_free (w_t6->addr); | ||
3157 | GNUNET_free (w_t6); | 857 | GNUNET_free (w_t6); |
3158 | } | 858 | } |
859 | } | ||
3159 | 860 | ||
3160 | /* free all peer information */ | 861 | static int |
3161 | if (plugin->peers != NULL) | 862 | configure_plugin (struct Plugin *plugin) |
863 | { | ||
864 | int res = GNUNET_OK; | ||
865 | |||
866 | /* Use IPv4? */ | ||
867 | if (GNUNET_CONFIGURATION_have_value | ||
868 | (plugin->env->cfg, plugin->name, "USE_IPv4")) | ||
3162 | { | 869 | { |
3163 | GNUNET_CONTAINER_multihashmap_iterate (plugin->peers, | 870 | plugin->ipv4 = |
3164 | &remove_peer_context_Iterator, | 871 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, |
3165 | plugin); | 872 | "USE_IPv4"); |
3166 | GNUNET_CONTAINER_multihashmap_destroy (plugin->peers); | ||
3167 | } | 873 | } |
3168 | if (plugin->multi_handle != NULL) | 874 | else |
875 | plugin->ipv4 = GNUNET_YES; | ||
876 | |||
877 | /* Use IPv6? */ | ||
878 | if (GNUNET_CONFIGURATION_have_value | ||
879 | (plugin->env->cfg, plugin->name, "USE_IPv6")) | ||
3169 | { | 880 | { |
3170 | mret = curl_multi_cleanup (plugin->multi_handle); | 881 | plugin->ipv6 = |
3171 | if (CURLM_OK != mret) | 882 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, |
3172 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 883 | "USE_IPv6"); |
3173 | "curl multihandle clean up failed\n"); | ||
3174 | plugin->multi_handle = NULL; | ||
3175 | } | 884 | } |
3176 | curl_global_cleanup (); | 885 | else |
886 | plugin->ipv6 = GNUNET_YES; | ||
3177 | 887 | ||
3178 | if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK) | 888 | if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO)) |
3179 | { | 889 | { |
3180 | GNUNET_SCHEDULER_cancel (plugin->http_curl_task); | 890 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, |
3181 | plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK; | 891 | _ |
892 | ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"), | ||
893 | plugin->name); | ||
894 | res = GNUNET_SYSERR; | ||
3182 | } | 895 | } |
3183 | 896 | ||
897 | /* Reading port number from config file */ | ||
898 | unsigned long long port; | ||
3184 | 899 | ||
3185 | GNUNET_free_non_null (plugin->bind4_address); | 900 | if ((GNUNET_OK != |
3186 | GNUNET_free_non_null (plugin->bind6_address); | 901 | GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, |
3187 | GNUNET_free_non_null (plugin->bind_hostname); | 902 | "PORT", &port)) || (port > 65535)) |
3188 | #if BUILD_HTTPS | 903 | { |
3189 | GNUNET_free_non_null (plugin->crypto_init); | 904 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, |
3190 | GNUNET_free_non_null (plugin->cert); | 905 | _("Port is required! Fix in configuration\n"), |
3191 | GNUNET_free_non_null (plugin->key); | 906 | plugin->name); |
3192 | #endif | 907 | res = GNUNET_SYSERR; |
3193 | GNUNET_free (plugin); | 908 | goto fail; |
3194 | GNUNET_free (api); | 909 | } |
3195 | #if DEBUG_HTTP | 910 | plugin->port = port; |
3196 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unload %s plugin complete...\n", | ||
3197 | PROTOCOL_PREFIX); | ||
3198 | #endif | ||
3199 | return NULL; | ||
3200 | } | ||
3201 | 911 | ||
3202 | #if BUILD_HTTPS | ||
3203 | static char * | ||
3204 | load_certificate (const char *file) | ||
3205 | { | ||
3206 | struct GNUNET_DISK_FileHandle *gn_file; | ||
3207 | struct stat fstat; | ||
3208 | char *text = NULL; | ||
3209 | 912 | ||
3210 | if (0 != STAT (file, &fstat)) | 913 | char * bind4_address = NULL; |
3211 | return NULL; | 914 | if ((plugin->ipv4 == GNUNET_YES) && (GNUNET_YES == |
3212 | text = GNUNET_malloc (fstat.st_size + 1); | 915 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, |
3213 | gn_file = | 916 | "BINDTO", &bind4_address))) |
3214 | GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, | ||
3215 | GNUNET_DISK_PERM_USER_READ); | ||
3216 | if (gn_file == NULL) | ||
3217 | { | 917 | { |
3218 | GNUNET_free (text); | 918 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
3219 | return NULL; | 919 | "Binding %s plugin to specific IPv4 address: `%s'\n", |
920 | plugin->protocol, bind4_address); | ||
921 | plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); | ||
922 | if (1 != inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr)) | ||
923 | { | ||
924 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
925 | _("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), | ||
926 | bind4_address, plugin->protocol); | ||
927 | GNUNET_free (plugin->server_addr_v4); | ||
928 | plugin->server_addr_v4 = NULL; | ||
929 | } | ||
930 | else | ||
931 | { | ||
932 | plugin->server_addr_v4->sin_family = AF_INET; | ||
933 | plugin->server_addr_v4->sin_port = htons (plugin->port); | ||
934 | } | ||
935 | GNUNET_free (bind4_address); | ||
3220 | } | 936 | } |
3221 | if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size)) | 937 | |
938 | |||
939 | char * bind6_address = NULL; | ||
940 | if ((plugin->ipv6 == GNUNET_YES) && (GNUNET_YES == | ||
941 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, | ||
942 | "BINDTO6", &bind6_address))) | ||
3222 | { | 943 | { |
3223 | GNUNET_free (text); | 944 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
3224 | GNUNET_DISK_file_close (gn_file); | 945 | "Binding %s plugin to specific IPv6 address: `%s'\n", |
3225 | return NULL; | 946 | plugin->protocol, bind6_address); |
947 | plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6)); | ||
948 | if (1 != inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr)) | ||
949 | { | ||
950 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
951 | _("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), | ||
952 | bind6_address, plugin->protocol); | ||
953 | GNUNET_free (plugin->server_addr_v6); | ||
954 | plugin->server_addr_v6 = NULL; | ||
955 | } | ||
956 | else | ||
957 | { | ||
958 | plugin->server_addr_v6->sin6_family = AF_INET6; | ||
959 | plugin->server_addr_v6->sin6_port = htons (plugin->port); | ||
960 | } | ||
961 | GNUNET_free (bind6_address); | ||
3226 | } | 962 | } |
3227 | text[fstat.st_size] = '\0'; | ||
3228 | GNUNET_DISK_file_close (gn_file); | ||
3229 | return text; | ||
3230 | } | ||
3231 | #endif | ||
3232 | 963 | ||
3233 | 964 | ||
965 | /* Optional parameters */ | ||
966 | unsigned long long maxneigh; | ||
967 | if (GNUNET_OK != | ||
968 | GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, | ||
969 | "MAX_CONNECTIONS", &maxneigh)) | ||
970 | maxneigh = 128; | ||
971 | plugin->max_connections = maxneigh; | ||
972 | |||
973 | fail: | ||
974 | return res; | ||
975 | } | ||
976 | |||
3234 | /** | 977 | /** |
3235 | * Entry point for the plugin. | 978 | * Entry point for the plugin. |
3236 | */ | 979 | */ |
@@ -3238,38 +981,12 @@ void * | |||
3238 | LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) | 981 | LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) |
3239 | { | 982 | { |
3240 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; | 983 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; |
3241 | struct Plugin *plugin; | ||
3242 | struct GNUNET_TRANSPORT_PluginFunctions *api; | 984 | struct GNUNET_TRANSPORT_PluginFunctions *api; |
3243 | struct GNUNET_TIME_Relative gn_timeout; | 985 | struct Plugin *plugin; |
3244 | long long unsigned int port; | 986 | int res; |
3245 | unsigned long long tneigh; | ||
3246 | struct sockaddr **addrs; | ||
3247 | socklen_t *addrlens; | ||
3248 | int ret; | ||
3249 | char *component_name; | ||
3250 | |||
3251 | #if BUILD_HTTPS | ||
3252 | char *key_file = NULL; | ||
3253 | char *cert_file = NULL; | ||
3254 | #endif | ||
3255 | |||
3256 | GNUNET_assert (cls != NULL); | ||
3257 | #if DEBUG_HTTP | ||
3258 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting %s plugin...\n", | ||
3259 | PROTOCOL_PREFIX); | ||
3260 | #endif | ||
3261 | GNUNET_asprintf (&component_name, "transport-%s", PROTOCOL_PREFIX); | ||
3262 | 987 | ||
3263 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | 988 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
3264 | plugin->stats = env->stats; | ||
3265 | plugin->env = env; | 989 | plugin->env = env; |
3266 | plugin->peers = NULL; | ||
3267 | plugin->bind4_address = NULL; | ||
3268 | plugin->bind6_address = NULL; | ||
3269 | plugin->use_ipv6 = GNUNET_YES; | ||
3270 | plugin->use_ipv4 = GNUNET_YES; | ||
3271 | plugin->use_localaddresses = GNUNET_NO; | ||
3272 | |||
3273 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 990 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
3274 | api->cls = plugin; | 991 | api->cls = plugin; |
3275 | api->send = &http_plugin_send; | 992 | api->send = &http_plugin_send; |
@@ -3278,392 +995,120 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) | |||
3278 | api->check_address = &http_plugin_address_suggested; | 995 | api->check_address = &http_plugin_address_suggested; |
3279 | api->address_to_string = &http_plugin_address_to_string; | 996 | api->address_to_string = &http_plugin_address_to_string; |
3280 | 997 | ||
3281 | /* Hashing our identity to use it in URLs */ | 998 | #if BUILD_HTTPS |
3282 | GNUNET_CRYPTO_hash_to_enc (&(plugin->env->my_identity->hashPubKey), | 999 | plugin->name = "transport-https"; |
3283 | &plugin->my_ascii_hash_ident); | 1000 | plugin->protocol = "https"; |
3284 | 1001 | #else | |
3285 | 1002 | plugin->name = "transport-http"; | |
3286 | if (GNUNET_OK != | 1003 | plugin->protocol = "http"; |
3287 | GNUNET_CONFIGURATION_get_value_number (env->cfg, component_name, | 1004 | #endif |
3288 | "MAX_CONNECTIONS", &tneigh)) | 1005 | /* Configure plugin from configuration */ |
3289 | tneigh = 128; | ||
3290 | plugin->max_connect_per_transport = tneigh; | ||
3291 | |||
3292 | |||
3293 | /* Use IPv6? */ | ||
3294 | if (GNUNET_CONFIGURATION_have_value (env->cfg, component_name, "USE_IPv6")) | ||
3295 | { | ||
3296 | plugin->use_ipv6 = | ||
3297 | GNUNET_CONFIGURATION_get_value_yesno (env->cfg, component_name, | ||
3298 | "USE_IPv6"); | ||
3299 | } | ||
3300 | /* Use IPv4? */ | ||
3301 | if (GNUNET_CONFIGURATION_have_value (env->cfg, component_name, "USE_IPv4")) | ||
3302 | { | ||
3303 | plugin->use_ipv4 = | ||
3304 | GNUNET_CONFIGURATION_get_value_yesno (env->cfg, component_name, | ||
3305 | "USE_IPv4"); | ||
3306 | } | ||
3307 | /* use local addresses? */ | ||
3308 | 1006 | ||
3309 | if (GNUNET_CONFIGURATION_have_value | 1007 | res = configure_plugin (plugin); |
3310 | (env->cfg, component_name, "USE_LOCALADDR")) | 1008 | if (res == GNUNET_SYSERR) |
3311 | { | ||
3312 | plugin->use_localaddresses = | ||
3313 | GNUNET_CONFIGURATION_get_value_yesno (env->cfg, component_name, | ||
3314 | "USE_LOCALADDR"); | ||
3315 | } | ||
3316 | /* Reading port number from config file */ | ||
3317 | if ((GNUNET_OK != | ||
3318 | GNUNET_CONFIGURATION_get_value_number (env->cfg, component_name, "PORT", | ||
3319 | &port)) || (port > 65535)) | ||
3320 | { | 1009 | { |
3321 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, component_name, | 1010 | GNUNET_free_non_null (plugin->server_addr_v4); |
3322 | _ | 1011 | GNUNET_free_non_null (plugin->server_addr_v6); |
3323 | ("Require valid port number for transport plugin `%s' in configuration!\n"), | 1012 | GNUNET_free (plugin); |
3324 | PROTOCOL_PREFIX); | 1013 | GNUNET_free (api); |
3325 | GNUNET_free (component_name); | ||
3326 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3327 | return NULL; | 1014 | return NULL; |
3328 | } | 1015 | } |
3329 | 1016 | ||
3330 | /* Reading ipv4 addresse to bind to from config file */ | 1017 | /* Start client */ |
3331 | if ((plugin->use_ipv4 == GNUNET_YES) && | 1018 | res = client_start (plugin); |
3332 | (GNUNET_CONFIGURATION_have_value (env->cfg, component_name, "BINDTO4"))) | 1019 | if (res == GNUNET_SYSERR) |
3333 | { | 1020 | { |
3334 | GNUNET_break (GNUNET_OK == | 1021 | GNUNET_free_non_null (plugin->server_addr_v4); |
3335 | GNUNET_CONFIGURATION_get_value_string (env->cfg, | 1022 | GNUNET_free_non_null (plugin->server_addr_v6); |
3336 | component_name, | 1023 | GNUNET_free (plugin); |
3337 | "BINDTO4", | 1024 | GNUNET_free (api); |
3338 | &plugin->bind_hostname)); | 1025 | return NULL; |
3339 | plugin->bind4_address = GNUNET_malloc (sizeof (struct sockaddr_in)); | ||
3340 | plugin->bind4_address->sin_family = AF_INET; | ||
3341 | plugin->bind4_address->sin_port = htons (port); | ||
3342 | |||
3343 | if (plugin->bind_hostname != NULL) | ||
3344 | { | ||
3345 | if (inet_pton | ||
3346 | (AF_INET, plugin->bind_hostname, | ||
3347 | &plugin->bind4_address->sin_addr) <= 0) | ||
3348 | { | ||
3349 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, component_name, | ||
3350 | _ | ||
3351 | ("Misconfigured address to bind to in configuration!\n")); | ||
3352 | GNUNET_free (plugin->bind4_address); | ||
3353 | GNUNET_free (plugin->bind_hostname); | ||
3354 | plugin->bind_hostname = NULL; | ||
3355 | plugin->bind4_address = NULL; | ||
3356 | } | ||
3357 | } | ||
3358 | } | 1026 | } |
3359 | 1027 | ||
3360 | /* Reading ipv4 addresse to bind to from config file */ | 1028 | /* Start server */ |
3361 | if ((plugin->use_ipv6 == GNUNET_YES) && | 1029 | res = server_start (plugin); |
3362 | (GNUNET_CONFIGURATION_have_value (env->cfg, component_name, "BINDTO6"))) | 1030 | if (res == GNUNET_SYSERR) |
3363 | { | 1031 | { |
3364 | if (GNUNET_OK == | 1032 | server_stop (plugin); |
3365 | GNUNET_CONFIGURATION_get_value_string (env->cfg, component_name, | 1033 | client_stop (plugin); |
3366 | "BINDTO6", | ||
3367 | &plugin->bind_hostname)) | ||
3368 | { | ||
3369 | plugin->bind6_address = GNUNET_malloc (sizeof (struct sockaddr_in6)); | ||
3370 | plugin->bind6_address->sin6_family = AF_INET6; | ||
3371 | plugin->bind6_address->sin6_port = htons (port); | ||
3372 | if (plugin->bind_hostname != NULL) | ||
3373 | { | ||
3374 | if (inet_pton | ||
3375 | (AF_INET6, plugin->bind_hostname, | ||
3376 | &plugin->bind6_address->sin6_addr) <= 0) | ||
3377 | { | ||
3378 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, component_name, | ||
3379 | _ | ||
3380 | ("Misconfigured address to bind to in configuration!\n")); | ||
3381 | GNUNET_free (plugin->bind6_address); | ||
3382 | GNUNET_free (plugin->bind_hostname); | ||
3383 | plugin->bind_hostname = NULL; | ||
3384 | plugin->bind6_address = NULL; | ||
3385 | } | ||
3386 | } | ||
3387 | } | ||
3388 | } | ||
3389 | 1034 | ||
3390 | #if BUILD_HTTPS | 1035 | GNUNET_free_non_null (plugin->server_addr_v4); |
3391 | /* Reading HTTPS crypto related configuration */ | 1036 | GNUNET_free_non_null (plugin->server_addr_v6); |
3392 | /* Get crypto init string from config */ | 1037 | GNUNET_free (plugin); |
3393 | if ((GNUNET_OK != | 1038 | GNUNET_free (api); |
3394 | GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-https", | ||
3395 | "CRYPTO_INIT", | ||
3396 | &plugin->crypto_init)) || | ||
3397 | (GNUNET_OK != | ||
3398 | GNUNET_CONFIGURATION_get_value_filename (env->cfg, "transport-https", | ||
3399 | "KEY_FILE", &key_file)) || | ||
3400 | (GNUNET_OK != | ||
3401 | GNUNET_CONFIGURATION_get_value_filename (env->cfg, "transport-https", | ||
3402 | "CERT_FILE", &cert_file))) | ||
3403 | { | ||
3404 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "https", | ||
3405 | _ | ||
3406 | ("Required configuration options missing in section `%s'\n"), | ||
3407 | "transport-https"); | ||
3408 | GNUNET_free (component_name); | ||
3409 | GNUNET_free_non_null (key_file); | ||
3410 | GNUNET_free_non_null (cert_file); | ||
3411 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3412 | return NULL; | 1039 | return NULL; |
3413 | } | 1040 | } |
3414 | 1041 | ||
3415 | /* read key & certificates from file */ | 1042 | /* Report addresses to transport service */ |
3416 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading TLS certificate `%s' `%s'\n", | 1043 | start_report_addresses (plugin); |
3417 | key_file, cert_file); | ||
3418 | |||
3419 | plugin->key = load_certificate (key_file); | ||
3420 | plugin->cert = load_certificate (cert_file); | ||
3421 | |||
3422 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
3423 | { | ||
3424 | struct GNUNET_OS_Process *certcreation; | ||
3425 | 1044 | ||
3426 | GNUNET_free_non_null (plugin->key); | ||
3427 | plugin->key = NULL; | ||
3428 | GNUNET_free_non_null (plugin->cert); | ||
3429 | plugin->cert = NULL; | ||
3430 | #if DEBUG_HTTP | 1045 | #if DEBUG_HTTP |
3431 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1046 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
3432 | "No usable TLS certificate found, creating certificate\n"); | 1047 | "Plugin `%s' loaded\n", plugin->name); |
3433 | #endif | ||
3434 | errno = 0; | ||
3435 | certcreation = | ||
3436 | GNUNET_OS_start_process (NULL, NULL, | ||
3437 | "gnunet-transport-certificate-creation", | ||
3438 | "gnunet-transport-certificate-creation", | ||
3439 | key_file, cert_file, NULL); | ||
3440 | if (certcreation == NULL) | ||
3441 | { | ||
3442 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "https", | ||
3443 | _ | ||
3444 | ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); | ||
3445 | GNUNET_free (key_file); | ||
3446 | GNUNET_free (cert_file); | ||
3447 | GNUNET_free (component_name); | ||
3448 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3449 | return NULL; | ||
3450 | } | ||
3451 | GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (certcreation)); | ||
3452 | GNUNET_OS_process_close (certcreation); | ||
3453 | plugin->key = load_certificate (key_file); | ||
3454 | plugin->cert = load_certificate (cert_file); | ||
3455 | } | ||
3456 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
3457 | { | ||
3458 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "https", | ||
3459 | _ | ||
3460 | ("No usable TLS certificate found and creating one failed!\n"), | ||
3461 | "transport-https"); | ||
3462 | GNUNET_free (key_file); | ||
3463 | GNUNET_free (cert_file); | ||
3464 | GNUNET_free (component_name); | ||
3465 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3466 | return NULL; | ||
3467 | } | ||
3468 | GNUNET_free (key_file); | ||
3469 | GNUNET_free (cert_file); | ||
3470 | #if DEBUG_HTTP | ||
3471 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); | ||
3472 | #endif | ||
3473 | #endif | 1048 | #endif |
3474 | 1049 | ||
3475 | GNUNET_assert ((port > 0) && (port <= 65535)); | 1050 | return api; |
3476 | plugin->port_inbound = port; | 1051 | } |
3477 | gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT; | ||
3478 | unsigned int timeout = (gn_timeout.rel_value) / 1000; | ||
3479 | 1052 | ||
3480 | if ((plugin->http_server_daemon_v6 == NULL) && | ||
3481 | (plugin->use_ipv6 == GNUNET_YES) && (port != 0)) | ||
3482 | { | ||
3483 | struct sockaddr *tmp = (struct sockaddr *) plugin->bind6_address; | ||
3484 | 1053 | ||
3485 | plugin->http_server_daemon_v6 = MHD_start_daemon ( | 1054 | /** |
3486 | #if DEBUG_MHD | 1055 | * Exit point from the plugin. |
3487 | MHD_USE_DEBUG | | 1056 | */ |
3488 | #endif | 1057 | void * |
3489 | #if BUILD_HTTPS | 1058 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) |
3490 | MHD_USE_SSL | | 1059 | { |
3491 | #endif | 1060 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
3492 | MHD_USE_IPv6, port, | 1061 | struct Plugin *plugin = api->cls; |
3493 | &mhd_accept_cb, plugin, | 1062 | struct Session *s = NULL; |
3494 | &mhd_access_cb, plugin, | ||
3495 | MHD_OPTION_SOCK_ADDR, | ||
3496 | tmp, | ||
3497 | MHD_OPTION_CONNECTION_LIMIT, | ||
3498 | (unsigned int) | ||
3499 | plugin->max_connect_per_transport, | ||
3500 | #if BUILD_HTTPS | ||
3501 | MHD_OPTION_HTTPS_PRIORITIES, | ||
3502 | plugin->crypto_init, | ||
3503 | MHD_OPTION_HTTPS_MEM_KEY, | ||
3504 | plugin->key, | ||
3505 | MHD_OPTION_HTTPS_MEM_CERT, | ||
3506 | plugin->cert, | ||
3507 | #endif | ||
3508 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
3509 | (unsigned int) timeout, | ||
3510 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
3511 | (size_t) (2 * | ||
3512 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
3513 | MHD_OPTION_NOTIFY_COMPLETED, | ||
3514 | &mhd_termination_cb, | ||
3515 | plugin, | ||
3516 | MHD_OPTION_EXTERNAL_LOGGER, | ||
3517 | mhd_logger, | ||
3518 | plugin->mhd_log, | ||
3519 | MHD_OPTION_END); | ||
3520 | } | ||
3521 | if ((plugin->http_server_daemon_v4 == NULL) && | ||
3522 | (plugin->use_ipv4 == GNUNET_YES) && (port != 0)) | ||
3523 | { | ||
3524 | plugin->http_server_daemon_v4 = MHD_start_daemon ( | ||
3525 | #if DEBUG_MHD | ||
3526 | MHD_USE_DEBUG | | ||
3527 | #endif | ||
3528 | #if BUILD_HTTPS | ||
3529 | MHD_USE_SSL | | ||
3530 | #endif | ||
3531 | MHD_NO_FLAG, port, | ||
3532 | &mhd_accept_cb, plugin, | ||
3533 | &mhd_access_cb, plugin, | ||
3534 | MHD_OPTION_SOCK_ADDR, | ||
3535 | (struct sockaddr_in *) | ||
3536 | plugin->bind4_address, | ||
3537 | MHD_OPTION_CONNECTION_LIMIT, | ||
3538 | (unsigned int) | ||
3539 | plugin->max_connect_per_transport, | ||
3540 | #if BUILD_HTTPS | ||
3541 | MHD_OPTION_HTTPS_PRIORITIES, | ||
3542 | plugin->crypto_init, | ||
3543 | MHD_OPTION_HTTPS_MEM_KEY, | ||
3544 | plugin->key, | ||
3545 | MHD_OPTION_HTTPS_MEM_CERT, | ||
3546 | plugin->cert, | ||
3547 | #endif | ||
3548 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
3549 | (unsigned int) timeout, | ||
3550 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
3551 | (size_t) (2 * | ||
3552 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
3553 | MHD_OPTION_NOTIFY_COMPLETED, | ||
3554 | &mhd_termination_cb, | ||
3555 | plugin, | ||
3556 | MHD_OPTION_EXTERNAL_LOGGER, | ||
3557 | mhd_logger, | ||
3558 | plugin->mhd_log, | ||
3559 | MHD_OPTION_END); | ||
3560 | } | ||
3561 | if (plugin->http_server_daemon_v4 != NULL) | ||
3562 | plugin->http_server_task_v4 = | ||
3563 | http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4); | ||
3564 | if (plugin->http_server_daemon_v6 != NULL) | ||
3565 | plugin->http_server_task_v6 = | ||
3566 | http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6); | ||
3567 | 1063 | ||
1064 | /* Stop reporting addresses to transport service */ | ||
1065 | stop_report_addresses (plugin); | ||
3568 | 1066 | ||
3569 | if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK) | 1067 | /* cleaning up sessions */ |
1068 | s = plugin->head; | ||
1069 | while (s != NULL) | ||
3570 | { | 1070 | { |
1071 | struct Session *t = s->next; | ||
3571 | #if DEBUG_HTTP | 1072 | #if DEBUG_HTTP |
3572 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1073 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
3573 | "Starting MHD with IPv4 bound to %s with port %u\n", | 1074 | "Disconnecting `%s' \n", GNUNET_i2s (&s->target)); |
3574 | (plugin->bind_hostname != | ||
3575 | NULL) ? plugin->bind_hostname : "every address", port); | ||
3576 | #endif | 1075 | #endif |
1076 | if (s->inbound == GNUNET_NO) | ||
1077 | GNUNET_assert (GNUNET_OK == client_disconnect (s)); | ||
1078 | else | ||
1079 | GNUNET_assert (GNUNET_OK == server_disconnect (s)); | ||
1080 | |||
1081 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); | ||
1082 | delete_session (s); | ||
1083 | s = t; | ||
3577 | } | 1084 | } |
3578 | else if ((plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) && | 1085 | |
3579 | (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)) | ||
3580 | { | ||
3581 | #if DEBUG_HTTP | 1086 | #if DEBUG_HTTP |
3582 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1087 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
3583 | "Starting MHD with IPv6 bound to %s with port %u\n", | 1088 | "Stopping server\n"); |
3584 | (plugin->bind_hostname != | ||
3585 | NULL) ? plugin->bind_hostname : "every address", port); | ||
3586 | #endif | 1089 | #endif |
3587 | } | 1090 | /* Stop server */ |
3588 | else if ((plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) && | 1091 | server_stop (plugin); |
3589 | (plugin->http_server_task_v4 == GNUNET_SCHEDULER_NO_TASK)) | 1092 | |
3590 | { | ||
3591 | #if DEBUG_HTTP | 1093 | #if DEBUG_HTTP |
3592 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1094 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
3593 | "Starting MHD with IPv4 and IPv6 bound to %s with port %u\n", | 1095 | "Stopping client\n"); |
3594 | (plugin->bind_hostname != | ||
3595 | NULL) ? plugin->bind_hostname : "every address", port); | ||
3596 | #endif | 1096 | #endif |
3597 | } | 1097 | /* Stop client */ |
3598 | else | 1098 | client_stop (plugin); |
3599 | { | ||
3600 | char *tmp = NULL; | ||
3601 | |||
3602 | if ((plugin->use_ipv6 == GNUNET_YES) && (plugin->use_ipv4 == GNUNET_YES)) | ||
3603 | GNUNET_asprintf (&tmp, "with IPv4 and IPv6 enabled"); | ||
3604 | if ((plugin->use_ipv6 == GNUNET_NO) && (plugin->use_ipv4 == GNUNET_YES)) | ||
3605 | GNUNET_asprintf (&tmp, "with IPv4 enabled"); | ||
3606 | if ((plugin->use_ipv6 == GNUNET_YES) && (plugin->use_ipv4 == GNUNET_NO)) | ||
3607 | GNUNET_asprintf (&tmp, "with IPv6 enabled"); | ||
3608 | if ((plugin->use_ipv6 == GNUNET_NO) && (plugin->use_ipv4 == GNUNET_NO)) | ||
3609 | GNUNET_asprintf (&tmp, "with NO IP PROTOCOL enabled"); | ||
3610 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3611 | _ | ||
3612 | ("HTTP Server with %s could not be started on port %u! %s plugin failed!\n"), | ||
3613 | tmp, port, PROTOCOL_PREFIX); | ||
3614 | GNUNET_free (tmp); | ||
3615 | GNUNET_free (component_name); | ||
3616 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3617 | return NULL; | ||
3618 | } | ||
3619 | |||
3620 | /* Initializing cURL */ | ||
3621 | curl_global_init (CURL_GLOBAL_ALL); | ||
3622 | plugin->multi_handle = curl_multi_init (); | ||
3623 | |||
3624 | if (NULL == plugin->multi_handle) | ||
3625 | { | ||
3626 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, component_name, | ||
3627 | _ | ||
3628 | ("Could not initialize curl multi handle, failed to start %s plugin!\n"), | ||
3629 | PROTOCOL_PREFIX); | ||
3630 | GNUNET_free (component_name); | ||
3631 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); | ||
3632 | return NULL; | ||
3633 | } | ||
3634 | 1099 | ||
3635 | ret = | ||
3636 | GNUNET_SERVICE_get_server_addresses (component_name, env->cfg, &addrs, | ||
3637 | &addrlens); | ||
3638 | 1100 | ||
3639 | if (ret != GNUNET_SYSERR) | 1101 | #if DEBUG_HTTP |
3640 | { | 1102 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
3641 | plugin->nat = | 1103 | "Plugin `%s' unloaded\n", plugin->name); |
3642 | GNUNET_NAT_register (env->cfg, GNUNET_YES, port, (unsigned int) ret, | 1104 | #endif |
3643 | (const struct sockaddr **) addrs, addrlens, | ||
3644 | &tcp_nat_port_map_callback, | ||
3645 | &try_connection_reversal, plugin); | ||
3646 | while (ret > 0) | ||
3647 | { | ||
3648 | ret--; | ||
3649 | GNUNET_assert (addrs[ret] != NULL); | ||
3650 | GNUNET_free (addrs[ret]); | ||
3651 | } | ||
3652 | GNUNET_free_non_null (addrs); | ||
3653 | GNUNET_free_non_null (addrlens); | ||
3654 | } | ||
3655 | else | ||
3656 | { | ||
3657 | plugin->nat = | ||
3658 | GNUNET_NAT_register (env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL, | ||
3659 | &try_connection_reversal, plugin); | ||
3660 | } | ||
3661 | 1105 | ||
3662 | plugin->peers = GNUNET_CONTAINER_multihashmap_create (10); | 1106 | GNUNET_free_non_null (plugin->server_addr_v4); |
1107 | GNUNET_free_non_null (plugin->server_addr_v6); | ||
1108 | GNUNET_free (plugin); | ||
1109 | GNUNET_free (api); | ||
3663 | 1110 | ||
3664 | GNUNET_free (component_name); | 1111 | return NULL; |
3665 | //GNUNET_SCHEDULER_add_now(address_notification, plugin); | ||
3666 | return api; | ||
3667 | } | 1112 | } |
3668 | 1113 | ||
3669 | /* end of plugin_transport_http.c */ | 1114 | /* end of plugin_transport_http.c */ |