diff options
author | Nathan S. Evans <evans@in.tum.de> | 2010-11-30 17:05:17 +0000 |
---|---|---|
committer | Nathan S. Evans <evans@in.tum.de> | 2010-11-30 17:05:17 +0000 |
commit | 7f806de4dcf1c2d71bfad522a2c7f8cf1d82566e (patch) | |
tree | 478e6490ec647b563ca695d899f7d655cb580cac /src/transport/transport_api.c | |
parent | 6075973b278f72f81de967c978706e80d6b79978 (diff) | |
download | gnunet-7f806de4dcf1c2d71bfad522a2c7f8cf1d82566e.tar.gz gnunet-7f806de4dcf1c2d71bfad522a2c7f8cf1d82566e.zip |
use hashmap instead of linked list of neighbors, fix for double free
Diffstat (limited to 'src/transport/transport_api.c')
-rw-r--r-- | src/transport/transport_api.c | 377 |
1 files changed, 230 insertions, 147 deletions
diff --git a/src/transport/transport_api.c b/src/transport/transport_api.c index 3d35f8d0b..23f8c71a7 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,39 @@ 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 | * Temporary transmit handle. | ||
213 | */ | ||
214 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
215 | |||
216 | /** | ||
217 | * Time to retry the send task. | ||
218 | */ | ||
219 | struct GNUNET_TIME_Relative retry_time; | ||
220 | }; | ||
221 | |||
222 | /** | ||
223 | * Entry in hash table of all of our current neighbours. | ||
224 | */ | ||
225 | struct NeighbourList | ||
226 | { | ||
227 | /** | ||
203 | * Overall transport handle. | 228 | * Overall transport handle. |
204 | */ | 229 | */ |
205 | struct GNUNET_TRANSPORT_Handle *h; | 230 | struct GNUNET_TRANSPORT_Handle *h; |
@@ -235,6 +260,11 @@ struct NeighbourList | |||
235 | */ | 260 | */ |
236 | int is_connected; | 261 | int is_connected; |
237 | 262 | ||
263 | /** | ||
264 | * Are we in the middle of disconnecting the peer already? | ||
265 | */ | ||
266 | unsigned int in_disconnect; | ||
267 | |||
238 | }; | 268 | }; |
239 | 269 | ||
240 | 270 | ||
@@ -334,7 +364,7 @@ struct GNUNET_TRANSPORT_Handle | |||
334 | /** | 364 | /** |
335 | * Linked list of the current neighbours of this peer. | 365 | * Linked list of the current neighbours of this peer. |
336 | */ | 366 | */ |
337 | struct NeighbourList *neighbours; | 367 | struct GNUNET_CONTAINER_MultiHashMap *neighbours; |
338 | 368 | ||
339 | /** | 369 | /** |
340 | * Peer identity as assumed by this process, or all zeros. | 370 | * Peer identity as assumed by this process, or all zeros. |
@@ -383,13 +413,10 @@ static struct NeighbourList * | |||
383 | neighbour_find (struct GNUNET_TRANSPORT_Handle *h, | 413 | neighbour_find (struct GNUNET_TRANSPORT_Handle *h, |
384 | const struct GNUNET_PeerIdentity *peer) | 414 | const struct GNUNET_PeerIdentity *peer) |
385 | { | 415 | { |
386 | struct NeighbourList *pos; | 416 | if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains(h->neighbours, &peer->hashPubKey)) |
417 | return NULL; | ||
387 | 418 | ||
388 | pos = h->neighbours; | 419 | return GNUNET_CONTAINER_multihashmap_get(h->neighbours, &peer->hashPubKey); |
389 | while ((pos != NULL) && | ||
390 | (0 != memcmp (peer, &pos->id, sizeof (struct GNUNET_PeerIdentity)))) | ||
391 | pos = pos->next; | ||
392 | return pos; | ||
393 | } | 420 | } |
394 | 421 | ||
395 | 422 | ||
@@ -416,6 +443,87 @@ quota_transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
416 | schedule_transmission (h); | 443 | schedule_transmission (h); |
417 | } | 444 | } |
418 | 445 | ||
446 | /** | ||
447 | * Iterator over hash map entries, attempt to schedule | ||
448 | * a transmission to entries in the neighbour hashmap. | ||
449 | * | ||
450 | * @param cls closure a TryTransmitContext | ||
451 | * @param key current key code | ||
452 | * @param value value in the hash map, the neighbour entry to consider | ||
453 | * @return GNUNET_YES if we should continue to | ||
454 | * iterate, | ||
455 | * GNUNET_NO if not. | ||
456 | */ | ||
457 | static int | ||
458 | try_schedule_transmission (void *cls, | ||
459 | const GNUNET_HashCode * key, | ||
460 | void *value) | ||
461 | { | ||
462 | struct NeighbourList *n = value; | ||
463 | struct TryTransmitContext *try_transmit_ctx = cls; | ||
464 | struct GNUNET_TIME_Relative duration; | ||
465 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
466 | |||
467 | if (n->transmit_stage != TS_QUEUED) | ||
468 | return GNUNET_YES; /* not eligible, keep iterating */ | ||
469 | if (n->is_connected != GNUNET_YES) | ||
470 | return GNUNET_YES; /* keep iterating */ | ||
471 | |||
472 | try_transmit_ctx->th = &n->transmit_handle; | ||
473 | GNUNET_break (n == try_transmit_ctx->th->neighbour); | ||
474 | /* check outgoing quota */ | ||
475 | duration = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, | ||
476 | try_transmit_ctx->th->notify_size - sizeof (struct OutboundMessage)); | ||
477 | struct GNUNET_TIME_Absolute duration_abs = GNUNET_TIME_relative_to_absolute (duration); | ||
478 | if (try_transmit_ctx->th->timeout.abs_value < duration_abs.abs_value) | ||
479 | { | ||
480 | /* signal timeout! */ | ||
481 | #if DEBUG_TRANSPORT | ||
482 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
483 | "Would need %llu ms before bandwidth is available for delivery to `%4s', that is too long. Signaling timeout.\n", | ||
484 | duration.rel_value, | ||
485 | GNUNET_i2s (&n->id)); | ||
486 | #endif | ||
487 | if (try_transmit_ctx->th->notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
488 | { | ||
489 | GNUNET_SCHEDULER_cancel (try_transmit_ctx->th->notify_delay_task); | ||
490 | try_transmit_ctx->th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
491 | } | ||
492 | n->transmit_stage = TS_NEW; | ||
493 | if (NULL != (notify = try_transmit_ctx->th->notify)) | ||
494 | { | ||
495 | try_transmit_ctx->th->notify = NULL; | ||
496 | GNUNET_assert (0 == notify (try_transmit_ctx->th->notify_cls, 0, NULL)); | ||
497 | } | ||
498 | return GNUNET_YES; /* keep iterating */ | ||
499 | } | ||
500 | if (duration.rel_value > 0) | ||
501 | { | ||
502 | #if DEBUG_TRANSPORT | ||
503 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
504 | "Need more bandwidth (%u b/s allowed, %u b needed), delaying delivery to `%4s' by %llu ms\n", | ||
505 | (unsigned int) n->out_tracker.available_bytes_per_s__, | ||
506 | (unsigned int) try_transmit_ctx->th->notify_size - sizeof (struct OutboundMessage), | ||
507 | GNUNET_i2s (&n->id), | ||
508 | duration.rel_value); | ||
509 | #endif | ||
510 | try_transmit_ctx->retry_time = GNUNET_TIME_relative_min (try_transmit_ctx->retry_time, | ||
511 | duration); | ||
512 | return GNUNET_YES; /* keep iterating */ | ||
513 | } | ||
514 | #if DEBUG_TRANSPORT | ||
515 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
516 | "Have %u bytes of bandwidth available for transmission to `%4s' right now\n", | ||
517 | try_transmit_ctx->th->notify_size - sizeof (struct OutboundMessage), | ||
518 | GNUNET_i2s (&n->id)); | ||
519 | #endif | ||
520 | |||
521 | if ( (try_transmit_ctx->ret == NULL) || | ||
522 | (try_transmit_ctx->ret->priority < try_transmit_ctx->th->priority) ) | ||
523 | try_transmit_ctx->ret = try_transmit_ctx->th; | ||
524 | |||
525 | return GNUNET_YES; | ||
526 | } | ||
419 | 527 | ||
420 | /** | 528 | /** |
421 | * Figure out which transmission to a peer can be done right now. | 529 | * Figure out which transmission to a peer can be done right now. |
@@ -430,88 +538,23 @@ quota_transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
430 | static struct GNUNET_TRANSPORT_TransmitHandle * | 538 | static struct GNUNET_TRANSPORT_TransmitHandle * |
431 | schedule_peer_transmission (struct GNUNET_TRANSPORT_Handle *h) | 539 | schedule_peer_transmission (struct GNUNET_TRANSPORT_Handle *h) |
432 | { | 540 | { |
433 | struct GNUNET_TRANSPORT_TransmitHandle *ret; | 541 | |
434 | struct GNUNET_TRANSPORT_TransmitHandle *th; | 542 | struct TryTransmitContext try_transmit_ctx; |
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 | 543 | ||
441 | if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) | 544 | if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) |
442 | { | 545 | { |
443 | GNUNET_SCHEDULER_cancel (h->quota_task); | 546 | GNUNET_SCHEDULER_cancel (h->quota_task); |
444 | h->quota_task = GNUNET_SCHEDULER_NO_TASK; | 547 | h->quota_task = GNUNET_SCHEDULER_NO_TASK; |
445 | } | 548 | } |
446 | retry_time = GNUNET_TIME_UNIT_FOREVER_REL; | 549 | memset(&try_transmit_ctx, 0, sizeof(struct TryTransmitContext)); |
447 | ret = NULL; | 550 | try_transmit_ctx.retry_time = GNUNET_TIME_UNIT_FOREVER_REL; |
448 | next = h->neighbours; | 551 | GNUNET_CONTAINER_multihashmap_iterate(h->neighbours, &try_schedule_transmission, &try_transmit_ctx); |
449 | while (NULL != (n = next)) | ||
450 | { | ||
451 | next = n->next; | ||
452 | if (n->transmit_stage != TS_QUEUED) | ||
453 | continue; /* not eligible */ | ||
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 | 552 | ||
506 | if ( (ret == NULL) || | 553 | if (try_transmit_ctx.ret == NULL) |
507 | (ret->priority < th->priority) ) | 554 | h->quota_task = GNUNET_SCHEDULER_add_delayed (try_transmit_ctx.retry_time, |
508 | ret = th; | ||
509 | } | ||
510 | if (ret == NULL) | ||
511 | h->quota_task = GNUNET_SCHEDULER_add_delayed (retry_time, | ||
512 | "a_transmit_ready, | 555 | "a_transmit_ready, |
513 | h); | 556 | h); |
514 | return ret; | 557 | return try_transmit_ctx.ret; |
515 | } | 558 | } |
516 | 559 | ||
517 | 560 | ||
@@ -809,9 +852,10 @@ send_set_quota (void *cls, size_t size, void *buf) | |||
809 | 852 | ||
810 | if (buf == NULL) | 853 | if (buf == NULL) |
811 | { | 854 | { |
812 | GNUNET_SCHEDULER_add_continuation (sqc->cont, | 855 | if (sqc->cont != NULL) |
813 | sqc->cont_cls, | 856 | GNUNET_SCHEDULER_add_continuation (sqc->cont, |
814 | GNUNET_SCHEDULER_REASON_TIMEOUT); | 857 | sqc->cont_cls, |
858 | GNUNET_SCHEDULER_REASON_TIMEOUT); | ||
815 | GNUNET_free (sqc); | 859 | GNUNET_free (sqc); |
816 | return 0; | 860 | return 0; |
817 | } | 861 | } |
@@ -1090,8 +1134,16 @@ static void | |||
1090 | neighbour_free (struct NeighbourList *n) | 1134 | neighbour_free (struct NeighbourList *n) |
1091 | { | 1135 | { |
1092 | struct GNUNET_TRANSPORT_Handle *h; | 1136 | struct GNUNET_TRANSPORT_Handle *h; |
1093 | struct NeighbourList *prev; | 1137 | |
1094 | struct NeighbourList *pos; | 1138 | /* Added so task gets canceled when a disconnect is received! */ |
1139 | /* Method 1 | ||
1140 | if (n->transmit_handle.notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
1141 | { | ||
1142 | GNUNET_SCHEDULER_cancel(n->transmit_handle.notify_delay_task); | ||
1143 | n->transmit_handle.notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
1144 | n->transmit_handle.notify = NULL; | ||
1145 | } | ||
1146 | */ | ||
1095 | 1147 | ||
1096 | GNUNET_assert (n->transmit_handle.notify == NULL); | 1148 | GNUNET_assert (n->transmit_handle.notify == NULL); |
1097 | h = n->h; | 1149 | h = n->h; |
@@ -1103,17 +1155,8 @@ neighbour_free (struct NeighbourList *n) | |||
1103 | GNUNET_break (n->is_connected == GNUNET_NO); | 1155 | GNUNET_break (n->is_connected == GNUNET_NO); |
1104 | GNUNET_break (n->transmit_stage == TS_NEW); | 1156 | GNUNET_break (n->transmit_stage == TS_NEW); |
1105 | 1157 | ||
1106 | prev = NULL; | 1158 | GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(h->neighbours, &n->id.hashPubKey, n)); |
1107 | pos = h->neighbours; | 1159 | |
1108 | while (pos != n) | ||
1109 | { | ||
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); | 1160 | GNUNET_free (n); |
1118 | } | 1161 | } |
1119 | 1162 | ||
@@ -1134,6 +1177,7 @@ neighbour_disconnect (struct NeighbourList *n) | |||
1134 | #endif | 1177 | #endif |
1135 | GNUNET_break (n->is_connected == GNUNET_YES); | 1178 | GNUNET_break (n->is_connected == GNUNET_YES); |
1136 | n->is_connected = GNUNET_NO; | 1179 | n->is_connected = GNUNET_NO; |
1180 | n->in_disconnect = GNUNET_YES; | ||
1137 | if (h->nd_cb != NULL) | 1181 | if (h->nd_cb != NULL) |
1138 | h->nd_cb (h->cls, &n->id); | 1182 | h->nd_cb (h->cls, &n->id); |
1139 | if (n->transmit_stage == TS_NEW) | 1183 | if (n->transmit_stage == TS_NEW) |
@@ -1153,6 +1197,33 @@ static void demultiplexer (void *cls, | |||
1153 | 1197 | ||
1154 | 1198 | ||
1155 | /** | 1199 | /** |
1200 | * Iterator over hash map entries, for getting rid of a neighbor | ||
1201 | * upon a reconnect call. | ||
1202 | * | ||
1203 | * @param cls closure (NULL) | ||
1204 | * @param key current key code | ||
1205 | * @param value value in the hash map, the neighbour entry to forget | ||
1206 | * @return GNUNET_YES if we should continue to | ||
1207 | * iterate, | ||
1208 | * GNUNET_NO if not. | ||
1209 | */ | ||
1210 | static int | ||
1211 | forget_neighbours (void *cls, | ||
1212 | const GNUNET_HashCode * key, | ||
1213 | void *value) | ||
1214 | { | ||
1215 | struct NeighbourList *n = value; | ||
1216 | #if DEBUG_TRANSPORT_DISCONNECT | ||
1217 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1218 | "Disconnecting due to reconnect being called\n"); | ||
1219 | #endif | ||
1220 | if (n->is_connected) | ||
1221 | neighbour_disconnect (n); | ||
1222 | |||
1223 | return GNUNET_YES; | ||
1224 | } | ||
1225 | |||
1226 | /** | ||
1156 | * Try again to connect to transport service. | 1227 | * Try again to connect to transport service. |
1157 | * | 1228 | * |
1158 | * @param cls the handle to the transport service | 1229 | * @param cls the handle to the transport service |
@@ -1164,8 +1235,6 @@ reconnect (void *cls, | |||
1164 | { | 1235 | { |
1165 | struct GNUNET_TRANSPORT_Handle *h = cls; | 1236 | struct GNUNET_TRANSPORT_Handle *h = cls; |
1166 | struct ControlMessage *pos; | 1237 | struct ControlMessage *pos; |
1167 | struct NeighbourList *n; | ||
1168 | struct NeighbourList *next; | ||
1169 | 1238 | ||
1170 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | 1239 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; |
1171 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | 1240 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) |
@@ -1174,18 +1243,8 @@ reconnect (void *cls, | |||
1174 | return; | 1243 | return; |
1175 | } | 1244 | } |
1176 | /* Forget about all neighbours that we used to be connected to */ | 1245 | /* Forget about all neighbours that we used to be connected to */ |
1177 | n = h->neighbours; | 1246 | GNUNET_CONTAINER_multihashmap_iterate(h->neighbours, &forget_neighbours, NULL); |
1178 | while (NULL != n) | 1247 | |
1179 | { | ||
1180 | #if DEBUG_TRANSPORT_DISCONNECT | ||
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 | 1248 | #if DEBUG_TRANSPORT |
1190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1249 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1191 | "Connecting to transport service.\n"); | 1250 | "Connecting to transport service.\n"); |
@@ -1336,17 +1395,59 @@ neighbour_add (struct GNUNET_TRANSPORT_Handle *h, | |||
1336 | #endif | 1395 | #endif |
1337 | n = GNUNET_malloc (sizeof (struct NeighbourList)); | 1396 | n = GNUNET_malloc (sizeof (struct NeighbourList)); |
1338 | n->id = *pid; | 1397 | n->id = *pid; |
1398 | n->h = h; | ||
1339 | GNUNET_BANDWIDTH_tracker_init (&n->out_tracker, | 1399 | GNUNET_BANDWIDTH_tracker_init (&n->out_tracker, |
1340 | GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, | 1400 | GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, |
1341 | MAX_BANDWIDTH_CARRY_S); | 1401 | MAX_BANDWIDTH_CARRY_S); |
1342 | n->next = h->neighbours; | 1402 | GNUNET_CONTAINER_multihashmap_put (h->neighbours, |
1343 | n->h = h; | 1403 | &pid->hashPubKey, |
1344 | h->neighbours = n; | 1404 | n, |
1345 | 1405 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | |
1346 | 1406 | ||
1347 | return n; | 1407 | return n; |
1348 | } | 1408 | } |
1349 | 1409 | ||
1410 | /** | ||
1411 | * Iterator over hash map entries, for deleting state of a neighbor. | ||
1412 | * | ||
1413 | * @param cls closure (NULL) | ||
1414 | * @param key current key code | ||
1415 | * @param value value in the hash map, the neighbour entry to delete | ||
1416 | * @return GNUNET_YES if we should continue to | ||
1417 | * iterate, | ||
1418 | * GNUNET_NO if not. | ||
1419 | */ | ||
1420 | static int | ||
1421 | delete_neighbours (void *cls, | ||
1422 | const GNUNET_HashCode * key, | ||
1423 | void *value) | ||
1424 | { | ||
1425 | struct NeighbourList *n = value; | ||
1426 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
1427 | |||
1428 | switch (n->transmit_stage) | ||
1429 | { | ||
1430 | case TS_NEW: | ||
1431 | case TS_TRANSMITTED: | ||
1432 | /* nothing to do */ | ||
1433 | break; | ||
1434 | case TS_QUEUED: | ||
1435 | case TS_TRANSMITTED_QUEUED: | ||
1436 | th = &n->transmit_handle; | ||
1437 | if (th->notify_delay_task != GNUNET_SCHEDULER_NO_TASK) | ||
1438 | { | ||
1439 | GNUNET_SCHEDULER_cancel (th->notify_delay_task); | ||
1440 | th->notify_delay_task = GNUNET_SCHEDULER_NO_TASK; | ||
1441 | } | ||
1442 | GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL)); | ||
1443 | break; | ||
1444 | default: | ||
1445 | GNUNET_break (0); | ||
1446 | } | ||
1447 | GNUNET_free (n); | ||
1448 | return GNUNET_YES; | ||
1449 | } | ||
1450 | |||
1350 | 1451 | ||
1351 | /** | 1452 | /** |
1352 | * Connect to the transport service. Note that the connection may | 1453 | * Connect to the transport service. Note that the connection may |
@@ -1382,6 +1483,7 @@ GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
1382 | ret->nc_cb = nc; | 1483 | ret->nc_cb = nc; |
1383 | ret->nd_cb = nd; | 1484 | ret->nd_cb = nd; |
1384 | ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; | 1485 | ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; |
1486 | ret->neighbours = GNUNET_CONTAINER_multihashmap_create(STARTING_NEIGHBOURS_SIZE); | ||
1385 | schedule_reconnect (ret); | 1487 | schedule_reconnect (ret); |
1386 | return ret; | 1488 | return ret; |
1387 | } | 1489 | } |
@@ -1393,8 +1495,6 @@ GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
1393 | void | 1495 | void |
1394 | GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) | 1496 | GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) |
1395 | { | 1497 | { |
1396 | struct GNUNET_TRANSPORT_TransmitHandle *th; | ||
1397 | struct NeighbourList *n; | ||
1398 | struct HelloWaitList *hwl; | 1498 | struct HelloWaitList *hwl; |
1399 | struct GNUNET_CLIENT_Connection *client; | 1499 | struct GNUNET_CLIENT_Connection *client; |
1400 | struct ControlMessage *cm; | 1500 | struct ControlMessage *cm; |
@@ -1403,30 +1503,13 @@ GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) | |||
1403 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n"); | 1503 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n"); |
1404 | #endif | 1504 | #endif |
1405 | handle->in_disconnect = GNUNET_YES; | 1505 | handle->in_disconnect = GNUNET_YES; |
1406 | while (NULL != (n = handle->neighbours)) | 1506 | |
1407 | { | 1507 | GNUNET_assert(GNUNET_SYSERR != |
1408 | handle->neighbours = n->next; | 1508 | GNUNET_CONTAINER_multihashmap_iterate(handle->neighbours, |
1409 | switch (n->transmit_stage) | 1509 | &delete_neighbours, |
1410 | { | 1510 | handle)); |
1411 | case TS_NEW: | 1511 | GNUNET_CONTAINER_multihashmap_destroy(handle->neighbours); |
1412 | case TS_TRANSMITTED: | 1512 | |
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)) | 1513 | while (NULL != (hwl = handle->hwl_head)) |
1431 | { | 1514 | { |
1432 | handle->hwl_head = hwl->next; | 1515 | handle->hwl_head = hwl->next; |
@@ -1902,7 +1985,7 @@ GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct | |||
1902 | n = th->neighbour; | 1985 | n = th->neighbour; |
1903 | #if DEBUG_TRANSPORT | 1986 | #if DEBUG_TRANSPORT |
1904 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1987 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1905 | "Transmission request of %u bytes to `%4s' was cancelled.\n", | 1988 | "Transmission request of %u bytes to `%4s' was canceled.\n", |
1906 | th->notify_size - sizeof (struct OutboundMessage), | 1989 | th->notify_size - sizeof (struct OutboundMessage), |
1907 | GNUNET_i2s (&n->id)); | 1990 | GNUNET_i2s (&n->id)); |
1908 | #endif | 1991 | #endif |
@@ -1918,7 +2001,7 @@ GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct | |||
1918 | break; | 2001 | break; |
1919 | case TS_QUEUED: | 2002 | case TS_QUEUED: |
1920 | n->transmit_stage = TS_NEW; | 2003 | n->transmit_stage = TS_NEW; |
1921 | if (n->is_connected == GNUNET_NO) | 2004 | if (n->in_disconnect == GNUNET_NO) |
1922 | neighbour_free (n); | 2005 | neighbour_free (n); |
1923 | break; | 2006 | break; |
1924 | case TS_TRANSMITTED: | 2007 | case TS_TRANSMITTED: |