diff options
author | Matthias Wachs <wachs@net.in.tum.de> | 2012-08-24 14:51:02 +0000 |
---|---|---|
committer | Matthias Wachs <wachs@net.in.tum.de> | 2012-08-24 14:51:02 +0000 |
commit | 8c3ea6f58287d4c7382b31f116580898f30aa914 (patch) | |
tree | ff9efdef7915476fbc582b4154558495268b2e88 /src/transport/plugin_transport_http_client.c | |
parent | b0cd5f3c9bf3f87d89fc2f50221cd245b0498b8f (diff) | |
download | gnunet-8c3ea6f58287d4c7382b31f116580898f30aa914.tar.gz gnunet-8c3ea6f58287d4c7382b31f116580898f30aa914.zip |
changes
Diffstat (limited to 'src/transport/plugin_transport_http_client.c')
-rw-r--r-- | src/transport/plugin_transport_http_client.c | 802 |
1 files changed, 756 insertions, 46 deletions
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c index 2be86a6ee..ff148c2a6 100644 --- a/src/transport/plugin_transport_http_client.c +++ b/src/transport/plugin_transport_http_client.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | 35 | ||
36 | #define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
37 | |||
36 | #include "platform.h" | 38 | #include "platform.h" |
37 | #include "gnunet_protocols.h" | 39 | #include "gnunet_protocols.h" |
38 | #include "gnunet_connection_lib.h" | 40 | #include "gnunet_connection_lib.h" |
@@ -45,20 +47,54 @@ | |||
45 | #include <curl/curl.h> | 47 | #include <curl/curl.h> |
46 | 48 | ||
47 | 49 | ||
48 | #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING | ||
49 | |||
50 | /** | 50 | /** |
51 | * After how long do we expire an address that we | 51 | * Encapsulation of all of the state of the plugin. |
52 | * learned from another peer if it is not reconfirmed | ||
53 | * by anyone? | ||
54 | */ | 52 | */ |
55 | #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) | 53 | struct HTTP_Client_Plugin; |
56 | 54 | ||
57 | 55 | ||
58 | /** | 56 | /** |
59 | * Encapsulation of all of the state of the plugin. | 57 | * Message to send using http |
60 | */ | 58 | */ |
61 | struct HTTP_Client_Plugin; | 59 | struct HTTP_Message |
60 | { | ||
61 | /** | ||
62 | * next pointer for double linked list | ||
63 | */ | ||
64 | struct HTTP_Message *next; | ||
65 | |||
66 | /** | ||
67 | * previous pointer for double linked list | ||
68 | */ | ||
69 | struct HTTP_Message *prev; | ||
70 | |||
71 | /** | ||
72 | * buffer containing data to send | ||
73 | */ | ||
74 | char *buf; | ||
75 | |||
76 | /** | ||
77 | * amount of data already sent | ||
78 | */ | ||
79 | size_t pos; | ||
80 | |||
81 | /** | ||
82 | * buffer length | ||
83 | */ | ||
84 | size_t size; | ||
85 | |||
86 | /** | ||
87 | * Continuation function to call once the transmission buffer | ||
88 | * has again space available. NULL if there is no | ||
89 | * continuation to call. | ||
90 | */ | ||
91 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; | ||
92 | |||
93 | /** | ||
94 | * Closure for transmit_cont. | ||
95 | */ | ||
96 | void *transmit_cont_cls; | ||
97 | }; | ||
62 | 98 | ||
63 | 99 | ||
64 | /** | 100 | /** |
@@ -70,7 +106,7 @@ struct Session | |||
70 | * To whom are we talking to (set to our identity | 106 | * To whom are we talking to (set to our identity |
71 | * if we are still waiting for the welcome message) | 107 | * if we are still waiting for the welcome message) |
72 | */ | 108 | */ |
73 | struct GNUNET_PeerIdentity sender; | 109 | struct GNUNET_PeerIdentity target; |
74 | 110 | ||
75 | /** | 111 | /** |
76 | * Stored in a linked list. | 112 | * Stored in a linked list. |
@@ -78,44 +114,77 @@ struct Session | |||
78 | struct Session *next; | 114 | struct Session *next; |
79 | 115 | ||
80 | /** | 116 | /** |
117 | * Stored in a linked list. | ||
118 | */ | ||
119 | struct Session *prev; | ||
120 | |||
121 | /** | ||
122 | * Address | ||
123 | */ | ||
124 | void *addr; | ||
125 | |||
126 | /** | ||
127 | * Address length | ||
128 | */ | ||
129 | size_t addrlen; | ||
130 | |||
131 | /** | ||
132 | * ATS network type in NBO | ||
133 | */ | ||
134 | uint32_t ats_address_network_type; | ||
135 | |||
136 | /** | ||
81 | * Pointer to the global plugin struct. | 137 | * Pointer to the global plugin struct. |
82 | */ | 138 | */ |
83 | struct HTTP_Client_Plugin *plugin; | 139 | struct HTTP_Client_Plugin *plugin; |
84 | 140 | ||
85 | /** | 141 | /** |
86 | * The client (used to identify this connection) | 142 | * Is client send handle paused since there are no data to send? |
143 | * GNUNET_YES/NO | ||
87 | */ | 144 | */ |
88 | /* void *client; */ | 145 | int client_put_paused; |
146 | |||
89 | 147 | ||
90 | /** | 148 | /** |
91 | * Continuation function to call once the transmission buffer | 149 | * Client send handle |
92 | * has again space available. NULL if there is no | ||
93 | * continuation to call. | ||
94 | */ | 150 | */ |
95 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; | 151 | void *client_put; |
96 | 152 | ||
97 | /** | 153 | /** |
98 | * Closure for transmit_cont. | 154 | * Client receive handle |
99 | */ | 155 | */ |
100 | void *transmit_cont_cls; | 156 | void *client_get; |
157 | |||
158 | /** | ||
159 | * next pointer for double linked list | ||
160 | */ | ||
161 | struct HTTP_Message *msg_head; | ||
101 | 162 | ||
102 | /** | 163 | /** |
103 | * At what time did we reset last_received last? | 164 | * previous pointer for double linked list |
104 | */ | 165 | */ |
105 | struct GNUNET_TIME_Absolute last_quota_update; | 166 | struct HTTP_Message *msg_tail; |
106 | 167 | ||
107 | /** | 168 | /** |
108 | * How many bytes have we received since the "last_quota_update" | 169 | * Message stream tokenizer for incoming data |
109 | * timestamp? | ||
110 | */ | 170 | */ |
111 | uint64_t last_received; | 171 | struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; |
112 | 172 | ||
113 | /** | 173 | /** |
114 | * Number of bytes per ms that this peer is allowed | 174 | * Session timeout task |
115 | * to send to us. | ||
116 | */ | 175 | */ |
117 | uint32_t quota; | 176 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; |
118 | 177 | ||
178 | /** | ||
179 | * Task to wake up client receive handle when receiving is allowed again | ||
180 | */ | ||
181 | GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task; | ||
182 | |||
183 | /** | ||
184 | * Absolute time when to receive data again | ||
185 | * Used for receive throttling | ||
186 | */ | ||
187 | struct GNUNET_TIME_Absolute next_receive; | ||
119 | }; | 188 | }; |
120 | 189 | ||
121 | /** | 190 | /** |
@@ -149,6 +218,23 @@ struct HTTP_Client_Plugin | |||
149 | char *protocol; | 218 | char *protocol; |
150 | 219 | ||
151 | /** | 220 | /** |
221 | * Maximum number of sockets the plugin can use | ||
222 | * Each http inbound /outbound connections are two connections | ||
223 | */ | ||
224 | unsigned int max_connections; | ||
225 | |||
226 | /** | ||
227 | * Current number of sockets the plugin can use | ||
228 | * Each http inbound /outbound connections are two connections | ||
229 | */ | ||
230 | unsigned int cur_connections; | ||
231 | |||
232 | /** | ||
233 | * Last used unique HTTP connection tag | ||
234 | */ | ||
235 | uint32_t last_tag; | ||
236 | |||
237 | /** | ||
152 | * use IPv6 | 238 | * use IPv6 |
153 | */ | 239 | */ |
154 | uint16_t use_ipv6; | 240 | uint16_t use_ipv6; |
@@ -162,8 +248,36 @@ struct HTTP_Client_Plugin | |||
162 | * cURL Multihandle | 248 | * cURL Multihandle |
163 | */ | 249 | */ |
164 | CURLM *curl_multi_handle; | 250 | CURLM *curl_multi_handle; |
251 | |||
252 | /** | ||
253 | * curl perform task | ||
254 | */ | ||
255 | GNUNET_SCHEDULER_TaskIdentifier client_perform_task; | ||
165 | }; | 256 | }; |
166 | 257 | ||
258 | /** | ||
259 | * Encapsulation of all of the state of the plugin. | ||
260 | */ | ||
261 | struct HTTP_Client_Plugin *p; | ||
262 | |||
263 | /** | ||
264 | * Start session timeout | ||
265 | */ | ||
266 | static void | ||
267 | client_start_session_timeout (struct Session *s); | ||
268 | |||
269 | /** | ||
270 | * Increment session timeout due to activity | ||
271 | */ | ||
272 | static void | ||
273 | client_reschedule_session_timeout (struct Session *s); | ||
274 | |||
275 | /** | ||
276 | * Cancel timeout | ||
277 | */ | ||
278 | static void | ||
279 | client_stop_session_timeout (struct Session *s); | ||
280 | |||
167 | 281 | ||
168 | /** | 282 | /** |
169 | * Function that can be used by the transport service to transmit | 283 | * Function that can be used by the transport service to transmit |
@@ -206,6 +320,8 @@ http_client_plugin_send (void *cls, | |||
206 | GNUNET_assert (plugin != NULL); | 320 | GNUNET_assert (plugin != NULL); |
207 | GNUNET_assert (session != NULL); | 321 | GNUNET_assert (session != NULL); |
208 | 322 | ||
323 | GNUNET_break (0); | ||
324 | |||
209 | /* struct Plugin *plugin = cls; */ | 325 | /* struct Plugin *plugin = cls; */ |
210 | return bytes_sent; | 326 | return bytes_sent; |
211 | } | 327 | } |
@@ -225,19 +341,435 @@ http_client_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *targ | |||
225 | { | 341 | { |
226 | // struct Plugin *plugin = cls; | 342 | // struct Plugin *plugin = cls; |
227 | // FIXME | 343 | // FIXME |
344 | GNUNET_break (0); | ||
345 | } | ||
346 | |||
347 | static struct Session * | ||
348 | client_lookup_session (struct HTTP_Client_Plugin *plugin, | ||
349 | const struct GNUNET_HELLO_Address *address) | ||
350 | { | ||
351 | struct Session *pos; | ||
352 | |||
353 | for (pos = plugin->head; NULL != pos; pos = pos->next) | ||
354 | if ((0 == memcmp (&address->peer, &pos->target, sizeof (struct GNUNET_PeerIdentity))) && | ||
355 | (address->address_length == pos->addrlen) && | ||
356 | (0 == memcmp (address->address, pos->addr, pos->addrlen))) | ||
357 | return pos; | ||
358 | return NULL; | ||
359 | } | ||
360 | |||
361 | static int | ||
362 | client_exist_session (struct HTTP_Client_Plugin *plugin, struct Session *s) | ||
363 | { | ||
364 | struct Session * head; | ||
365 | |||
366 | GNUNET_assert (NULL != plugin); | ||
367 | GNUNET_assert (NULL != s); | ||
368 | |||
369 | for (head = plugin->head; head != NULL; head = head->next) | ||
370 | { | ||
371 | if (head == s) | ||
372 | return GNUNET_YES; | ||
373 | } | ||
374 | return GNUNET_NO; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * Callback method used with libcurl | ||
379 | * Method is called when libcurl needs to read data during sending | ||
380 | * | ||
381 | * @param stream pointer where to write data | ||
382 | * @param size size of an individual element | ||
383 | * @param nmemb count of elements that can be written to the buffer | ||
384 | * @param cls source pointer, passed to the libcurl handle | ||
385 | * @return bytes written to stream, returning 0 will terminate connection! | ||
386 | */ | ||
387 | static size_t | ||
388 | client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) | ||
389 | { | ||
390 | struct Session *s = cls; | ||
391 | struct HTTP_Client_Plugin *plugin = s->plugin; | ||
392 | struct HTTP_Message *msg = s->msg_head; | ||
393 | size_t len; | ||
394 | |||
395 | if (GNUNET_YES != client_exist_session (plugin, s)) | ||
396 | { | ||
397 | GNUNET_break (0); | ||
398 | return 0; | ||
399 | } | ||
400 | if (NULL == msg) | ||
401 | { | ||
402 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
403 | "Nothing to for session %p send! Suspending PUT handle!\n", s); | ||
404 | s->client_put_paused = GNUNET_YES; | ||
405 | return CURL_READFUNC_PAUSE; | ||
406 | } | ||
407 | /* data to send */ | ||
408 | GNUNET_assert (msg->pos < msg->size); | ||
409 | /* calculate how much fits in buffer */ | ||
410 | len = GNUNET_MIN (msg->size - msg->pos, | ||
411 | size * nmemb); | ||
412 | memcpy (stream, &msg->buf[msg->pos], len); | ||
413 | msg->pos += len; | ||
414 | if (msg->pos == msg->size) | ||
415 | { | ||
416 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
417 | "Session %p message with %u bytes sent, removing message from queue\n", | ||
418 | s, msg->size, msg->pos); | ||
419 | /* Calling transmit continuation */ | ||
420 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
421 | if (NULL != msg->transmit_cont) | ||
422 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); | ||
423 | GNUNET_free (msg); | ||
424 | } | ||
425 | client_reschedule_session_timeout (s); | ||
426 | return len; | ||
228 | } | 427 | } |
229 | 428 | ||
429 | |||
230 | static void | 430 | static void |
231 | client_stop (struct HTTP_Client_Plugin *plugin) | 431 | client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
232 | { | 432 | { |
233 | if (NULL != plugin->curl_multi_handle) | 433 | struct Session *s = cls; |
434 | |||
435 | if (GNUNET_YES != client_exist_session(p, s)) | ||
234 | { | 436 | { |
235 | curl_multi_cleanup (plugin->curl_multi_handle); | 437 | GNUNET_break (0); |
236 | plugin->curl_multi_handle = NULL; | 438 | return; |
237 | } | 439 | } |
238 | curl_global_cleanup (); | 440 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; |
441 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
442 | return; | ||
443 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
444 | "Client: %p Waking up receive handle\n", s->client_get); | ||
445 | if (s->client_get != NULL) | ||
446 | curl_easy_pause (s->client_get, CURLPAUSE_CONT); | ||
447 | } | ||
448 | |||
449 | |||
450 | |||
451 | static int | ||
452 | client_receive_mst_cb (void *cls, void *client, | ||
453 | const struct GNUNET_MessageHeader *message) | ||
454 | { | ||
455 | struct Session *s = cls; | ||
456 | struct HTTP_Client_Plugin *plugin; | ||
457 | struct GNUNET_TIME_Relative delay; | ||
458 | struct GNUNET_ATS_Information atsi[2]; | ||
459 | |||
460 | if (GNUNET_YES != client_exist_session(p, s)) | ||
461 | { | ||
462 | GNUNET_break (0); | ||
463 | return GNUNET_OK; | ||
464 | } | ||
465 | plugin = s->plugin; | ||
466 | |||
467 | |||
468 | atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); | ||
469 | atsi[0].value = htonl (1); | ||
470 | atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); | ||
471 | atsi[1].value = s->ats_address_network_type; | ||
472 | GNUNET_break (s->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); | ||
473 | |||
474 | delay = s->plugin->env->receive (plugin->env->cls, &s->target, message, | ||
475 | (const struct GNUNET_ATS_Information *) &atsi, 2, | ||
476 | s, s->addr, s->addrlen); | ||
477 | s->next_receive = | ||
478 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); | ||
479 | |||
480 | if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) | ||
481 | { | ||
482 | |||
483 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
484 | "Client: peer `%s' address `%s' next read delayed for %llu ms\n", | ||
485 | GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), | ||
486 | delay); | ||
487 | } | ||
488 | client_reschedule_session_timeout (s); | ||
489 | return GNUNET_OK; | ||
490 | } | ||
491 | |||
492 | |||
493 | |||
494 | /** | ||
495 | * Callback method used with libcurl | ||
496 | * Method is called when libcurl needs to write data during sending | ||
497 | * | ||
498 | * @param stream pointer where to write data | ||
499 | * @param size size of an individual element | ||
500 | * @param nmemb count of elements that can be written to the buffer | ||
501 | * @param cls destination pointer, passed to the libcurl handle | ||
502 | * @return bytes read from stream | ||
503 | */ | ||
504 | static size_t | ||
505 | client_receive (void *stream, size_t size, size_t nmemb, void *cls) | ||
506 | { | ||
507 | return 0; | ||
508 | |||
509 | struct Session *s = cls; | ||
510 | struct GNUNET_TIME_Absolute now; | ||
511 | size_t len = size * nmemb; | ||
512 | struct HTTP_Client_Plugin *plugin = s->plugin; | ||
513 | |||
514 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
515 | "Received %u bytes from peer `%s'\n", len, | ||
516 | GNUNET_i2s (&s->target)); | ||
517 | now = GNUNET_TIME_absolute_get (); | ||
518 | if (now.abs_value < s->next_receive.abs_value) | ||
519 | { | ||
520 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
521 | struct GNUNET_TIME_Relative delta = | ||
522 | GNUNET_TIME_absolute_get_difference (now, s->next_receive); | ||
523 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
524 | "No inbound bandwidth for session %p available! Next read was delayed for %llu ms\n", | ||
525 | s, delta.rel_value); | ||
526 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
527 | { | ||
528 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
529 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
530 | } | ||
531 | s->recv_wakeup_task = | ||
532 | GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s); | ||
533 | return CURLPAUSE_ALL; | ||
534 | } | ||
535 | if (NULL == s->msg_tk) | ||
536 | s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s); | ||
537 | GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO); | ||
538 | return len; | ||
539 | |||
540 | } | ||
541 | |||
542 | /** | ||
543 | * Task performing curl operations | ||
544 | * | ||
545 | * @param cls plugin as closure | ||
546 | * @param tc gnunet scheduler task context | ||
547 | */ | ||
548 | static void | ||
549 | client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
550 | { | ||
551 | GNUNET_break (0); | ||
552 | #if 0 | ||
553 | struct HTTP_Client_Plugin *plugin = cls; | ||
554 | int running; | ||
555 | CURLMcode mret; | ||
556 | |||
557 | GNUNET_assert (cls != NULL); | ||
558 | |||
559 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
560 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
561 | return; | ||
562 | |||
563 | do | ||
564 | { | ||
565 | running = 0; | ||
566 | mret = curl_multi_perform (plugin->client_mh, &running); | ||
567 | |||
568 | CURLMsg *msg; | ||
569 | int msgs_left; | ||
570 | |||
571 | while ((msg = curl_multi_info_read (plugin->client_mh, &msgs_left))) | ||
572 | { | ||
573 | CURL *easy_h = msg->easy_handle; | ||
574 | struct Session *s = NULL; | ||
575 | char *d = (char *) s; | ||
576 | |||
577 | if (easy_h == NULL) | ||
578 | { | ||
579 | GNUNET_break (0); | ||
580 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
581 | "Client: connection to ended with reason %i: `%s', %i handles running\n", | ||
582 | msg->data.result, | ||
583 | curl_easy_strerror (msg->data.result), running); | ||
584 | continue; | ||
585 | } | ||
586 | |||
587 | GNUNET_assert (CURLE_OK == | ||
588 | curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); | ||
589 | s = (struct Session *) d; | ||
590 | |||
591 | if (GNUNET_YES != exist_session(plugin, s)) | ||
592 | { | ||
593 | GNUNET_break (0); | ||
594 | return; | ||
595 | } | ||
596 | |||
597 | GNUNET_assert (s != NULL); | ||
598 | if (msg->msg == CURLMSG_DONE) | ||
599 | { | ||
600 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
601 | "Client: %p connection to '%s' %s ended with reason %i: `%s'\n", | ||
602 | msg->easy_handle, GNUNET_i2s (&s->target), | ||
603 | http_plugin_address_to_string (NULL, s->addr, | ||
604 | s->addrlen), | ||
605 | msg->data.result, | ||
606 | curl_easy_strerror (msg->data.result)); | ||
607 | |||
608 | /* Disconnect other transmission direction and tell transport */ | ||
609 | client_disconnect (s); | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | while (mret == CURLM_CALL_MULTI_PERFORM); | ||
614 | client_schedule (plugin, GNUNET_NO); | ||
615 | #endif | ||
616 | } | ||
617 | |||
618 | |||
619 | static int | ||
620 | client_connect (struct Session *s) | ||
621 | { | ||
622 | |||
623 | struct HTTP_Client_Plugin *plugin = s->plugin; | ||
624 | int res = GNUNET_OK; | ||
625 | char *url; | ||
626 | CURLMcode mret; | ||
627 | |||
628 | /* create url */ | ||
629 | if (NULL == http_common_plugin_address_to_string (NULL, s->addr, s->addrlen)) | ||
630 | { | ||
631 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
632 | "Invalid address peer `%s'\n", | ||
633 | GNUNET_i2s (&s->target)); | ||
634 | return GNUNET_SYSERR; | ||
635 | } | ||
636 | |||
637 | GNUNET_asprintf (&url, "%s%s;%u", | ||
638 | http_common_plugin_address_to_string (plugin, s->addr, s->addrlen), | ||
639 | GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey), | ||
640 | plugin->last_tag); | ||
641 | |||
642 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
643 | "Initiating outbound session peer `%s' using address `%s'\n", | ||
644 | GNUNET_i2s (&s->target), url); | ||
645 | |||
646 | /* create get connection */ | ||
647 | s->client_get = curl_easy_init (); | ||
648 | #if VERBOSE_CURL | ||
649 | curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L); | ||
650 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log); | ||
651 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get); | ||
652 | #endif | ||
653 | #if BUILD_HTTPS | ||
654 | curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
655 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0); | ||
656 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0); | ||
657 | #endif | ||
658 | curl_easy_setopt (s->client_get, CURLOPT_URL, url); | ||
659 | //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb); | ||
660 | //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps); | ||
661 | curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb); | ||
662 | curl_easy_setopt (s->client_get, CURLOPT_READDATA, s); | ||
663 | curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive); | ||
664 | curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s); | ||
665 | curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS, | ||
666 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
667 | curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s); | ||
668 | curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS, | ||
669 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
670 | curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE, | ||
671 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
672 | #if CURL_TCP_NODELAY | ||
673 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); | ||
674 | #endif | ||
675 | |||
676 | /* create put connection */ | ||
677 | s->client_put = curl_easy_init (); | ||
678 | #if VERBOSE_CURL | ||
679 | curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L); | ||
680 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log); | ||
681 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put); | ||
682 | #endif | ||
683 | #if BUILD_HTTPS | ||
684 | curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
685 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0); | ||
686 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0); | ||
687 | #endif | ||
688 | curl_easy_setopt (s->client_put, CURLOPT_URL, url); | ||
689 | curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L); | ||
690 | //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb); | ||
691 | //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps); | ||
692 | curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb); | ||
693 | curl_easy_setopt (s->client_put, CURLOPT_READDATA, s); | ||
694 | curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive); | ||
695 | curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s); | ||
696 | curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS, | ||
697 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
698 | curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s); | ||
699 | curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS, | ||
700 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
701 | curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE, | ||
702 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
703 | #if CURL_TCP_NODELAY | ||
704 | curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); | ||
705 | #endif | ||
706 | GNUNET_free (url); | ||
707 | |||
708 | mret = curl_multi_add_handle (plugin->curl_multi_handle, s->client_get); | ||
709 | if (mret != CURLM_OK) | ||
710 | { | ||
711 | curl_easy_cleanup (s->client_get); | ||
712 | GNUNET_break (0); | ||
713 | return GNUNET_SYSERR; | ||
714 | } | ||
715 | |||
716 | mret = curl_multi_add_handle (plugin->curl_multi_handle, s->client_put); | ||
717 | if (mret != CURLM_OK) | ||
718 | { | ||
719 | curl_multi_remove_handle (plugin->curl_multi_handle, s->client_get); | ||
720 | curl_easy_cleanup (s->client_get); | ||
721 | curl_easy_cleanup (s->client_put); | ||
722 | GNUNET_break (0); | ||
723 | return GNUNET_SYSERR; | ||
724 | } | ||
725 | |||
726 | /* Perform connect */ | ||
727 | plugin->cur_connections += 2; | ||
728 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
729 | "# HTTP client connections", | ||
730 | plugin->cur_connections, | ||
731 | GNUNET_NO); | ||
732 | |||
733 | /* Re-schedule since handles have changed */ | ||
734 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
735 | { | ||
736 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
737 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
738 | } | ||
739 | plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin); | ||
740 | return res; | ||
239 | } | 741 | } |
240 | 742 | ||
743 | void | ||
744 | client_delete_session (struct Session *s) | ||
745 | { | ||
746 | struct HTTP_Client_Plugin *plugin = s->plugin; | ||
747 | struct HTTP_Message *pos = s->msg_head; | ||
748 | struct HTTP_Message *next = NULL; | ||
749 | |||
750 | client_stop_session_timeout (s); | ||
751 | |||
752 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); | ||
753 | |||
754 | while (NULL != (pos = next)) | ||
755 | { | ||
756 | next = pos->next; | ||
757 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, pos); | ||
758 | if (pos->transmit_cont != NULL) | ||
759 | pos->transmit_cont (pos->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
760 | GNUNET_free (pos); | ||
761 | } | ||
762 | |||
763 | if (s->msg_tk != NULL) | ||
764 | { | ||
765 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
766 | s->msg_tk = NULL; | ||
767 | } | ||
768 | GNUNET_free (s->addr); | ||
769 | GNUNET_free (s); | ||
770 | } | ||
771 | |||
772 | |||
241 | /** | 773 | /** |
242 | * Creates a new outbound session the transport service will use to send data to the | 774 | * Creates a new outbound session the transport service will use to send data to the |
243 | * peer | 775 | * peer |
@@ -252,49 +784,51 @@ http_client_plugin_get_session (void *cls, | |||
252 | { | 784 | { |
253 | struct HTTP_Client_Plugin *plugin = cls; | 785 | struct HTTP_Client_Plugin *plugin = cls; |
254 | struct Session * s = NULL; | 786 | struct Session * s = NULL; |
255 | // size_t addrlen; | ||
256 | 787 | ||
257 | GNUNET_assert (plugin != NULL); | 788 | GNUNET_assert (plugin != NULL); |
258 | GNUNET_assert (address != NULL); | 789 | GNUNET_assert (address != NULL); |
259 | GNUNET_assert (address->address != NULL); | 790 | GNUNET_assert (address->address != NULL); |
260 | 791 | ||
261 | GNUNET_break (0); | ||
262 | 792 | ||
263 | /* find existing session */ | 793 | /* find existing session */ |
264 | #if 0 | 794 | s = client_lookup_session (plugin, address); |
265 | s = lookup_session (plugin, address); | ||
266 | if (s != NULL) | 795 | if (s != NULL) |
267 | return s; | 796 | return s; |
268 | 797 | ||
269 | if (plugin->max_connections <= plugin->cur_connections) | 798 | if (plugin->max_connections <= plugin->cur_connections) |
270 | { | 799 | { |
271 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, | 800 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, |
272 | "Maximum number of connections reached, " | 801 | "Maximum number of connections (%u) reached: " |
273 | "cannot connect to peer `%s'\n", GNUNET_i2s (&address->peer)); | 802 | "cannot connect to peer `%s'\n", |
803 | plugin->max_connections, | ||
804 | GNUNET_i2s (&address->peer)); | ||
274 | return NULL; | 805 | return NULL; |
275 | } | 806 | } |
276 | 807 | ||
277 | /* create new session */ | 808 | s = GNUNET_malloc (sizeof (struct Session)); |
278 | addrlen = address->address_length; | 809 | memcpy (&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity)); |
279 | 810 | s->plugin = plugin; | |
280 | GNUNET_assert (addrlen > sizeof (struct HttpAddress)); | 811 | s->addr = GNUNET_malloc (address->address_length); |
812 | memcpy (s->addr, address->address, address->address_length); | ||
813 | s->addrlen = address->address_length; | ||
814 | //s->ats_address_network_type = ats.value; | ||
815 | GNUNET_break (0); | ||
281 | 816 | ||
282 | s = create_session (plugin, &address->peer, address->address, address->address_length); | 817 | client_start_session_timeout (s); |
283 | 818 | ||
284 | /* add new session */ | 819 | /* add new session */ |
285 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | 820 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); |
821 | |||
286 | /* initiate new connection */ | 822 | /* initiate new connection */ |
287 | if (GNUNET_SYSERR == client_connect (s)) | 823 | if (GNUNET_SYSERR == client_connect (s)) |
288 | { | 824 | { |
289 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | 825 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, |
290 | "Cannot connect to peer `%s' address `%s''\n", | 826 | "Cannot connect to peer `%s' address `%s''\n", |
291 | http_plugin_address_to_string(NULL, s->addr, s->addrlen), | 827 | http_common_plugin_address_to_string (NULL, s->addr, s->addrlen), |
292 | GNUNET_i2s (&s->target)); | 828 | GNUNET_i2s (&s->target)); |
293 | GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); | 829 | client_delete_session (s); |
294 | delete_session (s); | ||
295 | return NULL; | 830 | return NULL; |
296 | } | 831 | } |
297 | #endif | ||
298 | return s; | 832 | return s; |
299 | } | 833 | } |
300 | 834 | ||
@@ -314,6 +848,176 @@ client_start (struct HTTP_Client_Plugin *plugin) | |||
314 | return GNUNET_OK; | 848 | return GNUNET_OK; |
315 | } | 849 | } |
316 | 850 | ||
851 | static int | ||
852 | client_disconnect (struct Session *s) | ||
853 | { | ||
854 | #if 0 | ||
855 | int res = GNUNET_OK; | ||
856 | CURLMcode mret; | ||
857 | struct Plugin *plugin = s->plugin; | ||
858 | struct HTTP_Message *msg; | ||
859 | struct HTTP_Message *t; | ||
860 | |||
861 | if (GNUNET_YES != exist_session(plugin, s)) | ||
862 | { | ||
863 | GNUNET_break (0); | ||
864 | return GNUNET_SYSERR; | ||
865 | } | ||
866 | |||
867 | if (s->client_put != NULL) | ||
868 | { | ||
869 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
870 | "Client: %p / %p Deleting outbound PUT session to peer `%s'\n", | ||
871 | s, s->client_put, GNUNET_i2s (&s->target)); | ||
872 | |||
873 | /* remove curl handle from multi handle */ | ||
874 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_put); | ||
875 | if (mret != CURLM_OK) | ||
876 | { | ||
877 | /* clean up easy handle, handle is now invalid and free'd */ | ||
878 | res = GNUNET_SYSERR; | ||
879 | GNUNET_break (0); | ||
880 | } | ||
881 | curl_easy_cleanup (s->client_put); | ||
882 | s->client_put = NULL; | ||
883 | } | ||
884 | |||
885 | |||
886 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
887 | { | ||
888 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
889 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
890 | } | ||
891 | |||
892 | if (s->client_get != NULL) | ||
893 | { | ||
894 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
895 | "Client: %p / %p Deleting outbound GET session to peer `%s'\n", | ||
896 | s, | ||
897 | s->client_get, GNUNET_i2s (&s->target)); | ||
898 | |||
899 | /* remove curl handle from multi handle */ | ||
900 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_get); | ||
901 | if (mret != CURLM_OK) | ||
902 | { | ||
903 | /* clean up easy handle, handle is now invalid and free'd */ | ||
904 | res = GNUNET_SYSERR; | ||
905 | GNUNET_break (0); | ||
906 | } | ||
907 | curl_easy_cleanup (s->client_get); | ||
908 | s->client_get = NULL; | ||
909 | } | ||
910 | |||
911 | msg = s->msg_head; | ||
912 | while (msg != NULL) | ||
913 | { | ||
914 | t = msg->next; | ||
915 | if (NULL != msg->transmit_cont) | ||
916 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
917 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
918 | GNUNET_free (msg); | ||
919 | msg = t; | ||
920 | } | ||
921 | |||
922 | plugin->cur_connections -= 2; | ||
923 | |||
924 | notify_session_end (plugin, &s->target, s); | ||
925 | |||
926 | GNUNET_assert (plugin->outbound_sessions > 0); | ||
927 | plugin->outbound_sessions --; | ||
928 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
929 | "# HTTP outbound sessions", | ||
930 | plugin->outbound_sessions, | ||
931 | GNUNET_NO); | ||
932 | |||
933 | /* Re-schedule since handles have changed */ | ||
934 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
935 | { | ||
936 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
937 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
938 | } | ||
939 | client_schedule (plugin, GNUNET_YES); | ||
940 | |||
941 | return res; | ||
942 | #endif | ||
943 | GNUNET_break (0); | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | /** | ||
948 | * Session was idle, so disconnect it | ||
949 | */ | ||
950 | static void | ||
951 | client_session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
952 | { | ||
953 | GNUNET_assert (NULL != cls); | ||
954 | struct Session *s = cls; | ||
955 | |||
956 | s->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
957 | GNUNET_log (TIMEOUT_LOG, | ||
958 | "Session %p was idle for %llu ms, disconnecting\n", | ||
959 | s, (unsigned long long) TIMEOUT.rel_value); | ||
960 | |||
961 | /* call session destroy function */ | ||
962 | GNUNET_assert (GNUNET_OK == client_disconnect (s)); | ||
963 | } | ||
964 | |||
965 | /** | ||
966 | * Start session timeout | ||
967 | */ | ||
968 | static void | ||
969 | client_start_session_timeout (struct Session *s) | ||
970 | { | ||
971 | |||
972 | GNUNET_assert (NULL != s); | ||
973 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); | ||
974 | s->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
975 | &client_session_timeout, | ||
976 | s); | ||
977 | GNUNET_log (TIMEOUT_LOG, | ||
978 | "Timeout for session %p set to %llu ms\n", | ||
979 | s, (unsigned long long) TIMEOUT.rel_value); | ||
980 | GNUNET_break (0); | ||
981 | } | ||
982 | |||
983 | /** | ||
984 | * Increment session timeout due to activity | ||
985 | */ | ||
986 | static void | ||
987 | client_reschedule_session_timeout (struct Session *s) | ||
988 | { | ||
989 | #if 0 | ||
990 | GNUNET_assert (NULL != s); | ||
991 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); | ||
992 | |||
993 | GNUNET_SCHEDULER_cancel (s->timeout_task); | ||
994 | s->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
995 | &server_session_timeout, | ||
996 | s); | ||
997 | GNUNET_log (TIMEOUT_LOG, | ||
998 | "Timeout rescheduled for session %p set to %llu ms\n", | ||
999 | s, (unsigned long long) TIMEOUT.rel_value); | ||
1000 | #endif | ||
1001 | GNUNET_break (0); | ||
1002 | } | ||
1003 | |||
1004 | /** | ||
1005 | * Cancel timeout | ||
1006 | */ | ||
1007 | static void | ||
1008 | client_stop_session_timeout (struct Session *s) | ||
1009 | { | ||
1010 | GNUNET_assert (NULL != s); | ||
1011 | |||
1012 | if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) | ||
1013 | { | ||
1014 | GNUNET_SCHEDULER_cancel (s->timeout_task); | ||
1015 | s->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
1016 | GNUNET_log (TIMEOUT_LOG, "Timeout stopped for session %p\n", s); | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | |||
317 | /** | 1021 | /** |
318 | * Another peer has suggested an address for this | 1022 | * Another peer has suggested an address for this |
319 | * peer and transport plugin. Check that this could be a valid | 1023 | * peer and transport plugin. Check that this could be a valid |
@@ -344,7 +1048,12 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) | |||
344 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | 1048 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
345 | struct HTTP_Client_Plugin *plugin = api->cls; | 1049 | struct HTTP_Client_Plugin *plugin = api->cls; |
346 | 1050 | ||
347 | client_stop (plugin); | 1051 | if (NULL != plugin->curl_multi_handle) |
1052 | { | ||
1053 | curl_multi_cleanup (plugin->curl_multi_handle); | ||
1054 | plugin->curl_multi_handle = NULL; | ||
1055 | } | ||
1056 | curl_global_cleanup (); | ||
348 | 1057 | ||
349 | GNUNET_free (plugin); | 1058 | GNUNET_free (plugin); |
350 | GNUNET_free (api); | 1059 | GNUNET_free (api); |
@@ -363,6 +1072,7 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) | |||
363 | struct HTTP_Client_Plugin *plugin; | 1072 | struct HTTP_Client_Plugin *plugin; |
364 | 1073 | ||
365 | plugin = GNUNET_malloc (sizeof (struct HTTP_Client_Plugin)); | 1074 | plugin = GNUNET_malloc (sizeof (struct HTTP_Client_Plugin)); |
1075 | p = plugin; | ||
366 | plugin->env = env; | 1076 | plugin->env = env; |
367 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 1077 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
368 | api->cls = plugin; | 1078 | api->cls = plugin; |