[Serdev] Video NAT traversal

Rodrigo Frez rodrigo at frez.cl
Fri Jan 23 13:52:25 UTC 2004


The patch from gbernard works very well with two messenger clients
behind nat

#################################################################

--- nathelper.c.org     Sun Jan 18 22:36:30 2004
+++ nathelper.c Mon Jan 19 14:23:32 2004
@@ -49,6 +49,10 @@
  *               proxied and ignores sessions with such flag.
  *             o Added run-time check for version of command protocol
  *               supported by the RTP proxy.
+ * 2004-01-19   o Added support for a second RTP flow (ie VIDEO)
+ *              o Added support for RTCP (not tested)
+ *                (G. Bernard IPDirections)
+ *
  */

 #include "nhelpr_funcs.h"
@@ -106,7 +110,7 @@
 static int fix_nated_contact_f(struct sip_msg *, char *, char *);
 static int fix_nated_sdp_f(struct sip_msg *, char *, char *);
 static int extract_mediaip(str *, str *);
-static int extract_mediaport(str *, str *);
+static int extract_mediaport(str *, str *, str *, char *);
 static int alter_mediaip(struct sip_msg *, str *, str *, str *, int);
 static int alter_mediaport(struct sip_msg *, str *, str *, str *, int);
 static char *send_rtpp_command(const struct iovec *, int, int);
@@ -574,35 +578,59 @@
 }

 static int
-extract_mediaport(str *body, str *mediaport)
+extract_mediaport(str *body, str *mediaport, str *mediactl, char *type)
 {
        char *cp, *cp1;
        int len;

-       cp1 = NULL;
-       for (cp = body->s; (len = body->s + body->len - cp) > 0;) {
-               cp1 = ser_memmem(cp, "m=", len, 2);
-               if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
-                       break;
-               cp = cp1 + 2;
-       }
+       cp1 = body->s;
        if (cp1 == NULL) {
-               LOG(L_ERR, "ERROR: extract_mediaport: no `m=' in
SDP\n");
+               LOG(L_ERR, "ERROR: extract_mediaport: no body\n");
                return -1;
        }
-       mediaport->s = cp1 + 2;
-       mediaport->len = eat_line(mediaport->s, body->s + body->len -
-         mediaport->s) - mediaport->s;
-       trim_len(mediaport->len, mediaport->s, *mediaport);
-
-       if (mediaport->len < 7 || memcmp(mediaport->s, "audio", 5) != 0
||
-         !isspace((int)mediaport->s[5])) {
-               LOG(L_ERR, "ERROR: extract_mediaport: can't parse `m='
in SDP\n");
-               return -1;
+       while (cp1) {
+               for (cp = cp1; (len = body->s + body->len - cp) > 0;) {
+                       cp1 = ser_memmem(cp, "m=", len, 2);
+                       if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] ==
'\r')
+                               break;
+                       cp = cp1 + 2;
+               }
+               if (cp1 == NULL) {
+                       LOG(L_ERR,
+                               "ERROR: extract_mediaport: no `m=%s' in
SDP\n",
+                               type);
+                       return -1;
+               }
+               cp1 += 2;
+               mediaport->s = cp1;
+               mediaport->len = eat_line(mediaport->s, body->s +
body->len -
+               mediaport->s) - mediaport->s;
+               trim_len(mediaport->len, mediaport->s, *mediaport);
+
+               if (!(mediaport->len < 7 || memcmp(mediaport->s, type,
5) != 0
+                       || !isspace((int)mediaport->s[5]))) break;
        }
        cp = eat_space_end(mediaport->s + 5, mediaport->s +
mediaport->len);
        mediaport->len = eat_token_end(cp, mediaport->s +
mediaport->len) - cp;
        mediaport->s = cp;
+       mediactl->len = -1;
+       if (cp1 == NULL) {
+               LOG(L_ERR, "ERROR: extract_mediaport: no rctp port
found\n");
+               return 1;
+       }
+       for (cp = cp1; (len = body->s + body->len - cp) > 0;) {
+               cp1 = ser_memmem(cp, "a=rtcp:", len, 7);
+               if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
+                       break;
+               cp = cp1 + 7;
+       }
+       if (cp1 != NULL) {
+               cp1 += 7;
+               mediactl->s = cp1;
+               mediactl->len = eat_line(mediactl->s, body->s +
body->len -
+                       mediactl->s) - mediactl->s;
+               trim_len(mediactl->len, mediactl->s, *mediactl);
+       }
        return 1;
 }

@@ -774,7 +802,7 @@
 static int
 unforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2)
 {
-       str callid, from_tag, to_tag;
+       str callid, from_tag, to_tag, tag;
        struct iovec v[4 + 3] = {{"D", 1}, {" ", 1}, {NULL, 0}, {" ",
1}, {NULL, 0}, {" ", 1}, {NULL, 0}};
                                 /* 0 */   /* 1 */   /* 2 */    /* 3 */
/* 4 */    /* 5 */   /* 6 */

@@ -795,10 +823,26 @@
                LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get From
tag\n");
                return -1;
        }
-       STR2IOVEC(callid, v[2]);
+       tag.s = pkg_malloc(callid.len + 6);
+       if (tag.s == NULL) {
+               LOG(L_ERR, "ERROR: type_tag: out of memory\n");
+               return -1;
+       }
+       strcpy(tag.s, "audio-");
+       strncat(tag.s, callid.s, callid.len);
+       tag.len = callid.len + 6;
+       tag.s[tag.len] = (char)0;
+       STR2IOVEC(tag, v[2]);
        STR2IOVEC(from_tag, v[4]);
        STR2IOVEC(to_tag, v[6]);
        send_rtpp_command(v, (to_tag.len > 0) ? 7 : 5, 0);
+       strcpy(tag.s, "video-");
+       strncat(tag.s, callid.s, callid.len);
+       tag.len = callid.len + 6;
+       tag.s[tag.len] = (char)0;
+       STR2IOVEC(tag, v[2]);
+       send_rtpp_command(v, (to_tag.len > 0) ? 7 : 5, 0);
+       pkg_free(tag.s);

        return 1;
 }
@@ -806,10 +850,12 @@
 static int
 force_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2)
 {
-       str body, body1, oldport, oldip, oldip1, newport, newip;
-       str callid, from_tag, to_tag;
-       int create, port, len;
+       str body, body1, oldport, oldctl, oldvport, oldvctl, oldip,
oldip1;
+        str newvport, newport, newip;
+       str callid, from_tag, to_tag, tag;
+       int create, port, portv=0, len;
        char buf[16];
+       char fub[16];
        char *cp, *cp1;
        struct lump* anchor;
        struct iovec v[6 + 5] = {{"U", 1}, {" ", 1}, {NULL, 0}, {" ",
1}, {NULL, 7}, {" ", 1}, {NULL, 1}, {" ", 1}, {NULL, 0}, {" ", 1},
{NULL, 0}};
@@ -868,29 +914,80 @@
        if (extract_mediaip(&body1, &oldip1) == -1) {
                oldip1.len = 0;
        }
-       if (extract_mediaport(&body, &oldport) == -1) {
-               LOG(L_ERR, "ERROR: force_rtp_proxy: can't extract media
port "
+       if (extract_mediaport(&body, &oldport, &oldctl, "audio") == -1)
{
+               LOG(L_ERR, "ERROR: force_rtp_proxy: can't extract audio
port "
                    "from the message\n");
                return -1;
        }
+       if (oldctl.len > 0)
+               LOG(L_DBG, "DEBUG: Found Audio RTP/RTCP ports\n");
+       else
+               LOG(L_DBG, "DEBUG: Found Audio RTP port\n");
+       if (extract_mediaport(&body, &oldvport, &oldvctl, "video") ==
-1) {
+               LOG(L_ERR, "ERROR: force_rtp_proxy: can't extract video
port "
+                   "from the message\n");
+               oldvport.len = oldvctl.len = -1;
+       }
+       if (oldvctl.len > 0)
+               LOG(L_DBG, "DEBUG: Found Video RTP/RTCP ports\n");
+       else if (oldvport.len > 0)
+               LOG(L_DBG, "DEBUG: Found Video RTP port\n");
        newip.s = ip_addr2a(&msg->rcv.src_ip);
        newip.len = strlen(newip.s);
        if (create == 0)
                v[0].iov_base = "L";
-       STR2IOVEC(callid, v[2]);
+       tag.s = pkg_malloc(callid.len + 6);
+       if (tag.s == NULL) {
+               LOG(L_ERR, "ERROR: force_rtpproxy: out of memory\n");
+               return -1;
+       }
+       strcpy(tag.s, "audio-");
+       strncat(tag.s, callid.s, callid.len);
+       tag.len = callid.len + 6;
+       tag.s[tag.len] = (char)0;
+       STR2IOVEC(tag, v[2]);
        STR2IOVEC(newip, v[4]);
        STR2IOVEC(oldport, v[6]);
        STR2IOVEC(from_tag, v[8]);
        STR2IOVEC(to_tag, v[10]);
+       LOG(L_DBG, "DEBUG: Call-ID set to: %s\n", tag.s);
        cp = send_rtpp_command(v, (to_tag.len > 0) ? 11 : 9, 1);
+       pkg_free(tag.s);
        if (cp == NULL)
                return -1;
+       LOG(L_DBG, "DEBUG: New audio port is %s", cp);
        port = atoi(cp);
-       if (port <= 0 || port > 65535)
+       if (port <= 0 || port > 65534)
                return -1;

        newport.s = buf;
        newport.len = sprintf(buf, "%d", port);
+
+       if (oldvport.len > 0) {
+               tag.s = pkg_malloc(callid.len + 6);
+               if (tag.s == NULL) {
+                       LOG(L_ERR, "ERROR: force_rtpproxy: out of
memory\n");
+                       return -1;
+               }
+               strcpy(tag.s, "video-");
+               strncat(tag.s, callid.s, callid.len);
+               tag.len = callid.len + 6;
+               tag.s[tag.len] = (char)0;
+               STR2IOVEC(tag, v[2]);
+               STR2IOVEC(oldvport, v[6]);
+               LOG(L_DBG, "DEBUG: Call-ID set to: %s\n", tag.s);
+               cp = send_rtpp_command(v, (to_tag.len > 0) ? 11 : 9, 1);
+               pkg_free(tag.s);
+               if (cp == NULL)
+                       return -1;
+               LOG(L_DBG, "DEBUG: New video port is %s", cp);
+               portv = atoi(cp);
+               if (portv <= 0 || portv > 65534)
+                       return -1;
+               newvport.s = fub;
+               newvport.len = sprintf(fub, "%d", portv);
+       }
+
        newip.s = ip_addr2a(&msg->rcv.dst_ip);
        newip.len = strlen(newip.s);

@@ -901,6 +998,21 @@
                return -1;
        if (alter_mediaport(msg, &body, &oldport, &newport, 0) == -1)
                return -1;
+       port++;
+       newport.s = buf;
+       newport.len = sprintf(buf, "%d", port);
+       if (oldctl.len > 0 &&
+               alter_mediaport(msg, &body, &oldctl, &newport, 0) == -1)
+                       return -1;
+       if (oldvport.len > 0 &&
+               alter_mediaport(msg, &body, &oldvport, &newvport, 0) ==
-1)
+                       return -1;
+       portv++;
+       newvport.s = fub;
+       newvport.len = sprintf(fub, "%d", portv);
+       if (oldvport.len > 0 && oldvctl.len > 0 &&
+               alter_mediaport(msg, &body, &oldvctl, &newvport, 0) ==
-1)
+                       return -1;

        cp = pkg_malloc(ANORTPPROXY_LEN * sizeof(char));
        if (cp == NULL) {

#################################################################
-----Original Message-----
From: Adrian Georgescu [mailto:ag at ag-projects.com] 
Sent: Viernes, 23 de Enero de 2004 10:43
To: serdev at lists.iptel.org
Subject: [Serdev] Video NAT traversal


If nobody is bussy with this I am prepared to allocated resources for 
this project.

I will check personally with Maxim but any feed back is appreciated.

---
Adrian

_______________________________________________
Serdev mailing list
serdev at lists.iptel.org
http://lists.iptel.org/mailman/listinfo/serdev





More information about the Serdev mailing list