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" <a...@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)
--
openssl-dev mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-dev