diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-06-09 18:38:21 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-06-09 18:38:21 +0200 |
commit | 5c0d8339072c343e7f5d5578acecdd99d0fe842b (patch) | |
tree | a39512eb467ca842bf43474ebad8717ecdada8b4 /src/transport/gnunet-service-tng.c | |
parent | f531d06a9d64d627034c2220769c1af63fb72297 (diff) | |
download | gnunet-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.c | 138 |
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 | */ |
4241 | static void | 4282 | static struct GNUNET_TIME_Relative |
4242 | route_via_neighbour (const struct Neighbour *n, | 4283 | route_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 | */ |
4527 | static void | 4573 | static struct GNUNET_TIME_Relative |
4528 | encapsulate_for_dv (struct DistanceVector *dv, | 4574 | encapsulate_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 | */ |
4646 | static void | 4695 | static struct GNUNET_TIME_Relative |
4647 | route_control_message_without_fc (const struct GNUNET_PeerIdentity *target, | 4696 | route_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 | */ |
4733 | static void | 4787 | static void |
4734 | consider_sending_fc (struct VirtualLink *vl) | 4788 | consider_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); |