aboutsummaryrefslogtreecommitdiff
path: root/src/transport/transport_api.c
diff options
context:
space:
mode:
authorMatthias Wachs <wachs@net.in.tum.de>2010-12-02 13:03:09 +0000
committerMatthias Wachs <wachs@net.in.tum.de>2010-12-02 13:03:09 +0000
commit2d8a83d2269d9f88032f4bac2a12cc1d156741c1 (patch)
tree9a9dc8541c691fa00f82e29831afe19f5d293eeb /src/transport/transport_api.c
parent411d7e9f4da9b4b4e696533471c09b7f629c2d87 (diff)
downloadgnunet-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.c425
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 */
194struct NeighbourList 198struct 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 */
220struct 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 *
383neighbour_find (struct GNUNET_TRANSPORT_Handle *h, 407neighbour_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 */
449static int
450try_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)
430static struct GNUNET_TRANSPORT_TransmitHandle * 532static struct GNUNET_TRANSPORT_TransmitHandle *
431schedule_peer_transmission (struct GNUNET_TRANSPORT_Handle *h) 533schedule_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 &quota_transmit_ready, 550 &quota_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 */
780struct SetQuotaContext 821struct 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
1090neighbour_free (struct NeighbourList *n) 1150neighbour_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 */
1239static int
1240forget_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 */
1455static int
1456delete_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,
1393void 1530void
1394GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) 1531GNUNET_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: