[openssl-dev] DTLS retransmission api

Alfred E. Heggestad aeh at db.org
Fri Jun 3 09:52:29 UTC 2016



On 02/06/16 16:03, Matt Caswell wrote:
>
>
> On 02/06/16 14:33, Alfred E. Heggestad wrote:
>>
>>
>> On 01/06/16 13:58, Matt Caswell wrote:
>>>
>>>
>>> On 01/06/16 11:15, Alfred E. Heggestad wrote:
>>>> hi,
>>>>
>>>> we are using DTLS from OpenSSL to implement DTLS-SRTP in our
>>>> product (Wire.com) .. The code and implementation works really well
>>>> and is very robust. We are using OpenSSL version 1.0.2g
>>>>
>>>>
>>>> since our product is deployed globally on mobile data networks,
>>>> we have quite variable latency and packetloss. The patch below
>>>> shows my working code, it has an initial retransmit timeout
>>>> of 400 ms which is incrementing by 10% for every re-trans.
>>>>
>>>>
>>>> obviously this patch cannot make it into the official tree.
>>>>
>>>>
>>>> but I would like to discuss with you guys the option to
>>>> add some kind of API for:
>>>>
>>>> - Setting the initial RTO for DTLS (in milliseconds).
>>>> - Setting the retransmit policy for DTLS, i.e. should it
>>>>     double or increment by X for every re-trans.
>>>
>>> I think an API for that would be a great idea. Perhaps a callback could
>>> be used so that you can set exactly the policy you want?
>>>
>>
>> Thank you, Matt
>>
>>
>> I can work on a patch for this, if you guys can help me to define
>> the API.
>>
>>
>> I think we only need one CTRL api to set the next re-transmit
>> interval. then in the application code that calls this:
>>
>> - DTLSv1_handle_timeout
>> - DTLSv1_get_timeout
>>
>>
>> can also call DTLS_set_retrans_interval(400)
>>
>
> I'm not sure I follow you. I was thinking something like:
>
> int DTLS_set_timer_cb(SSL *s, int (*cb)(SSL *s, int timer));
>
> Then where in the current code we have:
>
>      dtls1_double_timeout(s);
>
> We might instead do
>
>      if(s->d1->timer_cb != NULL)
> 	s->d1->timeout_duration = timer_cb(s, s->d1->timeout_duration);
>      else
> 	dtls1_double_timeout(s);
>
>
> And in dtls1_start_timer() where we have:
>
>      /* If timer is not set, initialize duration with 1 second */
>      if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec
> == 0) {
>          s->d1->timeout_duration = 1;
>      }
>
>
> Instead have:
>
>      /* If timer is not set, initialize duration with 1 second */
>      if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec
> == 0) {
>          if (s->d1->timer_cb != NULL)
> 		s->d1->timeout_duration = s->d1_timeout_cb(s, 0);
>          else
>                  s->d1->timeout_duration = 1;
>      }
>
>

Hi Matt,

thanks for the suggested API and code. Please find below a suggested
patch that implements this new callback.


the patch is based on 1.0.2-dev from GIT:

   url:      git://git.openssl.org/openssl.git
   branch:   origin/OpenSSL_1_0_2-stable


I have renamed "timeout_duration" on purpose, since the units have
changed from "seconds" to "milliseconds".





 From e6c9fbe470ab1901010e90b727313ebc7875b40f Mon Sep 17 00:00:00 2001
From: "Alfred E. Heggestad" <aeh at db.org>
Date: Fri, 3 Jun 2016 11:31:45 +0200
Subject: [PATCH] add support for DTLS callback for timeout value

---
  ssl/d1_lib.c | 45 +++++++++++++++++++++++++++++++++++++--------
  ssl/dtls1.h  |  9 +++++++--
  ssl/ssl.h    |  4 ++++
  3 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index ee78921..235635a 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -240,6 +240,8 @@ void dtls1_clear(SSL *s)
      unsigned int link_mtu;

      if (s->d1) {
+        dtls_timer_cb *timer_cb = s->d1->timer_cb;
+
          unprocessed_rcds = s->d1->unprocessed_rcds.q;
          processed_rcds = s->d1->processed_rcds.q;
          buffered_messages = s->d1->buffered_messages;
@@ -252,6 +254,9 @@ void dtls1_clear(SSL *s)

          memset(s->d1, 0, sizeof(*(s->d1)));

+        /* Restore the timer callback from previous state */
+        s->d1->timer_cb = timer_cb;
+
          if (s->server) {
              s->d1->cookie_len = sizeof(s->d1->cookie);
          }
@@ -359,6 +364,8 @@ const SSL_CIPHER *dtls1_get_cipher(unsigned int u)

  void dtls1_start_timer(SSL *s)
  {
+    struct timeval diff;
+
  #ifndef OPENSSL_NO_SCTP
      /* Disable timer for SCTP */
      if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
@@ -367,16 +374,24 @@ void dtls1_start_timer(SSL *s)
      }
  #endif

-    /* If timer is not set, initialize duration with 1 second */
+    /* If timer is not set, initialize duration with 1 second or
+     * a user-specified value if the timer callback is installed. */
      if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) {
-        s->d1->timeout_duration = 1;
+
+        if (s->d1->timer_cb != NULL)
+            s->d1->timeout_duration_ms = s->d1->timer_cb(s, 1000);
+        else
+            s->d1->timeout_duration_ms = 1000;
      }

      /* Set timeout to current time */
      get_current_time(&(s->d1->next_timeout));

      /* Add duration to current time */
-    s->d1->next_timeout.tv_sec += s->d1->timeout_duration;
+    diff.tv_sec  = s->d1->timeout_duration_ms / 1000;
+    diff.tv_usec = (s->d1->timeout_duration_ms % 1000) * 1000;
+    timeradd(&s->d1->next_timeout, &diff, &s->d1->next_timeout);
+
      BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
               &(s->d1->next_timeout));
  }
@@ -441,9 +456,9 @@ int dtls1_is_timer_expired(SSL *s)

  void dtls1_double_timeout(SSL *s)
  {
-    s->d1->timeout_duration *= 2;
-    if (s->d1->timeout_duration > 60)
-        s->d1->timeout_duration = 60;
+    s->d1->timeout_duration_ms *= 2;
+    if (s->d1->timeout_duration_ms > 60000)
+        s->d1->timeout_duration_ms = 60000;
      dtls1_start_timer(s);
  }

@@ -452,7 +467,7 @@ void dtls1_stop_timer(SSL *s)
      /* Reset everything */
      memset(&(s->d1->timeout), 0, sizeof(struct dtls1_timeout_st));
      memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
-    s->d1->timeout_duration = 1;
+    s->d1->timeout_duration_ms = 1000;
      BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
               &(s->d1->next_timeout));
      /* Clear retransmission buffer */
@@ -491,7 +506,12 @@ int dtls1_handle_timeout(SSL *s)
          return 0;
      }

-    dtls1_double_timeout(s);
+    if (s->d1->timer_cb != NULL) {
+        const unsigned ms = s->d1->timer_cb(s, s->d1->timeout_duration_ms);
+        s->d1->timeout_duration_ms = ms;
+    }
+    else
+        dtls1_double_timeout(s);

      if (dtls1_check_timeout_num(s) < 0)
          return -1;
@@ -571,3 +591,12 @@ static int dtls1_handshake_write(SSL *s)
  {
      return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
  }
+
+
+void DTLS_set_timer_cb(SSL *s, unsigned (*cb)(SSL *s, unsigned timeout_ms))
+{
+    if (!s || !s->d1)
+        return;
+
+    s->d1->timer_cb = cb;
+}
diff --git a/ssl/dtls1.h b/ssl/dtls1.h
index 30bbcf2..53abe32 100644
--- a/ssl/dtls1.h
+++ b/ssl/dtls1.h
@@ -125,6 +125,8 @@ extern "C" {
  /* Max MTU overhead we know about so far is 40 for IPv6 + 8 for UDP */
  #  define DTLS1_MAX_MTU_OVERHEAD                   48

+typedef unsigned (dtls_timer_cb)(SSL *s, unsigned timer);
+
  typedef struct dtls1_bitmap_st {
      unsigned long map;          /* track 32 packets on 32-bit systems and 64
                                   * - on 64-bit systems */
@@ -225,8 +227,8 @@ typedef struct dtls1_state_st {
       * Indicates when the last handshake msg or heartbeat sent will timeout
       */
      struct timeval next_timeout;
-    /* Timeout duration */
-    unsigned short timeout_duration;
+    /* Timeout duration in [milliseconds] */
+    unsigned short timeout_duration_ms;
      /*
       * storage for Alert/Handshake protocol data received but not yet
       * processed by ssl3_read_bytes:
@@ -246,6 +248,9 @@ typedef struct dtls1_state_st {
      int next_state;
      int shutdown_received;
  #  endif
+
+    dtls_timer_cb *timer_cb;
+
  } DTLS1_STATE;

  typedef struct dtls1_record_data_st {
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 028681a..4251226 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -3155,6 +3155,10 @@ void ERR_load_SSL_strings(void);
  # define SSL_R_X509_LIB                                   268
  # define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS           269

+
+void DTLS_set_timer_cb(SSL *s, unsigned (*cb)(SSL *s, unsigned timer));
+
+
  #ifdef  __cplusplus
  }
  #endif
-- 
1.9.3 (Apple Git-50)







More information about the openssl-dev mailing list