diff options
author | Matthias Wachs <wachs@net.in.tum.de> | 2010-12-02 13:03:09 +0000 |
---|---|---|
committer | Matthias Wachs <wachs@net.in.tum.de> | 2010-12-02 13:03:09 +0000 |
commit | 2d8a83d2269d9f88032f4bac2a12cc1d156741c1 (patch) | |
tree | 9a9dc8541c691fa00f82e29831afe19f5d293eeb /src/transport/transport_api.c | |
parent | 411d7e9f4da9b4b4e696533471c09b7f629c2d87 (diff) | |
download | gnunet-2d8a83d2269d9f88032f4bac2a12cc1d156741c1.tar.gz gnunet-2d8a83d2269d9f88032f4bac2a12cc1d156741c1.zip |
this is a merged version of revision 13866 and my latestest changes without the old ats changes
all changes from r13826 not made from me are included
Diffstat (limited to 'src/transport/transport_api.c')
-rw-r--r-- | src/transport/transport_api.c | 425 |
1 files changed, 275 insertions, 150 deletions
diff --git a/src/transport/transport_api.c b/src/transport/transport_api.c index 643f8b0f4..4f9433c6c 100644 --- a/src/transport/transport_api.c +++ b/src/transport/transport_api.c | |||
@@ -60,6 +60,11 @@ | |||
60 | */ | 60 | */ |
61 | #define STOP_SERVICE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | 61 | #define STOP_SERVICE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) |
62 | 62 | ||
63 | /** | ||
64 | * How large to start with for the hashmap of neighbours. | ||
65 | */ | ||
66 | #define STARTING_NEIGHBOURS_SIZE 10 | ||
67 | |||
63 | 68 | ||
64 | /** | 69 | /** |
65 | * What stage are we in for transmission processing? | 70 | * What stage are we in for transmission processing? |
@@ -187,19 +192,34 @@ struct ControlMessage | |||
187 | 192 | ||
188 | }; | 193 | }; |
189 | 194 | ||
190 | |||
191 | /** | 195 | /** |
192 | * Entry in linked list of all of our current neighbours. | 196 | * Context for storing information about attempted next transmission. |
193 | */ | 197 | */ |
194 | struct NeighbourList | 198 | struct TryTransmitContext |
195 | { | 199 | { |
196 | 200 | ||
197 | /** | 201 | /** |
198 | * This is a linked list. | 202 | * Main transport handle. |
199 | */ | 203 | */ |
200 | struct NeighbourList *next; | 204 | struct GNUNET_TRANSPORT_Handle *h; |
205 | |||
206 | /** | ||
207 | * Returned transmission handle. | ||
208 | */ | ||
209 | struct GNUNET_TRANSPORT_TransmitHandle *ret; | ||
201 | 210 | ||
202 | /** | 211 | /** |
212 | * Time to retry the send task. | ||
213 | */ | ||
214 | struct GNUNET_TIME_Relative retry_time; | ||
215 | }; | ||
216 | |||
217 | /** | ||
218 | * Entry in hash table of all of our current neighbours. | ||
219 | */ | ||
220 | struct NeighbourList | ||
221 | { | ||
222 | /** | ||
203 | * Overall transport handle. | 223 | * Overall transport handle. |
204 | */ | 224 | */ |
205 | struct GNUNET_TRANSPORT_Handle *h; | 225 | struct GNUNET_TRANSPORT_Handle *h; |
@@ -235,6 +255,11 @@ struct NeighbourList | |||
235 | */ | 255 | */ |
236 | int is_connected; | 256 | int is_connected; |
237 | 257 | ||
258 | /** | ||
259 | * Are we in the middle of disconnecting the peer already? | ||
260 | */ | ||
261 | unsigned int in_disconnect; | ||
262 | |||
238 | }; | 263 | }; |
239 | 264 | ||
240 | 265 | ||
@@ -334,7 +359,7 @@ struct GNUNET_TRANSPORT_Handle | |||
334 | /** | 359 | /** |
335 | * Linked list of the current neighbours of this peer. | 360 | * Linked list of the current neighbours of this peer. |
336 | */ | 361 | */ |
337 | struct NeighbourList *neighbours; | 362 | struct GNUNET_CONTAINER_MultiHashMap *neighbours; |
338 | 363 | ||
339 | /** | 364 | /** |
340 | * Peer identity as assumed by this process, or all zeros. | 365 | * Peer identity as assumed by this process, or all zeros. |
@@ -371,7 +396,6 @@ struct GNUNET_TRANSPORT_Handle | |||
371 | }; | 396 | }; |
372 | 397 | ||
373 | 398 | ||
374 | // FIXME: replace with hash map! | ||
375 | /** | 399 | /** |
376 | * Get the neighbour list entry for the given peer | 400 | * Get the neighbour list entry for the given peer |
377 | * | 401 | * |
@@ -383,13 +407,7 @@ static struct NeighbourList * | |||
383 | neighbour_find (struct GNUNET_TRANSPORT_Handle *h, | 407 | neighbour_find (struct GNUNET_TRANSPORT_Handle *h, |
384 | const struct GNUNET_PeerIdentity *peer) | 408 | const struct GNUNET_PeerIdentity *peer) |
385 | { | 409 | { |
386 | struct NeighbourList *pos; | 410 | return GNUNET_CONTAINER_multihashmap_get(h->neighbours, &peer->hashPubKey); |
387 | |||
388 | pos = h->neighbours; | ||
389 | while ((pos != NULL) && | ||
390 | (0 != memcmp (peer, &pos->id, sizeof (struct GNUNET_PeerIdentity)))) | ||
391 | pos = pos->next; | ||
392 | return pos; | ||
393 | } | 411 | } |
394 | 412 | ||
395 | 413 | ||
@@ -418,6 +436,90 @@ quota_transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
418 | 436 | ||
419 | 437 | ||
420 | /** | 438 | /** |
439 | * Iterator over hash map entries, attempt to schedule | ||
440 | * a transmission to entries in the neighbour hashmap. | ||
441 | * | ||
442 | * @param cls closure a TryTransmitContext | ||
443 | * @param key current key code | ||
444 | * @param value value in the hash map, the neighbour entry to consider | ||
445 | * @return GNUNET_YES if we should continue to | ||
446 | * iterate, | ||
447 | * GNUNET_NO if not. | ||
448 | */ | ||
449 | static int | ||
450 | try_schedule_transmission (void *cls, | ||
451 | const GNUNET_HashCode * key, | ||
452 | void *value) | ||
453 | { | ||
454 | struct NeighbourList *n = value; | ||
455 | struct TryTransmitContext *try_transmit_ctx = cls; | ||
456 | struct GNUNET_TIME_Relative duration; | ||
457 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
458 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
459 | struct GNUNET_TIME_Absolute duration_abs; | ||
460 | |||
461 | if (n->transmit_stage != TS_QUEUED) | ||
462 | return GNUNET_YES; /* not eligible, keep iterating */ | ||
463 | if (n->is_connected != GNUNET_YES) | ||
464 | return GNUNET_YES; /* keep iterating */ | ||
465 | |||
466 | th = &n->transmit_handle; | ||
467 | GNUNET_break (n == th->neighbour); | ||
468 | /* check outgoing quota */ | ||
469 | duration = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, | ||
470 | th->notify_size - sizeof (struct OutboundMessage)); | ||
471 | duration_abs = GNUNET_TIME_relative_to_absolute (duration); | ||
472 | if (th->timeout.abs_value < duration_abs.abs_value) | ||
473 | { | ||
474 | /* signal timeout! */ | ||
475 | #if DEBUG_TRANSPORT | ||
476 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
477 | "Would need %llu ms before bandwidth is available for delivery to `%4s', that is too long. Signaling timeout.\n", | ||
478 | duration.rel_value, | ||
479 | GNUNET_i2s (&n->id)); | ||
480 | #endif | ||
481 | if (th->notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
482 | { | ||
483 | GNUNET_SCHEDULER_cancel (th->notify_delay_task); | ||
484 | th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
485 | } | ||
486 | n->transmit_stage = TS_NEW; | ||
487 | if (NULL != (notify = th->notify)) | ||
488 | { | ||
489 | th->notify = NULL; | ||
490 | GNUNET_assert (0 == notify (th->notify_cls, 0, NULL)); | ||
491 | } | ||
492 | return GNUNET_YES; /* keep iterating */ | ||
493 | } | ||
494 | if (duration.rel_value > 0) | ||
495 | { | ||
496 | #if DEBUG_TRANSPORT | ||
497 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
498 | "Need more bandwidth (%u b/s allowed, %u b needed), delaying delivery to `%4s' by %llu ms\n", | ||
499 | (unsigned int) n->out_tracker.available_bytes_per_s__, | ||
500 | (unsigned int) th->notify_size - sizeof (struct OutboundMessage), | ||
501 | GNUNET_i2s (&n->id), | ||
502 | (unsigned long long) duration.rel_value); | ||
503 | #endif | ||
504 | try_transmit_ctx->retry_time = GNUNET_TIME_relative_min (try_transmit_ctx->retry_time, | ||
505 | duration); | ||
506 | return GNUNET_YES; /* keep iterating */ | ||
507 | } | ||
508 | #if DEBUG_TRANSPORT | ||
509 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
510 | "Have %u bytes of bandwidth available for transmission to `%4s' right now\n", | ||
511 | th->notify_size - sizeof (struct OutboundMessage), | ||
512 | GNUNET_i2s (&n->id)); | ||
513 | #endif | ||
514 | |||
515 | if ( (try_transmit_ctx->ret == NULL) || | ||
516 | (try_transmit_ctx->ret->priority < th->priority) ) | ||
517 | try_transmit_ctx->ret = th; | ||
518 | return GNUNET_YES; | ||
519 | } | ||
520 | |||
521 | |||
522 | /** | ||
421 | * Figure out which transmission to a peer can be done right now. | 523 | * Figure out which transmission to a peer can be done right now. |
422 | * If none can, schedule a task to call 'schedule_transmission' | 524 | * If none can, schedule a task to call 'schedule_transmission' |
423 | * whenever a peer transmission can be done in the future and | 525 | * whenever a peer transmission can be done in the future and |
@@ -430,88 +532,24 @@ quota_transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
430 | static struct GNUNET_TRANSPORT_TransmitHandle * | 532 | static struct GNUNET_TRANSPORT_TransmitHandle * |
431 | schedule_peer_transmission (struct GNUNET_TRANSPORT_Handle *h) | 533 | schedule_peer_transmission (struct GNUNET_TRANSPORT_Handle *h) |
432 | { | 534 | { |
433 | struct GNUNET_TRANSPORT_TransmitHandle *ret; | 535 | struct TryTransmitContext try_transmit_ctx; |
434 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
435 | struct NeighbourList *n; | ||
436 | struct NeighbourList *next; | ||
437 | struct GNUNET_TIME_Relative retry_time; | ||
438 | struct GNUNET_TIME_Relative duration; | ||
439 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
440 | 536 | ||
441 | if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) | 537 | if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) |
442 | { | 538 | { |
443 | GNUNET_SCHEDULER_cancel (h->quota_task); | 539 | GNUNET_SCHEDULER_cancel (h->quota_task); |
444 | h->quota_task = GNUNET_SCHEDULER_NO_TASK; | 540 | h->quota_task = GNUNET_SCHEDULER_NO_TASK; |
445 | } | 541 | } |
446 | retry_time = GNUNET_TIME_UNIT_FOREVER_REL; | 542 | try_transmit_ctx.h = h; |
447 | ret = NULL; | 543 | try_transmit_ctx.ret = NULL; |
448 | next = h->neighbours; | 544 | try_transmit_ctx.retry_time = GNUNET_TIME_UNIT_FOREVER_REL; |
449 | while (NULL != (n = next)) | 545 | GNUNET_CONTAINER_multihashmap_iterate(h->neighbours, |
450 | { | 546 | &try_schedule_transmission, |
451 | next = n->next; | 547 | &try_transmit_ctx); |
452 | if (n->transmit_stage != TS_QUEUED) | 548 | if (try_transmit_ctx.ret == NULL) |
453 | continue; /* not eligible */ | 549 | h->quota_task = GNUNET_SCHEDULER_add_delayed (try_transmit_ctx.retry_time, |
454 | if (n->is_connected != GNUNET_YES) | ||
455 | continue; | ||
456 | |||
457 | th = &n->transmit_handle; | ||
458 | GNUNET_break (n == th->neighbour); | ||
459 | /* check outgoing quota */ | ||
460 | duration = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, | ||
461 | th->notify_size - sizeof (struct OutboundMessage)); | ||
462 | struct GNUNET_TIME_Absolute duration_abs = GNUNET_TIME_relative_to_absolute (duration); | ||
463 | if (th->timeout.abs_value < duration_abs.abs_value) | ||
464 | { | ||
465 | /* signal timeout! */ | ||
466 | #if DEBUG_TRANSPORT | ||
467 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
468 | "Would need %llu ms before bandwidth is available for delivery to `%4s', that is too long. Signaling timeout.\n", | ||
469 | duration.rel_value, | ||
470 | GNUNET_i2s (&n->id)); | ||
471 | #endif | ||
472 | if (th->notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
473 | { | ||
474 | GNUNET_SCHEDULER_cancel (th->notify_delay_task); | ||
475 | th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
476 | } | ||
477 | n->transmit_stage = TS_NEW; | ||
478 | if (NULL != (notify = th->notify)) | ||
479 | { | ||
480 | th->notify = NULL; | ||
481 | GNUNET_assert (0 == notify (th->notify_cls, 0, NULL)); | ||
482 | } | ||
483 | continue; | ||
484 | } | ||
485 | if (duration.rel_value > 0) | ||
486 | { | ||
487 | #if DEBUG_TRANSPORT | ||
488 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
489 | "Need more bandwidth (%u b/s allowed, %u b needed), delaying delivery to `%4s' by %llu ms\n", | ||
490 | (unsigned int) n->out_tracker.available_bytes_per_s__, | ||
491 | (unsigned int) th->notify_size - sizeof (struct OutboundMessage), | ||
492 | GNUNET_i2s (&n->id), | ||
493 | duration.rel_value); | ||
494 | #endif | ||
495 | retry_time = GNUNET_TIME_relative_min (retry_time, | ||
496 | duration); | ||
497 | continue; | ||
498 | } | ||
499 | #if DEBUG_TRANSPORT | ||
500 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
501 | "Have %u bytes of bandwidth available for transmission to `%4s' right now\n", | ||
502 | th->notify_size - sizeof (struct OutboundMessage), | ||
503 | GNUNET_i2s (&n->id)); | ||
504 | #endif | ||
505 | |||
506 | if ( (ret == NULL) || | ||
507 | (ret->priority < th->priority) ) | ||
508 | ret = th; | ||
509 | } | ||
510 | if (ret == NULL) | ||
511 | h->quota_task = GNUNET_SCHEDULER_add_delayed (retry_time, | ||
512 | "a_transmit_ready, | 550 | "a_transmit_ready, |
513 | h); | 551 | h); |
514 | return ret; | 552 | return try_transmit_ctx.ret; |
515 | } | 553 | } |
516 | 554 | ||
517 | 555 | ||
@@ -777,18 +815,39 @@ schedule_control_transmit (struct GNUNET_TRANSPORT_Handle *h, | |||
777 | } | 815 | } |
778 | 816 | ||
779 | 817 | ||
818 | /** | ||
819 | * FIXME: document | ||
820 | */ | ||
780 | struct SetQuotaContext | 821 | struct SetQuotaContext |
781 | { | 822 | { |
823 | /** | ||
824 | * FIXME: document | ||
825 | */ | ||
782 | struct GNUNET_TRANSPORT_Handle *handle; | 826 | struct GNUNET_TRANSPORT_Handle *handle; |
783 | 827 | ||
828 | /** | ||
829 | * FIXME: document | ||
830 | */ | ||
784 | struct GNUNET_PeerIdentity target; | 831 | struct GNUNET_PeerIdentity target; |
785 | 832 | ||
833 | /** | ||
834 | * FIXME: document | ||
835 | */ | ||
786 | GNUNET_SCHEDULER_Task cont; | 836 | GNUNET_SCHEDULER_Task cont; |
787 | 837 | ||
838 | /** | ||
839 | * Closure for 'cont'. | ||
840 | */ | ||
788 | void *cont_cls; | 841 | void *cont_cls; |
789 | 842 | ||
843 | /** | ||
844 | * FIXME: document | ||
845 | */ | ||
790 | struct GNUNET_TIME_Absolute timeout; | 846 | struct GNUNET_TIME_Absolute timeout; |
791 | 847 | ||
848 | /** | ||
849 | * FIXME: document | ||
850 | */ | ||
792 | struct GNUNET_BANDWIDTH_Value32NBO quota_in; | 851 | struct GNUNET_BANDWIDTH_Value32NBO quota_in; |
793 | }; | 852 | }; |
794 | 853 | ||
@@ -809,9 +868,10 @@ send_set_quota (void *cls, size_t size, void *buf) | |||
809 | 868 | ||
810 | if (buf == NULL) | 869 | if (buf == NULL) |
811 | { | 870 | { |
812 | GNUNET_SCHEDULER_add_continuation (sqc->cont, | 871 | if (sqc->cont != NULL) |
813 | sqc->cont_cls, | 872 | GNUNET_SCHEDULER_add_continuation (sqc->cont, |
814 | GNUNET_SCHEDULER_REASON_TIMEOUT); | 873 | sqc->cont_cls, |
874 | GNUNET_SCHEDULER_REASON_TIMEOUT); | ||
815 | GNUNET_free (sqc); | 875 | GNUNET_free (sqc); |
816 | return 0; | 876 | return 0; |
817 | } | 877 | } |
@@ -1090,9 +1150,21 @@ static void | |||
1090 | neighbour_free (struct NeighbourList *n) | 1150 | neighbour_free (struct NeighbourList *n) |
1091 | { | 1151 | { |
1092 | struct GNUNET_TRANSPORT_Handle *h; | 1152 | struct GNUNET_TRANSPORT_Handle *h; |
1093 | struct NeighbourList *prev; | ||
1094 | struct NeighbourList *pos; | ||
1095 | 1153 | ||
1154 | /* Added so task gets canceled when a disconnect is received! */ | ||
1155 | /* Method 1 | ||
1156 | if (n->transmit_handle.notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
1157 | { | ||
1158 | GNUNET_SCHEDULER_cancel(n->transmit_handle.notify_delay_task); | ||
1159 | n->transmit_handle.notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
1160 | n->transmit_handle.notify = NULL; | ||
1161 | } | ||
1162 | */ | ||
1163 | /* NATE: if the above is not needed, then clearly this assertion | ||
1164 | should hold (I've checked the code and I'm pretty sure this is | ||
1165 | true. -CG | ||
1166 | FIXME: remove above comments once we've seen tests pass with the assert... */ | ||
1167 | GNUNET_assert (n->transmit_handle.notify_delay_task == GNUNET_SCHEDULER_NO_TASK); | ||
1096 | GNUNET_assert (n->transmit_handle.notify == NULL); | 1168 | GNUNET_assert (n->transmit_handle.notify == NULL); |
1097 | h = n->h; | 1169 | h = n->h; |
1098 | #if DEBUG_TRANSPORT | 1170 | #if DEBUG_TRANSPORT |
@@ -1103,17 +1175,10 @@ neighbour_free (struct NeighbourList *n) | |||
1103 | GNUNET_break (n->is_connected == GNUNET_NO); | 1175 | GNUNET_break (n->is_connected == GNUNET_NO); |
1104 | GNUNET_break (n->transmit_stage == TS_NEW); | 1176 | GNUNET_break (n->transmit_stage == TS_NEW); |
1105 | 1177 | ||
1106 | prev = NULL; | 1178 | GNUNET_assert(GNUNET_YES == |
1107 | pos = h->neighbours; | 1179 | GNUNET_CONTAINER_multihashmap_remove(h->neighbours, |
1108 | while (pos != n) | 1180 | &n->id.hashPubKey, |
1109 | { | 1181 | n)); |
1110 | prev = pos; | ||
1111 | pos = pos->next; | ||
1112 | } | ||
1113 | if (prev == NULL) | ||
1114 | h->neighbours = n->next; | ||
1115 | else | ||
1116 | prev->next = n->next; | ||
1117 | GNUNET_free (n); | 1182 | GNUNET_free (n); |
1118 | } | 1183 | } |
1119 | 1184 | ||
@@ -1134,6 +1199,14 @@ neighbour_disconnect (struct NeighbourList *n) | |||
1134 | #endif | 1199 | #endif |
1135 | GNUNET_break (n->is_connected == GNUNET_YES); | 1200 | GNUNET_break (n->is_connected == GNUNET_YES); |
1136 | n->is_connected = GNUNET_NO; | 1201 | n->is_connected = GNUNET_NO; |
1202 | /* FIXME: this 'in_disconnect' flag is dubious; we should define | ||
1203 | clearly what disconnect means for pending 'notify_transmit_ready' | ||
1204 | requests; maybe a good approach is to REQUIRE clients to | ||
1205 | call 'notify_transmit_ready_cancel' on pending requests on disconnect | ||
1206 | and otherwise FAIL HARD with an assertion failure before | ||
1207 | 'neighbour_free' right here (transmit_stage would be forced | ||
1208 | to 'TS_NEW') */ | ||
1209 | n->in_disconnect = GNUNET_YES; | ||
1137 | if (h->nd_cb != NULL) | 1210 | if (h->nd_cb != NULL) |
1138 | h->nd_cb (h->cls, &n->id); | 1211 | h->nd_cb (h->cls, &n->id); |
1139 | if (n->transmit_stage == TS_NEW) | 1212 | if (n->transmit_stage == TS_NEW) |
@@ -1153,6 +1226,35 @@ static void demultiplexer (void *cls, | |||
1153 | 1226 | ||
1154 | 1227 | ||
1155 | /** | 1228 | /** |
1229 | * Iterator over hash map entries, for getting rid of a neighbor | ||
1230 | * upon a reconnect call. | ||
1231 | * | ||
1232 | * @param cls closure (NULL) | ||
1233 | * @param key current key code | ||
1234 | * @param value value in the hash map, the neighbour entry to forget | ||
1235 | * @return GNUNET_YES if we should continue to | ||
1236 | * iterate, | ||
1237 | * GNUNET_NO if not. | ||
1238 | */ | ||
1239 | static int | ||
1240 | forget_neighbours (void *cls, | ||
1241 | const GNUNET_HashCode * key, | ||
1242 | void *value) | ||
1243 | { | ||
1244 | struct NeighbourList *n = value; | ||
1245 | |||
1246 | #if DEBUG_TRANSPORT_DISCONNECT | ||
1247 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1248 | "Disconnecting due to reconnect being called\n"); | ||
1249 | #endif | ||
1250 | if (n->is_connected) | ||
1251 | neighbour_disconnect (n); | ||
1252 | |||
1253 | return GNUNET_YES; | ||
1254 | } | ||
1255 | |||
1256 | |||
1257 | /** | ||
1156 | * Try again to connect to transport service. | 1258 | * Try again to connect to transport service. |
1157 | * | 1259 | * |
1158 | * @param cls the handle to the transport service | 1260 | * @param cls the handle to the transport service |
@@ -1164,8 +1266,6 @@ reconnect (void *cls, | |||
1164 | { | 1266 | { |
1165 | struct GNUNET_TRANSPORT_Handle *h = cls; | 1267 | struct GNUNET_TRANSPORT_Handle *h = cls; |
1166 | struct ControlMessage *pos; | 1268 | struct ControlMessage *pos; |
1167 | struct NeighbourList *n; | ||
1168 | struct NeighbourList *next; | ||
1169 | 1269 | ||
1170 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | 1270 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; |
1171 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | 1271 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) |
@@ -1174,18 +1274,10 @@ reconnect (void *cls, | |||
1174 | return; | 1274 | return; |
1175 | } | 1275 | } |
1176 | /* Forget about all neighbours that we used to be connected to */ | 1276 | /* Forget about all neighbours that we used to be connected to */ |
1177 | n = h->neighbours; | 1277 | GNUNET_CONTAINER_multihashmap_iterate(h->neighbours, |
1178 | while (NULL != n) | 1278 | &forget_neighbours, |
1179 | { | 1279 | NULL); |
1180 | #if DEBUG_TRANSPORT_DISCONNECT | 1280 | |
1181 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1182 | "Disconnecting due to reconnect being called\n"); | ||
1183 | #endif | ||
1184 | next = n->next; | ||
1185 | if (n->is_connected) | ||
1186 | neighbour_disconnect (n); | ||
1187 | n = next; | ||
1188 | } | ||
1189 | #if DEBUG_TRANSPORT | 1281 | #if DEBUG_TRANSPORT |
1190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1282 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1191 | "Connecting to transport service.\n"); | 1283 | "Connecting to transport service.\n"); |
@@ -1310,6 +1402,7 @@ send_request_connect_message(struct GNUNET_TRANSPORT_Handle *h, struct Neighbour | |||
1310 | GNUNET_TIME_UNIT_FOREVER_REL, &send_transport_request_connect, trcm); | 1402 | GNUNET_TIME_UNIT_FOREVER_REL, &send_transport_request_connect, trcm); |
1311 | } | 1403 | } |
1312 | 1404 | ||
1405 | |||
1313 | /** | 1406 | /** |
1314 | * Add neighbour to our list | 1407 | * Add neighbour to our list |
1315 | * | 1408 | * |
@@ -1336,19 +1429,62 @@ neighbour_add (struct GNUNET_TRANSPORT_Handle *h, | |||
1336 | #endif | 1429 | #endif |
1337 | n = GNUNET_malloc (sizeof (struct NeighbourList)); | 1430 | n = GNUNET_malloc (sizeof (struct NeighbourList)); |
1338 | n->id = *pid; | 1431 | n->id = *pid; |
1432 | n->h = h; | ||
1339 | GNUNET_BANDWIDTH_tracker_init (&n->out_tracker, | 1433 | GNUNET_BANDWIDTH_tracker_init (&n->out_tracker, |
1340 | GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, | 1434 | GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, |
1341 | MAX_BANDWIDTH_CARRY_S); | 1435 | MAX_BANDWIDTH_CARRY_S); |
1342 | n->next = h->neighbours; | 1436 | GNUNET_CONTAINER_multihashmap_put (h->neighbours, |
1343 | n->h = h; | 1437 | &pid->hashPubKey, |
1344 | h->neighbours = n; | 1438 | n, |
1345 | 1439 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | |
1346 | 1440 | ||
1347 | return n; | 1441 | return n; |
1348 | } | 1442 | } |
1349 | 1443 | ||
1350 | 1444 | ||
1351 | /** | 1445 | /** |
1446 | * Iterator over hash map entries, for deleting state of a neighbor. | ||
1447 | * | ||
1448 | * @param cls closure (NULL) | ||
1449 | * @param key current key code | ||
1450 | * @param value value in the hash map, the neighbour entry to delete | ||
1451 | * @return GNUNET_YES if we should continue to | ||
1452 | * iterate, | ||
1453 | * GNUNET_NO if not. | ||
1454 | */ | ||
1455 | static int | ||
1456 | delete_neighbours (void *cls, | ||
1457 | const GNUNET_HashCode * key, | ||
1458 | void *value) | ||
1459 | { | ||
1460 | struct NeighbourList *n = value; | ||
1461 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
1462 | |||
1463 | switch (n->transmit_stage) | ||
1464 | { | ||
1465 | case TS_NEW: | ||
1466 | case TS_TRANSMITTED: | ||
1467 | /* nothing to do */ | ||
1468 | break; | ||
1469 | case TS_QUEUED: | ||
1470 | case TS_TRANSMITTED_QUEUED: | ||
1471 | th = &n->transmit_handle; | ||
1472 | if (th->notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
1473 | { | ||
1474 | GNUNET_SCHEDULER_cancel (th->notify_delay_task); | ||
1475 | th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
1476 | } | ||
1477 | GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL)); | ||
1478 | break; | ||
1479 | default: | ||
1480 | GNUNET_break (0); | ||
1481 | } | ||
1482 | GNUNET_free (n); | ||
1483 | return GNUNET_YES; | ||
1484 | } | ||
1485 | |||
1486 | |||
1487 | /** | ||
1352 | * Connect to the transport service. Note that the connection may | 1488 | * Connect to the transport service. Note that the connection may |
1353 | * complete (or fail) asynchronously. | 1489 | * complete (or fail) asynchronously. |
1354 | * | 1490 | * |
@@ -1382,6 +1518,7 @@ GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
1382 | ret->nc_cb = nc; | 1518 | ret->nc_cb = nc; |
1383 | ret->nd_cb = nd; | 1519 | ret->nd_cb = nd; |
1384 | ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; | 1520 | ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; |
1521 | ret->neighbours = GNUNET_CONTAINER_multihashmap_create(STARTING_NEIGHBOURS_SIZE); | ||
1385 | schedule_reconnect (ret); | 1522 | schedule_reconnect (ret); |
1386 | return ret; | 1523 | return ret; |
1387 | } | 1524 | } |
@@ -1393,8 +1530,6 @@ GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
1393 | void | 1530 | void |
1394 | GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) | 1531 | GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) |
1395 | { | 1532 | { |
1396 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
1397 | struct NeighbourList *n; | ||
1398 | struct HelloWaitList *hwl; | 1533 | struct HelloWaitList *hwl; |
1399 | struct GNUNET_CLIENT_Connection *client; | 1534 | struct GNUNET_CLIENT_Connection *client; |
1400 | struct ControlMessage *cm; | 1535 | struct ControlMessage *cm; |
@@ -1402,31 +1537,20 @@ GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) | |||
1402 | #if DEBUG_TRANSPORT | 1537 | #if DEBUG_TRANSPORT |
1403 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n"); | 1538 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n"); |
1404 | #endif | 1539 | #endif |
1540 | /* FIXME: this flag is dubious, we should be able to do this | ||
1541 | more cleanly; also, we should probably do 'disconnect' | ||
1542 | callbacks for every connected peer here, i.e. by calling | ||
1543 | the iterator with 'forget_neighbours' instead of 'delete_neighbours'. | ||
1544 | */ | ||
1545 | |||
1405 | handle->in_disconnect = GNUNET_YES; | 1546 | handle->in_disconnect = GNUNET_YES; |
1406 | while (NULL != (n = handle->neighbours)) | 1547 | |
1407 | { | 1548 | GNUNET_assert (GNUNET_SYSERR != |
1408 | handle->neighbours = n->next; | 1549 | GNUNET_CONTAINER_multihashmap_iterate(handle->neighbours, |
1409 | switch (n->transmit_stage) | 1550 | &delete_neighbours, |
1410 | { | 1551 | handle)); |
1411 | case TS_NEW: | 1552 | GNUNET_CONTAINER_multihashmap_destroy (handle->neighbours); |
1412 | case TS_TRANSMITTED: | 1553 | |
1413 | /* nothing to do */ | ||
1414 | break; | ||
1415 | case TS_QUEUED: | ||
1416 | case TS_TRANSMITTED_QUEUED: | ||
1417 | th = &n->transmit_handle; | ||
1418 | if (th->notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
1419 | { | ||
1420 | GNUNET_SCHEDULER_cancel (th->notify_delay_task); | ||
1421 | th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
1422 | } | ||
1423 | GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL)); | ||
1424 | break; | ||
1425 | default: | ||
1426 | GNUNET_break (0); | ||
1427 | } | ||
1428 | GNUNET_free (n); | ||
1429 | } | ||
1430 | while (NULL != (hwl = handle->hwl_head)) | 1554 | while (NULL != (hwl = handle->hwl_head)) |
1431 | { | 1555 | { |
1432 | handle->hwl_head = hwl->next; | 1556 | handle->hwl_head = hwl->next; |
@@ -1886,7 +2010,7 @@ GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct | |||
1886 | n = th->neighbour; | 2010 | n = th->neighbour; |
1887 | #if DEBUG_TRANSPORT | 2011 | #if DEBUG_TRANSPORT |
1888 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2012 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1889 | "Transmission request of %u bytes to `%4s' was cancelled.\n", | 2013 | "Transmission request of %u bytes to `%4s' was canceled.\n", |
1890 | th->notify_size - sizeof (struct OutboundMessage), | 2014 | th->notify_size - sizeof (struct OutboundMessage), |
1891 | GNUNET_i2s (&n->id)); | 2015 | GNUNET_i2s (&n->id)); |
1892 | #endif | 2016 | #endif |
@@ -1902,7 +2026,8 @@ GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct | |||
1902 | break; | 2026 | break; |
1903 | case TS_QUEUED: | 2027 | case TS_QUEUED: |
1904 | n->transmit_stage = TS_NEW; | 2028 | n->transmit_stage = TS_NEW; |
1905 | if (n->is_connected == GNUNET_NO) | 2029 | if ( (n->in_disconnect == GNUNET_NO) && |
2030 | (n->is_connected == GNUNET_NO) ) | ||
1906 | neighbour_free (n); | 2031 | neighbour_free (n); |
1907 | break; | 2032 | break; |
1908 | case TS_TRANSMITTED: | 2033 | case TS_TRANSMITTED: |