<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6338">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/38/6338/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 e6ac793..18646a5 100644<br>--- a/res/res_rtp_asterisk.c<br>+++ b/res/res_rtp_asterisk.c<br>@@ -213,8 +213,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>@@ -299,7 +300,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>@@ -2424,6 +2424,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>@@ -2438,6 +2439,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>@@ -2446,6 +2454,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>@@ -2652,10 +2661,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>@@ -4154,17 +4162,6 @@<br> <br>      packetwords = res / 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 %d bytes\n", res);<br> <br>      while (position < packetwords) {<br>@@ -4191,6 +4188,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>@@ -4517,37 +4533,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>@@ -5005,7 +5014,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/6338">change 6338</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/6338"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: certified/13.13 </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: 6338 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>