<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6339">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_rtp_asterisk: Only learn a new source in learn state.<br><br>This change moves the logic which learns a new source address<br>for RTP so it only occurs in the learning state. The learning<br>state is entered on initial allocation of RTP or if we are<br>told that the remote address for the media has changed. While<br>in the learning state if we continue to receive media from<br>the original source we restart the learning process. It is<br>only once we receive a sufficient number of RTP packets from<br>the new source that we will switch to it. Once this is done<br>the closed state is entered where all packets that do not<br>originate from the expected source are dropped.<br><br>The learning process has also been improved to take into<br>account the time between received packets so a flood of them<br>while in the learning state does not cause media to be switched.<br><br>Finally RTCP now drops packets which are not for the learned<br>SSRC if strict RTP is enabled.<br><br>ASTERISK-27013<br><br>Change-Id: I56a96e993700906355e79bc880ad9d4ad3ab129c<br>---<br>M res/res_rtp_asterisk.c<br>1 file changed, 50 insertions(+), 37 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/39/6339/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c<br>index 039ed5f..fa0baf2 100644<br>--- a/res/res_rtp_asterisk.c<br>+++ b/res/res_rtp_asterisk.c<br>@@ -218,8 +218,9 @@<br> <br> /*! \brief RTP learning mode tracking information */<br> struct rtp_learning_info {<br>- int max_seq; /*!< The highest sequence number received */<br>- int packets; /*!< The number of remaining packets before the source is accepted */<br>+ int max_seq; /*!< The highest sequence number received */<br>+ int packets; /*!< The number of remaining packets before the source is accepted */<br>+ struct timeval received; /*!< The time of the last received packet */<br> };<br> <br> #ifdef HAVE_OPENSSL_SRTP<br>@@ -312,7 +313,6 @@<br> * but these are in place to keep learning mode sequence values sealed from their normal counterparts.<br> */<br> struct rtp_learning_info rtp_source_learn; /* Learning mode track for the expected RTP source */<br>- struct rtp_learning_info alt_source_learn; /* Learning mode tracking for a new RTP source after one has been chosen */<br> <br> struct rtp_red *red;<br> <br>@@ -2755,6 +2755,7 @@<br> {<br> info->max_seq = seq - 1;<br> info->packets = learning_min_sequential;<br>+ memset(&info->received, 0, sizeof(info->received));<br> }<br> <br> /*!<br>@@ -2769,6 +2770,13 @@<br> */<br> static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq)<br> {<br>+ if (!ast_tvzero(info->received) && ast_tvdiff_ms(ast_tvnow(), info->received) < 5) {<br>+ /* During the probation period the minimum amount of media we'll accept is<br>+ * 10ms so give a reasonable 5ms buffer just in case we get it sporadically.<br>+ */<br>+ return 1;<br>+ }<br>+<br> if (seq == info->max_seq + 1) {<br> /* packet is in sequence */<br> info->packets--;<br>@@ -2777,6 +2785,7 @@<br> info->packets = learning_min_sequential - 1;<br> }<br> info->max_seq = seq;<br>+ info->received = ast_tvnow();<br> <br> return (info->packets == 0);<br> }<br>@@ -3051,10 +3060,9 @@<br> /* Set default parameters on the newly created RTP structure */<br> rtp->ssrc = ast_random();<br> rtp->seqno = ast_random() & 0x7fff;<br>- rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);<br>+ rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_CLOSED : STRICT_RTP_OPEN);<br> if (strictrtp) {<br> rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);<br>- rtp_learning_seq_init(&rtp->alt_source_learn, (uint16_t)rtp->seqno);<br> }<br> <br> /* Create a new socket for us to listen on and use */<br>@@ -4593,17 +4601,6 @@<br> <br> packetwords = size / 4;<br> <br>- if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {<br>- /* Send to whoever sent to us */<br>- if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) {<br>- ast_sockaddr_copy(&rtp->rtcp->them, addr);<br>- if (rtpdebug) {<br>- ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",<br>- ast_sockaddr_stringify(&rtp->rtcp->them));<br>- }<br>- }<br>- }<br>-<br> ast_debug(1, "Got RTCP report of %zu bytes\n", size);<br> <br> while (position < packetwords) {<br>@@ -4630,6 +4627,25 @@<br> ast_debug(1, "RTCP Read too short\n");<br> }<br> return &ast_null_frame;<br>+ }<br>+<br>+ if ((rtp->strict_rtp_state != STRICT_RTP_OPEN) && (rtcp_report->ssrc != rtp->themssrc)) {<br>+ /* Skip over this RTCP record as it does not contain the correct SSRC */<br>+ position += (length + 1);<br>+ ast_debug(1, "%p -- Received RTCP report from %s, dropping due to strict RTP protection. Received SSRC '%u' but expected '%u'\n",<br>+ rtp, ast_sockaddr_stringify(addr), rtcp_report->ssrc, rtp->themssrc);<br>+ continue;<br>+ }<br>+<br>+ if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {<br>+ /* Send to whoever sent to us */<br>+ if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) {<br>+ ast_sockaddr_copy(&rtp->rtcp->them, addr);<br>+ if (rtpdebug) {<br>+ ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",<br>+ ast_sockaddr_stringify(&rtp->rtcp->them));<br>+ }<br>+ }<br> }<br> <br> if (rtcp_debug_test_addr(addr)) {<br>@@ -5055,37 +5071,30 @@<br> <br> /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */<br> if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {<br>- ast_debug(1, "%p -- Probation learning mode pass with source address %s\n", rtp, ast_sockaddr_stringify(&addr));<br>- /* For now, we always copy the address. */<br>- ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);<br>-<br>- /* Send the rtp and the seqno from header to rtp_learning_rtp_seq_update to see whether we can exit or not*/<br>- if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {<br>- ast_debug(1, "%p -- Probation at seq %d with %d to go; discarding frame\n",<br>- rtp, rtp->rtp_source_learn.max_seq, rtp->rtp_source_learn.packets);<br>- return &ast_null_frame;<br>- }<br>-<br>- ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));<br>- rtp->strict_rtp_state = STRICT_RTP_CLOSED;<br>- }<br>- if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {<br> if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {<br>- /* Always reset the alternate learning source */<br>- rtp_learning_seq_init(&rtp->alt_source_learn, seqno);<br>+ /* We are learning a new address but have received traffic from the existing address,<br>+ * accept it but reset the current learning for the new source so it only takes over<br>+ * once sufficient traffic has been received. */<br>+ rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);<br> } else {<br> /* Start trying to learn from the new address. If we pass a probationary period with<br> * it, that means we've stopped getting RTP from the original source and we should<br> * switch to it.<br> */<br>- if (rtp_learning_rtp_seq_update(&rtp->alt_source_learn, seqno)) {<br>+ if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {<br> ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n",<br>- rtp, ast_sockaddr_stringify(&addr), rtp->alt_source_learn.packets);<br>+ rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);<br> return &ast_null_frame;<br> }<br>- ast_verb(4, "%p -- Switching RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));<br> ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);<br>+<br>+ ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));<br>+ rtp->strict_rtp_state = STRICT_RTP_CLOSED;<br> }<br>+ } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED && ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {<br>+ ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n",<br>+ rtp, ast_sockaddr_stringify(&addr));<br>+ return &ast_null_frame;<br> }<br> <br> /* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */<br>@@ -5608,7 +5617,11 @@<br> <br> rtp->rxseqno = 0;<br> <br>- if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN) {<br>+ if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN && !ast_sockaddr_isnull(addr) &&<br>+ ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) {<br>+ /* We only need to learn a new strict source address if we've been told the source is<br>+ * changing to something different.<br>+ */<br> rtp->strict_rtp_state = STRICT_RTP_LEARN;<br> rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno);<br> }<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6339">change 6339</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6339"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 14 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I56a96e993700906355e79bc880ad9d4ad3ab129c </div>
<div style="display:none"> Gerrit-Change-Number: 6339 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>