Преглед изворни кода

Merge branch 'master' of https://github.com/kamailio/kamailio

Juha Heinanen пре 9 година
родитељ
комит
b4e3c04b60

+ 1 - 1
futexlock.h

@@ -142,7 +142,7 @@ static inline int futex_try(futex_lock_t* lock)
 {
 	int c;
 	c=atomic_cmpxchg(lock, 0, 1);
-	if (likely(c))
+	if (likely(c==0))
 		membar_enter_lock();
 	return c;
 }

+ 52 - 22
modules/rtpproxy/rtpproxy.c

@@ -2227,16 +2227,22 @@ free_opts(struct options *op1, struct options *op2, struct options *op3)
 	return (e); \
     } while (0);
 
+struct new_mediaip {
+	str strip;
+	int pf;
+};
+
 static int
 force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forcedIP)
 {
-	str body, body1, oldport, oldip, newport, newip;
+	str body, body1, oldport, oldip, newport;
+	struct new_mediaip newip;
 	str callid, from_tag, to_tag, tmp, payload_types;
 	str newrtcp = {0, 0};
 	str viabranch;
 	int create, port, len, flookup, argc, proxied, real, via, ret;
 	int orgip, commip;
-	int pf, pf1, force;
+	int pf, force;
 	struct options opts, rep_opts, pt_opts;
 	char *cp, *cp1;
 	char  *cpend, *next;
@@ -2575,10 +2581,12 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 			medianum++;
 
 			if (real != 0) {
-				newip = oldip;
+				newip.strip = oldip;
+				newip.pf = pf;
 			} else {
-				newip.s = ip_addr2a(&msg->rcv.src_ip);
-				newip.len = strlen(newip.s);
+				newip.strip.s = ip_addr2a(&msg->rcv.src_ip);
+				newip.strip.len = strlen(newip.strip.s);
+				newip.pf = msg->rcv.src_ip.af;
 			}
 			/* XXX must compare address families in all addresses */
 			if (pf == AF_INET6) {
@@ -2611,10 +2619,10 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 				}
 			}
 
-			STR2IOVEC(newip, v[9]);
+			STR2IOVEC(newip.strip, v[9]);
 			STR2IOVEC(oldport, v[11]);
 #ifdef EXTRA_DEBUG
-			LM_DBG("STR2IOVEC(newip[%.*s], v[9])", newip.len, newip.s);
+			LM_DBG("STR2IOVEC(newip[%.*s], v[9])", newip.strip.len, newip.strip.s);
 			LM_DBG("STR2IOVEC(oldport[%.*s], v[11])", oldport.len, oldport.s);
 #endif
 			if (1 || media_multi) /* XXX netch: can't choose now*/
@@ -2728,26 +2736,46 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 				FORCE_RTP_PROXY_RET (-1);
 			}
 
-			pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET;
+			/*
+			 * if (argc == 1) {
+			 *      Assume AF in reply stays the same as one in
+			 *      the original request.
+			 * }
+			 */
+			if (argc == 2) {
+				/*
+				 * For historical reasons, if rtpproxy returns
+				 * bare address without AF flag, this means
+				 * IPv4.
+				 */
+				newip.pf = AF_INET;
+			} else if (argc >= 3) {
+				/*
+				 * When rtpproxy returns explicit address +
+				 * "AF" flag, use that.
+				 */
+				newip.pf = (argv[2][0] == '6') ? AF_INET6 : AF_INET;
+			}
 
 			if (isnulladdr(&oldip, pf)) {
-				if (pf1 == AF_INET6) {
-					newip.s = "::";
-					newip.len = 2;
+				if (newip.pf == AF_INET6) {
+					newip.strip.s = "::";
+					newip.strip.len = 2;
 				} else {
-					newip.s = "0.0.0.0";
-					newip.len = 7;
+					newip.strip.s = "0.0.0.0";
+					newip.strip.len = 7;
 				}
 			} else {
 				if (forcedIP) {
-					newip.s = str2;
-					newip.len = strlen(newip.s);
+					newip.strip.s = str2;
+					newip.strip.len = strlen(newip.strip.s);
 #ifdef EXTRA_DEBUG
-					LM_DBG("forcing IP='%.*s'\n", newip.len, newip.s);
+					LM_DBG("forcing IP='%.*s'\n", newip.strip.len,
+					    newip.strip.s);
 #endif
 				} else {
-					newip.s = (argc < 2) ? str2 : argv[1];
-					newip.len = strlen(newip.s);
+					newip.strip.s = (argc < 2) ? str2 : argv[1];
+					newip.strip.len = strlen(newip.strip.s);
 				}
 			}
 			/* marker to double check : newport goes: str -> int -> str ?!?! */
@@ -2796,7 +2824,7 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 				body1.s = sdp_stream->ice_attr->foundation.s - 12;
 				body1.len = bodylimit - body1.s;
 				if (insert_candidates(msg, sdp_stream->ice_attr->foundation.s - 12,
-						&newip, port, ice_candidate_priority_val.n) == -1) {
+						&newip.strip, port, ice_candidate_priority_val.n) == -1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
 			}
@@ -2813,7 +2841,7 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 #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) {
+				if (alter_mediaip(msg, &body1, &oldip, pf, &newip.strip, newip.pf, 0)==-1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
 				if (!c2p)
@@ -2828,7 +2856,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 #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) {
+				if (alter_mediaip(msg, &body1, &sdp_session->ip_addr,
+				    sdp_session->pf, &newip.strip, newip.pf, 0)==-1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
 				c1p_altered = 1;
@@ -2842,7 +2871,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 #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) {
+				if (alter_mediaip(msg, &body1, &sdp_session->o_ip_addr,
+				    sdp_session->o_pf, &newip.strip, newip.pf, 0)==-1) {
 					FORCE_RTP_PROXY_RET (-1);
 				}
 				o1p = 0;

+ 61 - 57
modules/sdpops/sdpops_mod.c

@@ -378,25 +378,21 @@ int sdp_remove_codecs_by_id(sip_msg_t* msg, str* codecs)
 	return 0;
 }
 
-// removes consecutive blocks of SDP lines that begin with script provided prefix
+/**
+ * @brief remove all SDP lines that begin with prefix
+ * @return -1 - error; 0 - no lines found ; 1..N - N lines deleted
+ */
 int sdp_remove_line_by_prefix(sip_msg_t* msg, str* prefix)
 {
 	str body = {NULL, 0};
-	str remove = {NULL, 0};
-	str line = {NULL, 0};
-	char* del_lump_start = NULL;
-	char* del_lump_end = NULL;
-	int del_lump_flag = 0;
-	struct lump *anchor;
-	char* p = NULL;
 
 	if(parse_sdp(msg) < 0) {
-		LM_ERR("Unable to parse sdp\n");
+		LM_ERR("Unable to parse SDP\n");
 		return -1;
 	}
 
 	if(msg->body == NULL) {
-		LM_DBG("No sdp body\n");
+		LM_DBG("No SDP body\n");
 		return -1;
 	}
 
@@ -413,69 +409,77 @@ int sdp_remove_line_by_prefix(sip_msg_t* msg, str* prefix)
 		return -1;
 	}
 
-	p = find_sdp_line(body.s, body.s+body.len, prefix->s[0]);
-	while (p != NULL)
+	char *ptr = NULL;
+	str line = {NULL, 0};
+	str remove = {NULL, 0};
+	int found = 0;
+	struct lump *anchor = NULL;
+
+	ptr = find_sdp_line(body.s, body.s + body.len, prefix->s[0]);
+	while (ptr)
 	{
-		if (sdp_locate_line(msg, p, &line) != 0)
+		if (sdp_locate_line(msg, ptr, &line) != 0)
 		{
-			LM_ERR("sdp_locate_line fail\n");
+			LM_ERR("sdp_locate_line() failed\n");
 			return -1;
 		}
 
-		//LM_DBG("line.s: %.*s\n", line.len, line.s);
-
-		if (extract_field(&line, &remove, *prefix) == 0)
-		{
-			//LM_DBG("line range: %d - %d\n", line.s - body.s, line.s + line.len - body.s);
-
-			if (del_lump_start == NULL)
-			{
-				del_lump_start = line.s;
-				del_lump_end = line.s + line.len;
-				//LM_DBG("first match, prepare new lump  (len=%d)\n", line.len);
-			}
-			else if ( p == del_lump_end )  // current line is same as del_lump_end
-			{
-				del_lump_end = line.s + line.len;
-				//LM_DBG("cont. match, made lump longer  (len+=%d)\n", line.len);
-			}
-
-			if (del_lump_end >= body.s + body.len)
-			{
-				//LM_DBG("end of buffer, delete lump\n");
-				del_lump_flag = 1;
-			}
-			//LM_DBG("lump pos: %d - %d\n", del_lump_start - body.s, del_lump_end - body.s);
-		}
-		else if ( del_lump_end != NULL)
+		if (body.s + body.len < line.s + prefix->len) // check if strncmp would run too far
 		{
-			//LM_DBG("line does not start with search pattern, delete current lump\n");
-			del_lump_flag = 1;
+			//LM_DBG("done searching, prefix string >%.*s< (%d) does not fit into remaining buffer space (%ld) \n", prefix->len, prefix->s, prefix->len, body.s + body.len - line.s);
+			break;
 		}
 
-		if (del_lump_flag && del_lump_start && del_lump_end)
+		if (strncmp(line.s, prefix->s, prefix->len ) == 0)
 		{
-			LM_DBG("del_lump range: %d - %d  len: %d\n", (int)(del_lump_start - body.s),
-					(int)(del_lump_end - body.s), (int)(del_lump_end - del_lump_start));
-
-			anchor = del_lump(msg, del_lump_start - msg->buf, del_lump_end - del_lump_start, HDR_OTHER_T);
-			if (anchor == NULL)
-			{
-				LM_ERR("failed to remove lump\n");
-				return -1;
+			//LM_DBG("current remove >%.*s< (%d)\n", remove.len, remove.s, remove.len);
+			if (!found) {
+				//LM_DBG("first match >%.*s< (%d)\n", line.len,line.s,line.len);
+				remove.s = line.s;
+				remove.len = line.len;
+			} else {
+				//LM_DBG("cont. match >%.*s< (%d)\n", line.len,line.s,line.len);
+				if (remove.s + remove.len == line.s) {
+					//LM_DBG("this match is right after previous match\n");
+					remove.len += line.len;
+				} else {
+					//LM_DBG("there is gap between this and previous match, remove now\n");
+					anchor = del_lump(msg, remove.s - msg->buf, remove.len, HDR_OTHER_T);
+					if (anchor==NULL)
+					{
+						LM_ERR("failed to remove lump\n");
+						return -1;
+					}
+					remove.s = line.s;
+					remove.len = line.len;
+				}
 			}
+			found++;
+			//LM_DBG("updated remove >%.*s< (%d)\n", remove.len, remove.s, remove.len);
 
-			del_lump_start = NULL;
-			del_lump_end = NULL;
-			del_lump_flag = 0;
-			//LM_DBG("succesful lump deletion\n");
 		}
+		ptr = find_next_sdp_line(ptr, body.s + body.len, prefix->s[0], NULL);
+	}
 
-		p = find_sdp_line(line.s + line.len, body.s + body.len, prefix->s[0]);
+	if (found) {
+		//LM_DBG("remove >%.*s< (%d)\n", remove.len, remove.s, remove.len);
+		anchor = del_lump(msg, remove.s - msg->buf, remove.len, HDR_OTHER_T);
+		if (anchor==NULL)
+		{
+			LM_ERR("failed to remove lump\n");
+			return -1;
+		}
+		return found;
 	}
+
+	LM_DBG("no match\n");
 	return 0;
 }
 
+/**
+ * removes all SDP lines that begin with script provided prefix
+ * @return -1 - error; 1 - found
+ */
 static int w_sdp_remove_line_by_prefix(sip_msg_t* msg, char* prefix, char* bar)
 {
 	str prfx = {NULL, 0};
@@ -493,7 +497,7 @@ static int w_sdp_remove_line_by_prefix(sip_msg_t* msg, char* prefix, char* bar)
 	}
 	LM_DBG("Removing SDP lines with prefix: %.*s\n", prfx.len, prfx.s);
 
-	if(sdp_remove_line_by_prefix(msg, &prfx)<0)
+	if ( sdp_remove_line_by_prefix(msg, &prfx) < 0)
 		return -1;
 	return 1;
 }

+ 8 - 4
modules/tls/tls_server.c

@@ -186,7 +186,8 @@ static int tls_complete_init(struct tcp_connection* c)
 
 	if (LOW_MEM_NEW_CONNECTION_TEST()){
 		ERR("tls: ssl bug #1491 workaround: not enough memory for safe"
-				" operation: %lu\n", shm_available());
+				" operation: shm=%lu threshold1=%d\n", shm_available_safe(),
+				cfg_get(tls, tls_cfg, low_mem_threshold1));
 		goto error2;
 	}
 	     /* Get current TLS configuration and increase reference
@@ -294,7 +295,8 @@ static int tls_fix_connection_unsafe(struct tcp_connection* c)
 		}
 	}else if (unlikely(LOW_MEM_CONNECTED_TEST())){
 		ERR("tls: ssl bug #1491 workaround: not enough memory for safe"
-				" operation: %lu\n", shm_available());
+				" operation: shm=%lu threshold2=%d\n", shm_available_safe(),
+				cfg_get(tls, tls_cfg, low_mem_threshold2));
 		return -1;
 	}
 	return 0;
@@ -324,7 +326,8 @@ static int tls_fix_connection(struct tcp_connection* c)
 	}
 	if (unlikely(LOW_MEM_CONNECTED_TEST())){
 		ERR("tls: ssl bug #1491 workaround: not enough memory for safe"
-				" operation: %lu\n", shm_available());
+				" operation: shm=%lu threshold2=%d\n", shm_available_safe(),
+				cfg_get(tls, tls_cfg, low_mem_threshold2));
 		return -1;
 	}
 	return 0;
@@ -527,7 +530,8 @@ static int tls_shutdown(struct tcp_connection *c)
 		return 0;
 	if (unlikely(LOW_MEM_CONNECTED_TEST())){
 		ERR("tls: ssl bug #1491 workaround: not enough memory for safe"
-				" operation: %lu\n", shm_available());
+				" operation: shm=%lu threshold2=%d\n", shm_available_safe(),
+				cfg_get(tls, tls_cfg, low_mem_threshold2));
 		goto err;
 	}
 	

+ 18 - 0
test/unit/60-message-sdp0.sip

@@ -0,0 +1,18 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Info: sdpops remove_line_by_prefix() test0 - invalid SDP
+
+v=0
+oo=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=rtpmap:100 X-NSE/8000
+

+ 18 - 0
test/unit/60-message-sdp1.sip

@@ -0,0 +1,18 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Info: sdpops remove_line_by_prefix() test1 - no matching line
+
+v=0
+o=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=rtpmap:100 X-NSE/8000
+

+ 19 - 0
test/unit/60-message-sdp2.sip

@@ -0,0 +1,19 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Info: sdpops remove_line_by_prefix() test2 - single matching line
+
+v=0
+o=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=X-cap: 1 audio RTP/AVP 100
+a=rtpmap:100 X-NSE/8000
+

+ 19 - 0
test/unit/60-message-sdp3.sip

@@ -0,0 +1,19 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Info: sdpops remove_line_by_prefix() test3 - single matching line at the end of buffer
+
+v=0
+o=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=rtpmap:100 X-NSE/8000
+a=X-cap: 1 audio RTP/AVP 100
+

+ 20 - 0
test/unit/60-message-sdp4.sip

@@ -0,0 +1,20 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Info: sdpops remove_line_by_prefix() test4 - dual matching lines
+
+v=0
+o=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=rtpmap:100 X-NSE/8000
+a=X-cap1: 1 audio RTP/AVP 100
+a=X-cap2: 1 audio RTP/AVP 100
+

+ 20 - 0
test/unit/60-message-sdp5.sip

@@ -0,0 +1,20 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Info: sdpops remove_line_by_prefix() test5 - dual matching lines with gap
+
+v=0
+o=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=X-cap1: 1 audio RTP/AVP 100
+a=rtpmap:100 X-NSE/8000
+a=X-cap2: 1 audio RTP/AVP 100
+

+ 20 - 0
test/unit/60-message-sdp6.sip

@@ -0,0 +1,20 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Info: sdpops remove_line_by_prefix() test6 - matching line + end of buffer
+
+v=0
+o=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=rtpmap:100 X-NSE/8000
+a=X-cap1: 1 audio RTP/AVP 100
+a=X
+

+ 19 - 0
test/unit/60-message-sdp7.sip

@@ -0,0 +1,19 @@
+MESSAGE sip:[email protected] SIP/2.0
+From: sip:[email protected];tag=45dfdf49
+To: sip:[email protected]
+Call-ID: 1172299593a
+CSeq: 1 MESSAGE
+Content-Type: application/sdp
+Max-Forwards: 2
+X-Case: 60-test7
+X-Info: sdpops remove_line_by_prefix() test7 - change s -line
+
+v=0
+o=- 370010 0 IN IP4 192.168.13.31
+s=MGW
+c=IN IP4 192.168.13.31
+t=0 0
+m=audio 22616 RTP/AVP 0 96 100
+a=rtpmap:96 telephone-event/8000
+a=rtpmap:100 X-NSE/8000
+

+ 41 - 0
test/unit/60.cfg

@@ -0,0 +1,41 @@
+# ----------- global configuration parameters ------------------------
+debug=2
+fork=yes
+log_stderror=no
+children=1
+disable_tcp=yes
+listen=udp:127.0.0.1:5060
+auto_aliases=no
+alias=example.invalid
+# ------------------ module loading ----------------------------------
+loadpath "../../modules/"
+
+loadmodule "tm.so"
+loadmodule "sl.so"
+loadmodule "pv.so"
+loadmodule "textops.so"
+loadmodule "textopsx.so"
+loadmodule "sdpops.so"
+
+route {
+	if ( is_present_hf("X-Case") ) {
+		if ($hdr(X-Case) == '60-test7') {
+			sdp_remove_line_by_prefix("s=");
+			msg_apply_changes();
+			set_reply_body($rb,"application/sdp");
+			sl_send_reply(200,"OK");
+			exit;
+		}
+	} else {
+		$var(rc) = sdp_remove_line_by_prefix("a=X-cap");
+		if ( $var(rc) < 0 ) {
+			sl_send_reply(500,"Some error");
+			exit;
+		}
+		msg_apply_changes();
+		set_reply_body($rb,"application/sdp");
+		sl_send_reply(200,"OK");
+		exit;
+	}
+}
+

+ 75 - 0
test/unit/60.sh

@@ -0,0 +1,75 @@
+#!/bin/sh
+# checks sdpops module function remove_line_by_prefix()
+#
+# Copyright (C) 2016 [email protected]
+#
+# This file is part of Kamailio, a free SIP server.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+. include/common
+. include/require.sh
+
+CFG=60.cfg
+TMPFILE=$(mktemp -t kamailio-test.XXXXXXXXXX)
+
+if ! (check_sipsak && check_kamailio && check_module "sdpops"); then
+	exit 0
+fi
+
+${BIN} -w . -f ${CFG} > /dev/null
+ret=$?
+
+sleep 1
+if [ "${ret}" -ne 0 ] ; then
+	echo "start fail"
+	${KILL}
+	exit ${ret}
+fi
+
+# Borken SDP should give 500 response
+sipsak -f 60-message-sdp0.sip -L -s sip:127.0.0.1 -v > ${TMPFILE}
+ret=$?
+if [ "${ret}" -eq 1 ] ; then
+	ret=0
+else
+	echo "invalid SDP not rejected"
+	ret=1
+	exit ${ret}
+fi
+
+# Kamailio replies back with modified SDP
+for i in 1 2 3 4 5 6 7; do
+	FILE="60-message-sdp${i}.sip"
+	TOTALBEFORE=$(awk '/^v=0/,/^$/ {total++; if ($0 ~ /^a=X-cap/ ) { prefix++;} else { other++} } END {if (prefix) {print other " + " prefix} else { print other " + 0"} }' ${FILE})
+	OTHERBEFORE=$(echo ${TOTALBEFORE}|cut -d+ -f1)
+
+	sipsak -f ${FILE} -L -s sip:127.0.0.1 -v > ${TMPFILE}
+	ret=$?
+	if [ "${ret}" -eq 0 ] ; then
+		TOTALAFTER=$(awk '/^v=0/,/^$/ {total++; if ($0 ~ /^a=X-cap/ ) { prefix++;} else { other++} } END {if (prefix) {print other " + " prefix} else { print other " + 0"} }' ${TMPFILE})
+		OTHERAFTER=$(echo ${TOTALBEFORE}|cut -d+ -f1)
+		PREFIXAFTER=$(echo ${TOTALAFTER}|cut -d+ -f2)
+		if [ ${PREFIXAFTER} -eq 0 ] && [ ${OTHERBEFORE} -eq ${OTHERAFTER} ]; then
+			ret=0
+		else
+			ret=1
+			echo "found ${PREFIXAFTER} lines that should be deleted (${FILE})"
+		fi
+	fi
+done
+
+${KILL}
+
+exit ${ret}
+

+ 65 - 0
test/unit/include/require.sh

@@ -0,0 +1,65 @@
+# Copyright (C) 2008 1&1 Internet AG
+# Copyright (C) 2016 Mikko Lehto
+#
+# This file is part of kamailio, a free SIP server.
+#
+# kamailio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version
+#
+# kamailio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+. include/common
+
+check_kamailio() {
+	if ! (test -e $BIN) ; then
+		echo "kamailio not found, not run"
+		return 1
+	fi;
+	return 0
+}
+
+check_module() {
+	if [ $# -ne 1 ]; then
+		echo "wrong number of params in check_module()"
+		return 1
+	fi
+
+	if ! (test -e $SRC_DIR/modules/$1/$1.so) ; then
+		echo "$SRC_DIR/modules/$1/$1.so not found, not run"
+		return 1
+	fi;
+	return 0
+}
+
+check_netcat() {
+	if ! ( which nc > /dev/null ); then
+		echo "netcat not found, not run"
+		return 1
+	fi;
+	return 0
+}
+
+check_sipp() {
+	if ! ( which sipp > /dev/null ); then
+		echo "sipp not found, not run"
+		return 1
+	fi;
+	return 0
+}
+
+check_sipsak() {
+	if ! ( which sipsak > /dev/null ); then
+		echo "sipsak not found, not run"
+		return 1
+	fi;
+	return 0
+}