From 9fd97834ce7c9bce80f0d94515745be7d7221d65 Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Fri, 25 Apr 2014 19:26:14 +0000 Subject: [PATCH] res_rtp_asterisk: Add support for DTLS handshake retransmissions On congested networks, it is possible for the DTLS handshake messages to get lost. This patch adds a timer to res_rtp_asterisk that will periodically check to see if the handshake has succeeded. If not, it will retransmit the DTLS handshake. Review: https://reviewboard.asterisk.org/r/3337 ASTERISK-23649 #close Reported by: Nitesh Bansal patches: dtls_retransmission.patch uploaded by Nitesh Bansal (License 6418) ........ Merged revisions 413008 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 413009 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: http://svn.asterisk.org/svn/asterisk/trunk@413012 f38db490-d61c-443f-a65b-d21fe96a405b --- res/res_rtp_asterisk.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 2ad76b78f6..444b9f7c54 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -283,6 +283,7 @@ struct ast_rtp { SSL *ssl; /*!< SSL session */ BIO *read_bio; /*!< Memory buffer for reading */ BIO *write_bio; /*!< Memory buffer for writing */ + ast_mutex_t dtls_timer_lock; /*!< Lock for synchronization purposes */ enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */ enum ast_srtp_suite suite; /*!< SRTP crypto suite */ char local_fingerprint[160]; /*!< Fingerprint of our certificate */ @@ -291,6 +292,7 @@ struct ast_rtp { unsigned int dtls_failure:1; /*!< Failure occurred during DTLS negotiation */ unsigned int rekey; /*!< Interval at which to renegotiate and rekey */ int rekeyid; /*!< Scheduled item id for rekeying */ + int dtlstimerid; /*!< Scheduled item id for DTLS retransmission for RTP */ #endif }; @@ -402,6 +404,7 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level); #ifdef HAVE_OPENSSL_SRTP static int ast_rtp_activate(struct ast_rtp_instance *instance); +static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp); #endif static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp); @@ -1320,9 +1323,43 @@ static inline int rtcp_debug_test_addr(struct ast_sockaddr *addr) } #ifdef HAVE_OPENSSL_SRTP + +static int dtls_srtp_handle_timeout(const void *data) +{ + struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data; + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + if (!rtp) + { + return 0; + } + + ast_mutex_lock(&rtp->dtls_timer_lock); + if (rtp->dtlstimerid == -1) + { + ast_mutex_unlock(&rtp->dtls_timer_lock); + ao2_ref(instance, -1); + return 0; + } + + rtp->dtlstimerid = -1; + ast_mutex_unlock(&rtp->dtls_timer_lock); + + if (rtp->ssl) { + DTLSv1_handle_timeout(rtp->ssl); + } + + dtls_srtp_check_pending(instance, rtp); + + ao2_ref(instance, -1); + + return 0; +} + static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp) { size_t pending = BIO_ctrl_pending(rtp->write_bio); + struct timeval dtls_timeout; /* timeout on DTLS */ if (pending > 0) { char outgoing[pending]; @@ -1339,6 +1376,23 @@ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct as out = BIO_read(rtp->write_bio, outgoing, sizeof(outgoing)); + /* Stop existing DTLS timer if running */ + ast_mutex_lock(&rtp->dtls_timer_lock); + if (rtp->dtlstimerid > -1) { + AST_SCHED_DEL_UNREF(rtp->sched, rtp->dtlstimerid, ao2_ref(instance, -1)); + rtp->dtlstimerid = -1; + } + + if (DTLSv1_get_timeout(rtp->ssl, &dtls_timeout)) { + int timeout = dtls_timeout.tv_sec * 1000 + dtls_timeout.tv_usec / 1000; + ao2_ref(instance, +1); + if ((rtp->dtlstimerid = ast_sched_add(rtp->sched, timeout, dtls_srtp_handle_timeout, instance)) < 0) { + ao2_ref(instance, -1); + ast_log(LOG_WARNING, "scheduling DTLS retransmission for RTP instance [%p] failed.\n", instance); + } + } + ast_mutex_unlock(&rtp->dtls_timer_lock); + __rtp_sendto(instance, outgoing, out, 0, &remote_address, 0, &ice, 0); } } @@ -1972,6 +2026,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, #ifdef HAVE_OPENSSL_SRTP rtp->rekeyid = -1; + rtp->dtlstimerid = -1; #endif return 0; @@ -4319,6 +4374,9 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance) #ifdef HAVE_OPENSSL_SRTP AST_SCHED_DEL_UNREF(rtp->sched, rtp->rekeyid, ao2_ref(instance, -1)); + ast_mutex_lock(&rtp->dtls_timer_lock); + AST_SCHED_DEL_UNREF(rtp->sched, rtp->dtlstimerid, ao2_ref(instance, -1)); + ast_mutex_unlock(&rtp->dtls_timer_lock); #endif if (rtp->rtcp && rtp->rtcp->schedid > 0) {