소스 검색

nathelper(k): Core SDP parser integrated into nathelper

The nathelper (k version) is using the core SDP parser to
extract the IP and port from the received message.
Ovidiu Sas 15 년 전
부모
커밋
377e5afba8
1개의 변경된 파일96개의 추가작업 그리고 276개의 파일을 삭제
  1. 96 276
      modules_k/nathelper/nathelper.c

+ 96 - 276
modules_k/nathelper/nathelper.c

@@ -161,6 +161,8 @@
  *             (bogdan)
  * 2008-12-12 Support for RTCP attribute in the SDP
  *              (Min Wang/BASIS AudioNet - ported from SER)
+ * 2010-08-05 Core SDP parser integrated into nathelper
+ *             (osas)
  */
 
 #include <sys/types.h>
@@ -200,6 +202,7 @@
 #include "../../parser/parse_to.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/parser_f.h"
+#include "../../parser/sdp/sdp.h"
 #include "../../resolve.h"
 #include "../../timer.h"
 #include "../../trim.h"
@@ -285,8 +288,6 @@ static int pv_get_rr_count_f(struct sip_msg *, pv_param_t *, pv_value_t *);
 static int pv_get_rr_top_count_f(struct sip_msg *, pv_param_t *, pv_value_t *);
 static int fix_nated_sdp_f(struct sip_msg *, char *, char *);
 static int extract_mediaip(str *, str *, int *, char *);
-static int extract_mediainfo(str *, str *, str *);
-static int extract_rtcp(str *body, str *rtcpport);
 static int alter_mediaip(struct sip_msg *, str *, str *, int, str *, int, int);
 static int alter_mediaport(struct sip_msg *, str *, str *, str *, int);
 static int alter_rtcp(struct sip_msg *msg, str *body, str *oldport, str *newport);
@@ -307,9 +308,6 @@ static int rtpproxy_answer2_f(struct sip_msg *, char *, char *);
 static int rtpproxy_offer1_f(struct sip_msg *, char *, char *);
 static int rtpproxy_offer2_f(struct sip_msg *, char *, char *);
 
-static char *find_sdp_line(char *, char *, char);
-static char *find_next_sdp_line(char *, char *, char, char *);
-
 static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, char * rtpproxy);
 static int fixup_set_id(void ** param, int param_no);
 static int set_rtp_proxy_set_f(struct sip_msg * msg, char * str1, char * str2);
@@ -350,21 +348,6 @@ static struct {
 	{NULL, 0, 0}
 };
 
-static struct {
-	const char *s;
-	int len;
-	int is_rtp;
-} sup_ptypes[] = {
-	{.s = "udp",       .len = 3, .is_rtp = 0},
-	{.s = "udptl",     .len = 5, .is_rtp = 0},
-	{.s = "rtp/avp",   .len = 7, .is_rtp = 1},
-	{.s = "rtp/avpf",  .len = 8, .is_rtp = 1},
-	{.s = "rtp/savp",  .len = 8, .is_rtp = 1},
-	{.s = "rtp/savpf", .len = 9, .is_rtp = 1},
-	{.s = "udp/bfcp",  .len = 8, .is_rtp = 0},
-	{.s = NULL,        .len = 0, .is_rtp = 0}
-};
-
 /*
  * If this parameter is set then the natpinger will ping only contacts
  * that have the NAT flag set in user location database
@@ -1985,121 +1968,6 @@ extract_mediaip(str *body, str *mediaip, int *pf, char *line)
 	return 1;
 }
 
-static int
-extract_mediainfo(str *body, str *mediaport, str *payload_types)
-{
-	char *cp, *cp1;
-	int len, i;
-	str ptype;
-
-	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;
-	}
-	if (cp1 == NULL) {
-		LM_ERR("no `m=' in SDP\n");
-		return -1;
-	}
-	mediaport->s = cp1 + 2; /* skip `m=' */
-	mediaport->len = eat_line(mediaport->s, body->s + body->len -
-	  mediaport->s) - mediaport->s;
-	trim_len(mediaport->len, mediaport->s, *mediaport);
-
-	/* Skip media supertype and spaces after it */
-	cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
-	mediaport->len -= cp - mediaport->s;
-	if (mediaport->len <= 0 || cp == mediaport->s) {
-		LM_ERR("no port in `m='\n");
-		return -1;
-	}
-	mediaport->s = cp;
-	cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len);
-	mediaport->len -= cp - mediaport->s;
-	if (mediaport->len <= 0 || cp == mediaport->s) {
-		LM_ERR("no port in `m='\n");
-		return -1;
-	}
-	/* Extract port */
-	mediaport->s = cp;
-	cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
-	ptype.len = mediaport->len - (cp - mediaport->s);
-	if (ptype.len <= 0 || cp == mediaport->s) {
-		LM_ERR("no port in `m='\n");
-		return -1;
-	}
-	ptype.s = cp;
-	mediaport->len = cp - mediaport->s;
-	/* Skip spaces after port */
-	cp = eat_space_end(ptype.s, ptype.s + ptype.len);
-	ptype.len -= cp - ptype.s;
-	if (ptype.len <= 0 || cp == ptype.s) {
-		LM_ERR("no protocol type in `m='\n");
-		return -1;
-	}
-	/* Extract protocol type */
-	ptype.s = cp;
-	cp = eat_token_end(ptype.s, ptype.s + ptype.len);
-	if (cp == ptype.s) {
-		LM_ERR("no protocol type in `m='\n");
-		return -1;
-	}
-	payload_types->len = ptype.len - (cp - ptype.s);
-	ptype.len = cp - ptype.s;
-	payload_types->s = cp;
-
-	for (i = 0; sup_ptypes[i].s != NULL; i++) {
-		if (ptype.len != sup_ptypes[i].len ||
-		    strncasecmp(ptype.s, sup_ptypes[i].s, ptype.len) != 0)
-			continue;
-		if (sup_ptypes[i].is_rtp == 0) {
-			payload_types->len = 0;
-			return 0;
-		}
-		cp = eat_space_end(payload_types->s, payload_types->s +
-		    payload_types->len);
-		if (cp == payload_types->s) {
-			LM_ERR("no payload types in `m='\n");
-			return -1;
-		}
-		payload_types->len -= cp - payload_types->s;
-		payload_types->s = cp;
-		return 0;
-	}
-	/* Unproxyable protocol type. Generally it isn't error. */
-	return -1;
-}
-
-/*
- * this function is ported from SER 
- */
-static int
-extract_rtcp(str *body, str *rtcpport)
-{
-	char *cp, *cp1;
-	int len;
-
-	cp1 = NULL;
-	for (cp = body->s; (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)
-		return -1;
-
-	rtcpport->s = cp1 + 7; /* skip `a=rtcp:' */
-	rtcpport->len = eat_line(rtcpport->s, body->s + body->len -
-				 rtcpport->s) - rtcpport->s;
-	trim_len(rtcpport->len, rtcpport->s, *rtcpport);
-
-	return 0;
-}
-
 static int
 alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf,
   str *newip, int newpf, int preserve)
@@ -2632,54 +2500,8 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2)
 	return 1;
 }
 
-/*
- * Auxiliary for some functions.
- * Returns pointer to first character of found line, or NULL if no such line.
- */
-
-static char *
-find_sdp_line(char* p, char* plimit, char linechar)
-{
-	static char linehead[3] = "x=";
-	char *cp, *cp1;
-	linehead[0] = linechar;
-	/* Iterate thru body */
-	cp = p;
-	for (;;) {
-		if (cp >= plimit)
-			return NULL;
-		cp1 = ser_memmem(cp, linehead, plimit-cp, 2);
-		if (cp1 == NULL)
-			return NULL;
-		/*
-		 * As it is body, we assume it has previous line and we can
-		 * lookup previous character.
-		 */
-		if (cp1[-1] == '\n' || cp1[-1] == '\r')
-			return cp1;
-		/*
-		 * Having such data, but not at line beginning.
-		 * Skip them and reiterate. ser_memmem() will find next
-		 * occurence.
-		 */
-		if (plimit - cp1 < 2)
-			return NULL;
-		cp = cp1 + 2;
-	}
-}
-
 /* This function assumes p points to a line of requested type. */
 
-static char *
-find_next_sdp_line(char* p, char* plimit, char linechar, char* defptr)
-{
-	char *t;
-	if (p >= plimit || plimit - p < 3)
-		return defptr;
-	t = find_sdp_line(p + 2, plimit, linechar);
-	return t ? t : defptr;
-}
-
 static int
 set_rtp_proxy_set_f(struct sip_msg * msg, char * str1, char * str2)
 {
@@ -2800,7 +2622,7 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 {
 	str body, body1, oldport, oldip, newport, newip;
 	str callid, from_tag, to_tag, tmp, payload_types;
-	str oldrtcp, newrtcp;
+	str newrtcp;
 	int create, port, len, flookup, argc, proxied, real;
 	int orgip, commip;
 	int pf, pf1, force, swap;
@@ -2830,13 +2652,17 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 		{";", 1},	/* separator */
 		{NULL, 0}	/* medianum */
 	};
-	char *v1p, *v2p, *c1p, *c2p, *m1p, *m2p, *bodylimit, *o1p;
+	char *c1p, *c2p, *bodylimit, *o1p;
 	char medianum_buf[20];
 	int medianum, media_multi;
-	str medianum_str, tmpstr1;
+	str medianum_str;
 	int c1p_altered;
 	static int swap_warned = 0;
 
+	int sdp_session_num, sdp_stream_num;
+	sdp_session_cell_t* sdp_session;
+	sdp_stream_cell_t* sdp_stream;
+
 	memset(&opts, '\0', sizeof(opts));
 	memset(&rep_opts, '\0', sizeof(rep_opts));
 	memset(&pt_opts, '\0', sizeof(pt_opts));
@@ -3027,16 +2853,13 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 	 * to the same value (RTP proxy IP), so we can change all c-lines
 	 * unconditionally.
 	 */
-	bodylimit = body.s + body.len;
-	v1p = find_sdp_line(body.s, bodylimit, 'v');
-	if (v1p == NULL) {
-		LM_ERR("no sessions in SDP\n");
+	if(0 != parse_sdp(msg)) {
+		LM_ERR("Unable to parse sdp\n");
 		FORCE_RTP_PROXY_RET (-1);
 	}
-	v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);
-	media_multi = (v2p != bodylimit);
-	v2p = v1p;
-	medianum = 0;
+	print_sdp((sdp_info_t*)msg->body, L_INFO);
+
+	bodylimit = body.s + body.len;
 
 	if(msg->id != current_msg_id){
 		selected_rtpp_set = default_rtpp_set;
@@ -3049,68 +2872,45 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 	STR2IOVEC(from_tag, v[11]);
 	STR2IOVEC(to_tag, v[15]);
 
+	/* check if this is a single or a multi stream SDP offer/answer */
+	sdp_stream_num = get_sdp_stream_num(msg);
+	switch (sdp_stream_num) {
+	case 0:
+		LM_ERR("sdp w/o streams\n");
+		FORCE_RTP_PROXY_RET (-1);
+		break;
+	case 1:
+		media_multi = 0;
+		break;
+	default:
+		media_multi = 1;
+	}
+#ifdef EXTRA_DEBUG
+	LM_DBG("my new media_multi=%d\n", media_multi);
+#endif
+	medianum = 0; 
+	sdp_session_num = 0;
 	for(;;) {
-		/* Per-session iteration. */
-		v1p = v2p;
-		if (v1p == NULL || v1p >= bodylimit)
-			break; /* No sessions left */
-		v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);
-		/* v2p is text limit for session parsing. */
-		/* get session origin */
-		o1p = find_sdp_line(v1p, v2p, 'o');
-		if (o1p==0) {
-			LM_ERR("no o= in session\n");
-			FORCE_RTP_PROXY_RET (-1);
-		}
-		/* Have this session media description? */
-		m1p = find_sdp_line(o1p, v2p, 'm');
-		if (m1p == NULL) {
-			LM_ERR("no m= in session\n");
-			FORCE_RTP_PROXY_RET (-1);
-		}
-		/*
-		 * Find c1p only between session begin and first media.
-		 * c1p will give common c= for all medias.
-		 */
-		c1p = find_sdp_line(o1p, m1p, 'c');
+		sdp_session = get_sdp_session(msg, sdp_session_num);
+		if(!sdp_session) break;
+		sdp_stream_num = 0;
 		c1p_altered = 0;
-		if (orgip==0)
-			o1p = 0;
-		/* Have session. Iterate media descriptions in session */
-		m2p = m1p;
-		for (;;) {
-			m1p = m2p;
-			if (m1p == NULL || m1p >= v2p)
-				break;
-			m2p = find_next_sdp_line(m1p, v2p, 'm', v2p);
-			/* c2p will point to per-media "c=" */
-			c2p = find_sdp_line(m1p, m2p, 'c');
-			/* Extract address and port */
-			tmpstr1.s = c2p ? c2p : c1p;
-			if (tmpstr1.s == NULL) {
-				/* No "c=" */
-				LM_ERR("can't find media IP in the message\n");
-				FORCE_RTP_PROXY_RET (-1);
-			}
-			tmpstr1.len = v2p - tmpstr1.s; /* limit is session limit text */
-			if (extract_mediaip(&tmpstr1, &oldip, &pf,"c=") == -1) {
-				LM_ERR("can't extract media IP from the message\n");
-				FORCE_RTP_PROXY_RET (-1);
-			}
-			tmpstr1.s = m1p;
-			tmpstr1.len = m2p - m1p;
-			if (extract_mediainfo(&tmpstr1, &oldport, &payload_types) == -1) {
-				LM_ERR("can't extract media port from the message\n");
-				FORCE_RTP_PROXY_RET (-1);
+		o1p = sdp_session->o_ip_addr.s;
+		for(;;) {
+			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
+			if(!sdp_stream) break;
+
+			if (sdp_stream->ip_addr.s && !sdp_stream->ip_addr.len) {
+				oldip = sdp_stream->ip_addr;
+				pf = sdp_stream->pf;
+			} else {
+				oldip = sdp_session->ip_addr;
+				pf = sdp_session->pf;
 			}
-			/* Extract rtcp attribute,ported from SER */
-			tmpstr1.s = m1p;
-			tmpstr1.len = m2p - m1p;
-			oldrtcp.s = NULL;
-			oldrtcp.len = 0;
-			extract_rtcp(&tmpstr1, &oldrtcp);
-			
-			++medianum;
+			oldport = sdp_stream->port;
+			payload_types = sdp_stream->payloads;
+			medianum++;
+
 			if (real != 0) {
 				newip = oldip;
 			} else {
@@ -3126,6 +2926,10 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 			}
 			STR2IOVEC(newip, v[7]);
 			STR2IOVEC(oldport, v[9]);
+#ifdef EXTRA_DEBUG
+			LM_DBG("STR2IOVEC(newip[%.*s], v[7])", newip.len, newip.s);
+			LM_DBG("STR2IOVEC(oldport[%.*s], v[9])", oldport.len, oldport.s);
+#endif
 			if (1 || media_multi) /* XXX netch: can't choose now*/
 			{
 				snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum);
@@ -3133,6 +2937,10 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 				medianum_str.len = strlen(medianum_buf);
 				STR2IOVEC(medianum_str, v[13]);
 				STR2IOVEC(medianum_str, v[17]);
+#ifdef EXTRA_DEBUG
+				LM_DBG("STR2IOVEC(medianum_str, v[13])\n");
+				LM_DBG("STR2IOVEC(medianum_str, v[17])\n");
+#endif
 			} else {
 				v[12].iov_len = v[13].iov_len = 0;
 				v[16].iov_len = v[17].iov_len = 0;
@@ -3153,7 +2961,10 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 						v[2].iov_len += rep_opts.oidx;
 					}
 				}
-				if (payload_types.len > 0 && node->rn_ptl_supported != 0) {
+#ifdef EXTRA_DEBUG
+				LM_DBG("payload_types='%.*s'\n", payload_types.len, payload_types.s);
+#endif
+				if (sdp_stream->is_rtp && payload_types.len > 0 && node->rn_ptl_supported != 0) {
 					pt_opts.oidx = 0;
 					if (append_opts(&pt_opts, 'c') == -1) {
 						LM_ERR("out of pkg memory\n");
@@ -3236,8 +3047,11 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 			/* marker to double check : newport goes: str -> int -> str ?!?! */
 			newport.s = int2str(port, &newport.len); /* beware static buffer */
 			/* Alter port. */
-			body1.s = m1p;
+			body1.s = sdp_stream->media.s;
 			body1.len = bodylimit - body1.s;
+#ifdef EXTRA_DEBUG
+			LM_DBG("alter port body1='%.*s'\n", body1.len, body1.s);
+#endif
 			/* do not do it if old port was 0 (means media disable)
 			 * - check if actually should be better done in rtpptoxy,
 			 *   by returning also 0
@@ -3255,19 +3069,23 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 			 * by RTP proxy). No IP-address is needed in the new RTCP attribute as the
 			 * 'c' attribute (altered below) will contain the RTP proxy IP address.
 			 * See RFC 3605 for definition of RTCP attribute.
-             * ported from ser
+			 * ported from ser
 			 */
-			if (oldrtcp.s && oldrtcp.len) {
+			if (sdp_stream->rtcp_port.s && sdp_stream->rtcp_port.len) {
 				newrtcp.s = int2str(port+1, &newrtcp.len); /* beware static buffer */
 				/* Alter port. */
-				body1.s = m1p;
+				body1.s = sdp_stream->rtcp_port.s;
 				body1.len = bodylimit - body1.s;
-				if (alter_rtcp(msg, &body1, &oldrtcp, &newrtcp) == -1) {
+#ifdef EXTRA_DEBUG
+				LM_DBG("alter rtcp body1='%.*s'\n", body1.len, body1.s);
+#endif
+				if (alter_rtcp(msg, &body1, &sdp_stream->rtcp_port, &newrtcp) == -1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
-			}			
-			
-			
+			}
+
+			c1p = sdp_session->ip_addr.s;
+			c2p = sdp_stream->ip_addr.s;
 			/*
 			 * Alter IP. Don't alter IP common for the session
 			 * more than once.
@@ -3275,6 +3093,9 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 			if (c2p != NULL || !c1p_altered) {
 				body1.s = c2p ? c2p : c1p;
 				body1.len = bodylimit - body1.s;
+#ifdef EXTRA_DEBUG
+				LM_DBG("alter ip body1='%.*s'\n", body1.len, body1.s);
+#endif
 				if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0)==-1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
@@ -3285,15 +3106,12 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 			 * Alter common IP if required, but don't do it more than once.
 			 */
 			if (commip && c1p && !c1p_altered) {
-				tmpstr1.s = c1p;
-				tmpstr1.len = v2p - tmpstr1.s;
-				if (extract_mediaip(&tmpstr1, &oldip, &pf,"c=") == -1) {
-					LM_ERR("can't extract media IP from the message\n");
-					FORCE_RTP_PROXY_RET (-1);
-				}
 				body1.s = c1p;
 				body1.len = bodylimit - body1.s;
-				if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0)==-1) {
+#ifdef EXTRA_DEBUG
+				LM_DBG("alter common ip body1='%.*s'\n", body1.len, body1.s);
+#endif
+				if (alter_mediaip(msg, &body1, &sdp_session->ip_addr, sdp_session->pf, &newip, pf1, 0)==-1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
 				c1p_altered = 1;
@@ -3302,21 +3120,23 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer)
 			 * Alter the IP in "o=", but only once per session
 			 */
 			if (o1p) {
-				tmpstr1.s = o1p;
-				tmpstr1.len = v2p - tmpstr1.s;
-				if (extract_mediaip(&tmpstr1, &oldip, &pf,"o=") == -1) {
-					LM_ERR("can't extract media IP from the message\n");
-					FORCE_RTP_PROXY_RET (-1);
-				}
 				body1.s = o1p;
 				body1.len = bodylimit - body1.s;
-				if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0)==-1) {
+#ifdef EXTRA_DEBUG
+				LM_DBG("alter media ip body1='%.*s'\n", body1.len, body1.s);
+#endif
+				if (alter_mediaip(msg, &body1, &sdp_session->o_ip_addr, sdp_session->o_pf, &newip, pf1, 0)==-1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
 				o1p = 0;
 			}
-		} /* Iterate medias in session */
-	} /* Iterate sessions */
+			sdp_stream_num++;
+		}
+		sdp_session_num++;
+	}
+
+
+
 	free_opts(&opts, &rep_opts, &pt_opts);
 
 	if (proxied == 0 && nortpproxy_str.len) {