From 6adc64ee122e9be37c6b83e9b745719b4d5940b8 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 26 Jan 2017 18:34:29 +0100 Subject: [PATCH] implement random packet drop option, fix retransmission logic --- src/cadet/gnunet-service-cadet-new.c | 22 +++++++- src/cadet/gnunet-service-cadet-new.h | 5 ++ src/cadet/gnunet-service-cadet-new_channel.c | 29 +++++++++-- src/cadet/gnunet-service-cadet-new_peer.c | 55 +++++++++++++++++--- src/cadet/gnunet-service-cadet-new_tunnels.c | 11 ---- 5 files changed, 100 insertions(+), 22 deletions(-) diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c index f24c9f518..d40d4f10e 100644 --- a/src/cadet/gnunet-service-cadet-new.c +++ b/src/cadet/gnunet-service-cadet-new.c @@ -188,6 +188,11 @@ struct GNUNET_TIME_Relative ratchet_time; */ struct GNUNET_TIME_Relative keepalive_period; +/** + * Set to non-zero values to create random drops to test retransmissions. + */ +unsigned long long drop_percent; + /** * Send a message to a client. @@ -1352,7 +1357,22 @@ run (void *cls, "need delay value"); keepalive_period = GNUNET_TIME_UNIT_MINUTES; } - + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (c, + "CADET", + "DROP_PERCENT", + &drop_percent)) + { + drop_percent = 0; + } + else + { + LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); + } my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); if (NULL == my_private_key) { diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet-new.h index 721044ac4..dff0d3c8c 100644 --- a/src/cadet/gnunet-service-cadet-new.h +++ b/src/cadet/gnunet-service-cadet-new.h @@ -235,6 +235,11 @@ extern struct GNUNET_TIME_Relative keepalive_period; */ extern int shutting_down; +/** + * Set to non-zero values to create random drops to test retransmissions. + */ +extern unsigned long long drop_percent; + /** * Send a message to a client. diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c index e55a9a77d..a923f19dc 100644 --- a/src/cadet/gnunet-service-cadet-new_channel.c +++ b/src/cadet/gnunet-service-cadet-new_channel.c @@ -1190,6 +1190,8 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, 1, GNUNET_NO); GNUNET_MQ_discard (env); + if (GNUNET_YES == ch->reliable) + send_channel_data_ack (ch); return; } @@ -1348,16 +1350,38 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, crmn = crm->next; if (ack->mid.mid == crm->data_message->mid.mid) { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got DATA_ACK with base %u matching message %u on %s\n", + (unsigned int) mid_base, + ntohl (crm->data_message->mid.mid), + GCCH_2s (ch)); handle_matching_ack (ch, crm); found = GNUNET_YES; continue; } delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base) - 1; + if (delta >= UINT_MAX - ch->max_pending_messages) + { + /* overflow, means crm was way in the past, so this ACK counts for it. */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got DATA_ACK with base %u past %u on %s\n", + (unsigned int) mid_base, + ntohl (crm->data_message->mid.mid), + GCCH_2s (ch)); + handle_matching_ack (ch, + crm); + found = GNUNET_YES; + continue; + } if (delta >= 64) continue; if (0 != (mid_mask & (1LLU << delta))) { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got DATA_ACK with mask for %u on %s\n", + ntohl (crm->data_message->mid.mid), + GCCH_2s (ch)); handle_matching_ack (ch, crm); found = GNUNET_YES; @@ -1498,9 +1522,8 @@ data_sent_cb (void *cls) GCCH_2s (ch), GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry), GNUNET_YES)); - if (crm == ch->head_sent) + if (NULL == ch->head_sent->qe) { - /* We are the new head, need to reschedule retry task */ if (NULL != ch->retry_data_task) GNUNET_SCHEDULER_cancel (ch->retry_data_task); ch->retry_data_task @@ -1698,7 +1721,7 @@ GCCH_handle_local_ack (struct CadetChannel *ch, } LOG (GNUNET_ERROR_TYPE_DEBUG, - "Got LOCAL ACK, passing payload message %u to %s-%X on %s\n", + "Got LOCAL_ACK, passing payload message %u to %s-%X on %s\n", ntohl (com->mid.mid), GSC_2s (ccc->c), ntohl (ccc->ccn.channel_of_client), diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c index fe40d76b6..97bb1378e 100644 --- a/src/cadet/gnunet-service-cadet-new_peer.c +++ b/src/cadet/gnunet-service-cadet-new_peer.c @@ -502,6 +502,34 @@ GCP_set_mq (struct CadetPeer *cp, } +/** + * Debug function should NEVER return true in production code, useful to + * simulate losses for testcases. + * + * @return #GNUNET_YES or #GNUNET_NO with the decision to drop. + */ +static int +should_I_drop (void) +{ + if (0 == drop_percent) + return GNUNET_NO; + if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 101) < drop_percent) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Function called when CORE took one of the messages from + * a message queue manager and transmitted it. + * + * @param cls the `struct CadetPeeer` where we made progress + */ +static void +mqm_send_done (void *cls); + + /** * Transmit current envelope from this @a mqm. * @@ -512,10 +540,6 @@ mqm_execute (struct GCP_MessageQueueManager *mqm) { struct CadetPeer *cp = mqm->cp; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending to peer %s from MQM %p\n", - GCP_2s (cp), - mqm); /* Move entry to the end of the DLL, to be fair. */ if (mqm != cp->mqm_tail) { @@ -526,10 +550,27 @@ mqm_execute (struct GCP_MessageQueueManager *mqm) cp->mqm_tail, mqm); } - GNUNET_MQ_send (cp->core_mq, - mqm->env); - mqm->env = NULL; cp->mqm_ready_counter--; + if (GNUNET_YES == should_I_drop ()) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "DROPPING message to peer %s from MQM %p\n", + GCP_2s (cp), + mqm); + GNUNET_MQ_discard (mqm->env); + mqm->env = NULL; + mqm_send_done (cp); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending to peer %s from MQM %p\n", + GCP_2s (cp), + mqm); + GNUNET_MQ_send (cp->core_mq, + mqm->env); + mqm->env = NULL; + } mqm->cb (mqm->cb_cls, GNUNET_YES); } diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet-new_tunnels.c index 03067a605..592a8c683 100644 --- a/src/cadet/gnunet-service-cadet-new_tunnels.c +++ b/src/cadet/gnunet-service-cadet-new_tunnels.c @@ -361,17 +361,6 @@ struct CadetTunnel */ struct CadetTunnelQueueEntry *tq_tail; - - /** - * Ephemeral message in the queue (to avoid queueing more than one). - */ - struct CadetConnectionQueue *ephm_hKILL; - - /** - * Pong message in the queue. - */ - struct CadetConnectionQueue *pong_hKILL; - /** * How long do we wait until we retry the KX? */ -- 2.25.1