[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