aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-tng.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-06-09 18:38:21 +0200
committerChristian Grothoff <christian@grothoff.org>2019-06-09 18:38:21 +0200
commit5c0d8339072c343e7f5d5578acecdd99d0fe842b (patch)
treea39512eb467ca842bf43474ebad8717ecdada8b4 /src/transport/gnunet-service-tng.c
parentf531d06a9d64d627034c2220769c1af63fb72297 (diff)
downloadgnunet-5c0d8339072c343e7f5d5578acecdd99d0fe842b.tar.gz
gnunet-5c0d8339072c343e7f5d5578acecdd99d0fe842b.zip
add FC retransmission logic
Diffstat (limited to 'src/transport/gnunet-service-tng.c')
-rw-r--r--src/transport/gnunet-service-tng.c138
1 files changed, 113 insertions, 25 deletions
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
index 3e4d750a2..bb477fc1e 100644
--- a/src/transport/gnunet-service-tng.c
+++ b/src/transport/gnunet-service-tng.c
@@ -26,9 +26,7 @@
26 * Implement next: 26 * Implement next:
27 * - FIXME-FC: realize transport-to-transport flow control (needed in case 27 * - FIXME-FC: realize transport-to-transport flow control (needed in case
28 * communicators do not offer flow control). 28 * communicators do not offer flow control).
29 * We do transmit FC window sizes now. Left: 29 * We do transmit FC window sizes now.
30 * for SENDING)
31 * - need to call consider_sending_fc() periodically if it goes unanswered!
32 * 30 *
33 * for DV) 31 * for DV)
34 * - send challenges via DV (when DVH is confirmed *and* we care about 32 * - send challenges via DV (when DVH is confirmed *and* we care about
@@ -118,6 +116,20 @@
118#define MAX_CUMMULATIVE_ACKS 64 116#define MAX_CUMMULATIVE_ACKS 64
119 117
120/** 118/**
119 * What is the 1:n chance that we send a Flow control response when
120 * receiving a flow control message that did not change anything for
121 * us? Basically, this is used in the case where both peers are stuck
122 * on flow control (no window changes), but one might continue sending
123 * flow control messages to the other peer as the first FC message
124 * when things stalled got lost, and then subsequently the other peer
125 * does *usually* not respond as nothing changed. So to ensure that
126 * eventually the FC messages stop, we do send with 1/8th probability
127 * an FC message even if nothing changed. That prevents one peer
128 * being stuck in sending (useless) FC messages "forever".
129 */
130#define FC_NO_CHANGE_REPLY_PROBABILITY 8
131
132/**
121 * What is the size we assume for a read operation in the 133 * What is the size we assume for a read operation in the
122 * absence of an MTU for the purpose of flow control? 134 * absence of an MTU for the purpose of flow control?
123 */ 135 */
@@ -1290,6 +1302,12 @@ struct VirtualLink
1290 struct GNUNET_SCHEDULER_Task *visibility_task; 1302 struct GNUNET_SCHEDULER_Task *visibility_task;
1291 1303
1292 /** 1304 /**
1305 * Task scheduled to periodically retransmit FC messages (in
1306 * case one got lost).
1307 */
1308 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1309
1310 /**
1293 * Neighbour used by this virtual link, NULL if @e dv is used. 1311 * Neighbour used by this virtual link, NULL if @e dv is used.
1294 */ 1312 */
1295 struct Neighbour *n; 1313 struct Neighbour *n;
@@ -1335,6 +1353,12 @@ struct VirtualLink
1335 struct GNUNET_TIME_Absolute last_fc_timestamp; 1353 struct GNUNET_TIME_Absolute last_fc_timestamp;
1336 1354
1337 /** 1355 /**
1356 * Expected RTT from the last FC transmission. (Zero if the last
1357 * attempt failed, but could theoretically be zero even on success.)
1358 */
1359 struct GNUNET_TIME_Relative last_fc_rtt;
1360
1361 /**
1338 * Used to generate unique UUIDs for messages that are being 1362 * Used to generate unique UUIDs for messages that are being
1339 * fragmented. 1363 * fragmented.
1340 */ 1364 */
@@ -1400,6 +1424,17 @@ struct VirtualLink
1400 uint64_t outbound_fc_window_size_used; 1424 uint64_t outbound_fc_window_size_used;
1401 1425
1402 /** 1426 /**
1427 * What is the most recent FC window the other peer sent us
1428 * in `outbound_window_size`? This is basically the window
1429 * size value the other peer has definitively received from
1430 * us. If it matches @e incoming_fc_window_size, we should
1431 * not send a FC message to increase the FC window. However,
1432 * we may still send an FC message to notify the other peer
1433 * that we received the other peer's FC message.
1434 */
1435 uint64_t last_outbound_window_size_received;
1436
1437 /**
1403 * Generator for the sequence numbers of 1438 * Generator for the sequence numbers of
1404 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send. 1439 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1405 */ 1440 */
@@ -2987,6 +3022,11 @@ free_virtual_link (struct VirtualLink *vl)
2987 GNUNET_SCHEDULER_cancel (vl->visibility_task); 3022 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2988 vl->visibility_task = NULL; 3023 vl->visibility_task = NULL;
2989 } 3024 }
3025 if (NULL != vl->fc_retransmit_task)
3026 {
3027 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
3028 vl->fc_retransmit_task = NULL;
3029 }
2990 while (NULL != (csc = vl->csc_head)) 3030 while (NULL != (csc = vl->csc_head))
2991 { 3031 {
2992 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc); 3032 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
@@ -4237,8 +4277,9 @@ queue_send_msg (struct Queue *queue,
4237 * @param hdr message to send as payload 4277 * @param hdr message to send as payload
4238 * @param options whether queues must be confirmed or not, 4278 * @param options whether queues must be confirmed or not,
4239 * and whether we may pick multiple (2) queues 4279 * and whether we may pick multiple (2) queues
4280 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4240 */ 4281 */
4241static void 4282static struct GNUNET_TIME_Relative
4242route_via_neighbour (const struct Neighbour *n, 4283route_via_neighbour (const struct Neighbour *n,
4243 const struct GNUNET_MessageHeader *hdr, 4284 const struct GNUNET_MessageHeader *hdr,
4244 enum RouteMessageOptions options) 4285 enum RouteMessageOptions options)
@@ -4247,6 +4288,7 @@ route_via_neighbour (const struct Neighbour *n,
4247 unsigned int candidates; 4288 unsigned int candidates;
4248 unsigned int sel1; 4289 unsigned int sel1;
4249 unsigned int sel2; 4290 unsigned int sel2;
4291 struct GNUNET_TIME_Relative rtt;
4250 4292
4251 /* Pick one or two 'random' queues from n (under constraints of options) */ 4293 /* Pick one or two 'random' queues from n (under constraints of options) */
4252 now = GNUNET_TIME_absolute_get (); 4294 now = GNUNET_TIME_absolute_get ();
@@ -4274,9 +4316,10 @@ route_via_neighbour (const struct Neighbour *n,
4274 "# route selection failed (all no valid queue)", 4316 "# route selection failed (all no valid queue)",
4275 1, 4317 1,
4276 GNUNET_NO); 4318 GNUNET_NO);
4277 return; 4319 return GNUNET_TIME_UNIT_FOREVER_REL;
4278 } 4320 }
4279 4321
4322 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4280 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates); 4323 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4281 if (0 == (options & RMO_REDUNDANT)) 4324 if (0 == (options & RMO_REDUNDANT))
4282 sel2 = candidates; /* picks none! */ 4325 sel2 = candidates; /* picks none! */
@@ -4297,11 +4340,13 @@ route_via_neighbour (const struct Neighbour *n,
4297 GNUNET_i2s (&n->pid), 4340 GNUNET_i2s (&n->pid),
4298 pos->address, 4341 pos->address,
4299 (sel1 == candidates) ? 1 : 2); 4342 (sel1 == candidates) ? 1 : 2);
4343 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4300 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size)); 4344 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4301 } 4345 }
4302 candidates++; 4346 candidates++;
4303 } 4347 }
4304 } 4348 }
4349 return rtt;
4305} 4350}
4306 4351
4307 4352
@@ -4523,8 +4568,9 @@ typedef void (*DVMessageHandler) (void *cls,
4523 * @param use function to call with the encapsulated message 4568 * @param use function to call with the encapsulated message
4524 * @param use_cls closure for @a use 4569 * @param use_cls closure for @a use
4525 * @param options whether path must be confirmed or not, to be passed to @a use 4570 * @param options whether path must be confirmed or not, to be passed to @a use
4571 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4526 */ 4572 */
4527static void 4573static struct GNUNET_TIME_Relative
4528encapsulate_for_dv (struct DistanceVector *dv, 4574encapsulate_for_dv (struct DistanceVector *dv,
4529 unsigned int num_dvhs, 4575 unsigned int num_dvhs,
4530 struct DistanceVectorHop **dvhs, 4576 struct DistanceVectorHop **dvhs,
@@ -4540,6 +4586,7 @@ encapsulate_for_dv (struct DistanceVector *dv,
4540 struct TransportDVBoxPayloadP *enc_payload_hdr = 4586 struct TransportDVBoxPayloadP *enc_payload_hdr =
4541 (struct TransportDVBoxPayloadP *) enc; 4587 (struct TransportDVBoxPayloadP *) enc;
4542 struct DVKeyState key; 4588 struct DVKeyState key;
4589 struct GNUNET_TIME_Relative rtt;
4543 4590
4544 /* Encrypt payload */ 4591 /* Encrypt payload */
4545 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX); 4592 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
@@ -4560,7 +4607,7 @@ encapsulate_for_dv (struct DistanceVector *dv,
4560 enc_body_size); 4607 enc_body_size);
4561 dv_hmac (&key, &box_hdr.hmac, enc, sizeof (enc)); 4608 dv_hmac (&key, &box_hdr.hmac, enc, sizeof (enc));
4562 dv_key_clean (&key); 4609 dv_key_clean (&key);
4563 4610 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4564 /* For each selected path, take the pre-computed header and body 4611 /* For each selected path, take the pre-computed header and body
4565 and add the path in the middle of the message; then send it. */ 4612 and add the path in the middle of the message; then send it. */
4566 for (unsigned int i = 0; i < num_dvhs; i++) 4613 for (unsigned int i = 0; i < num_dvhs; i++)
@@ -4603,13 +4650,14 @@ encapsulate_for_dv (struct DistanceVector *dv,
4603 path); 4650 path);
4604 GNUNET_free (path); 4651 GNUNET_free (path);
4605 } 4652 }
4606 4653 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4607 memcpy (&dhops[num_hops], enc, sizeof (enc)); 4654 memcpy (&dhops[num_hops], enc, sizeof (enc));
4608 use (use_cls, 4655 use (use_cls,
4609 dvh->next_hop, 4656 dvh->next_hop,
4610 (const struct GNUNET_MessageHeader *) buf, 4657 (const struct GNUNET_MessageHeader *) buf,
4611 options); 4658 options);
4612 } 4659 }
4660 return rtt;
4613} 4661}
4614 4662
4615 4663
@@ -4629,7 +4677,7 @@ send_dv_to_neighbour (void *cls,
4629 enum RouteMessageOptions options) 4677 enum RouteMessageOptions options)
4630{ 4678{
4631 (void) cls; 4679 (void) cls;
4632 route_via_neighbour (next_hop, hdr, options); 4680 (void) route_via_neighbour (next_hop, hdr, options);
4633} 4681}
4634 4682
4635 4683
@@ -4642,8 +4690,9 @@ send_dv_to_neighbour (void *cls,
4642 * @param target peer to receive @a hdr 4690 * @param target peer to receive @a hdr
4643 * @param hdr header of the message to route and #GNUNET_free() 4691 * @param hdr header of the message to route and #GNUNET_free()
4644 * @param options which transmission channels are allowed 4692 * @param options which transmission channels are allowed
4693 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4645 */ 4694 */
4646static void 4695static struct GNUNET_TIME_Relative
4647route_control_message_without_fc (const struct GNUNET_PeerIdentity *target, 4696route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4648 const struct GNUNET_MessageHeader *hdr, 4697 const struct GNUNET_MessageHeader *hdr,
4649 enum RouteMessageOptions options) 4698 enum RouteMessageOptions options)
@@ -4651,6 +4700,8 @@ route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4651 struct VirtualLink *vl; 4700 struct VirtualLink *vl;
4652 struct Neighbour *n; 4701 struct Neighbour *n;
4653 struct DistanceVector *dv; 4702 struct DistanceVector *dv;
4703 struct GNUNET_TIME_Relative rtt1;
4704 struct GNUNET_TIME_Relative rtt2;
4654 4705
4655 vl = lookup_virtual_link (target); 4706 vl = lookup_virtual_link (target);
4656 GNUNET_assert (NULL != vl); 4707 GNUNET_assert (NULL != vl);
@@ -4675,7 +4726,7 @@ route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4675 "# Messages dropped in routing: no acceptable method", 4726 "# Messages dropped in routing: no acceptable method",
4676 1, 4727 1,
4677 GNUNET_NO); 4728 GNUNET_NO);
4678 return; 4729 return GNUNET_TIME_UNIT_FOREVER_REL;
4679 } 4730 }
4680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4681 "Routing message of type %u to %s with options %X\n", 4732 "Routing message of type %u to %s with options %X\n",
@@ -4694,9 +4745,11 @@ route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4694 if ((NULL != n) && (NULL != dv)) 4745 if ((NULL != n) && (NULL != dv))
4695 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's 4746 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4696 enough for redunancy, so clear the flag. */ 4747 enough for redunancy, so clear the flag. */
4748 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4749 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4697 if (NULL != n) 4750 if (NULL != n)
4698 { 4751 {
4699 route_via_neighbour (n, hdr, options); 4752 rtt1 = route_via_neighbour (n, hdr, options);
4700 } 4753 }
4701 if (NULL != dv) 4754 if (NULL != dv)
4702 { 4755 {
@@ -4711,16 +4764,17 @@ route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4711 { 4764 {
4712 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4765 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4713 "Failed to route message, could not determine DV path\n"); 4766 "Failed to route message, could not determine DV path\n");
4714 return; 4767 return rtt1;
4715 } 4768 }
4716 encapsulate_for_dv (dv, 4769 rtt2 = encapsulate_for_dv (dv,
4717 res, 4770 res,
4718 hops, 4771 hops,
4719 hdr, 4772 hdr,
4720 &send_dv_to_neighbour, 4773 &send_dv_to_neighbour,
4721 NULL, 4774 NULL,
4722 options & (~RMO_REDUNDANT)); 4775 options & (~RMO_REDUNDANT));
4723 } 4776 }
4777 return GNUNET_TIME_relative_min (rtt1, rtt2);
4724} 4778}
4725 4779
4726 4780
@@ -4728,21 +4782,23 @@ route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4728 * Something changed on the virtual link with respect to flow 4782 * Something changed on the virtual link with respect to flow
4729 * control. Consider retransmitting the FC window size. 4783 * control. Consider retransmitting the FC window size.
4730 * 4784 *
4731 * @param vl virtual link to work with 4785 * @param cls a `struct VirtualLink` to work with
4732 */ 4786 */
4733static void 4787static void
4734consider_sending_fc (struct VirtualLink *vl) 4788consider_sending_fc (void *cls)
4735{ 4789{
4790 struct VirtualLink *vl = cls;
4736 struct GNUNET_TIME_Absolute monotime; 4791 struct GNUNET_TIME_Absolute monotime;
4737 struct TransportFlowControlMessage fc; 4792 struct TransportFlowControlMessage fc;
4738 struct GNUNET_TIME_Relative duration; 4793 struct GNUNET_TIME_Relative duration;
4794 struct GNUNET_TIME_Relative rtt;
4739 4795
4740 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission); 4796 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
4741 /* FIXME: decide sane criteria on when to do this, instead of doing 4797 /* FIXME: decide sane criteria on when to do this, instead of doing
4742 it always! */ 4798 it always! */
4743 /* For example, we should probably ONLY do this if a bit more than 4799 /* For example, we should probably ONLY do this if a bit more than
4744 an RTT has passed, or if the window changed "significantly" since 4800 an RTT has passed, or if the window changed "significantly" since
4745 then. */ 4801 then. See vl->last_fc_rtt! */
4746 (void) duration; 4802 (void) duration;
4747 4803
4748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -4759,7 +4815,24 @@ consider_sending_fc (struct VirtualLink *vl)
4759 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used); 4815 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
4760 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size); 4816 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
4761 fc.sender_time = GNUNET_TIME_absolute_hton (monotime); 4817 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
4762 route_control_message_without_fc (&vl->target, &fc.header, RMO_NONE); 4818 rtt = route_control_message_without_fc (&vl->target, &fc.header, RMO_NONE);
4819 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
4820 {
4821 rtt = GNUNET_TIME_UNIT_SECONDS;
4822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4823 "FC retransmission to %s failed, will retry in %s\n",
4824 GNUNET_i2s (&vl->target),
4825 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
4826 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
4827 }
4828 else
4829 {
4830 vl->last_fc_rtt = rtt;
4831 }
4832 if (NULL != vl->fc_retransmit_task)
4833 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
4834 vl->fc_retransmit_task =
4835 GNUNET_SCHEDULER_add_delayed (rtt, &consider_sending_fc, vl);
4763} 4836}
4764 4837
4765 4838
@@ -8181,12 +8254,27 @@ handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8181 (unsigned long long) vl->outbound_fc_window_size, 8254 (unsigned long long) vl->outbound_fc_window_size,
8182 (long long) vl->incoming_fc_window_size_loss); 8255 (long long) vl->incoming_fc_window_size_loss);
8183 wnd = GNUNET_ntohll (fc->outbound_window_size); 8256 wnd = GNUNET_ntohll (fc->outbound_window_size);
8184 if (wnd < vl->incoming_fc_window_size) 8257 if ((wnd < vl->incoming_fc_window_size) ||
8258 (vl->last_outbound_window_size_received != wnd) ||
8259 (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX) %
8260 FC_NO_CHANGE_REPLY_PROBABILITY))
8185 { 8261 {
8186 /* Consider re-sending our FC message, as clearly the 8262 /* Consider re-sending our FC message, as clearly the
8187 other peer's idea of the window is not up-to-date */ 8263 other peer's idea of the window is not up-to-date */
8188 consider_sending_fc (vl); 8264 consider_sending_fc (vl);
8189 } 8265 }
8266 if ((wnd == vl->incoming_fc_window_size) &&
8267 (vl->last_outbound_window_size_received == wnd) &&
8268 (NULL != vl->fc_retransmit_task))
8269 {
8270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8271 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8272 GNUNET_i2s (&vl->target),
8273 (unsigned long long) wnd);
8274 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8275 vl->fc_retransmit_task = NULL;
8276 }
8277 vl->last_outbound_window_size_received = wnd;
8190 /* FC window likely increased, check transmission possibilities! */ 8278 /* FC window likely increased, check transmission possibilities! */
8191 check_vl_transmission (vl); 8279 check_vl_transmission (vl);
8192 finish_cmc_handling (cmc); 8280 finish_cmc_handling (cmc);