[asterisk-commits] mmichelson: branch 1.6.0 r197615 - in /branches/1.6.0: ./ channels/ include/a...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu May 28 10:34:58 CDT 2009


Author: mmichelson
Date: Thu May 28 10:34:48 2009
New Revision: 197615

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=197615
Log:
Merged revisions 197606 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

................
  r197606 | mmichelson | 2009-05-28 10:32:19 -0500 (Thu, 28 May 2009) | 22 lines
  
  Recorded merge of revisions 197588 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r197588 | mmichelson | 2009-05-28 10:27:49 -0500 (Thu, 28 May 2009) | 16 lines
    
    Allow for media to arrive from an alternate source when responding to a reinvite with 491.
    
    When we receive a SIP reinvite, it is possible that we may not be able to process the
    reinvite immediately since we have also sent a reinvite out ourselves. The problem is
    that whoever sent us the reinvite may have also sent a reinvite out to another party,
    and that reinvite may have succeeded.
    
    As a result, even though we are not going to accept the reinvite we just received, it
    is important for us to not have problems if we suddenly start receiving RTP from a new
    source. The fix for this is to grab the media source information from the SDP of the
    reinvite that we receive. This information is passed to the RTP layer so that it will
    know about the alternate source for media.
    
    Review: https://reviewboard.asterisk.org/r/252
  ........
................

Modified:
    branches/1.6.0/   (props changed)
    branches/1.6.0/channels/chan_sip.c
    branches/1.6.0/include/asterisk/rtp.h
    branches/1.6.0/main/rtp.c

Propchange: branches/1.6.0/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.0/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.0/channels/chan_sip.c?view=diff&rev=197615&r1=197614&r2=197615
==============================================================================
--- branches/1.6.0/channels/chan_sip.c (original)
+++ branches/1.6.0/channels/chan_sip.c Thu May 28 10:34:48 2009
@@ -6573,6 +6573,63 @@
 		return TRUE;
 	}
 	return FALSE;
+}
+
+enum media_type {
+	SDP_AUDIO,
+	SDP_VIDEO,
+};
+
+static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct sockaddr_in *sin)
+{
+	const char *m;
+	const char *c;
+	int miterator = req->sdp_start;
+	int citerator = req->sdp_start;
+	int x = 0;
+	int numberofports;
+	int len;
+	char host[258] = ""; /*Initialize to empty so we will know if we have any input */
+	struct ast_hostent audiohp;
+	struct hostent *hp;
+
+	c = get_sdp_iterate(&citerator, req, "c");
+	if (sscanf(c, "IN IP4 %256s", host) != 1) {
+		ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
+		/* Continue since there may be a valid host in a c= line specific to the audio stream */
+	}
+	/* We only want the m and c lines for audio */
+	while ((m = get_sdp_iterate(&miterator, req, "m"))) {
+		if ((media == SDP_AUDIO && ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+		    (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1 && len > 0))) ||
+			(media == SDP_VIDEO && ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+		    (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1 && len > 0)))) {
+			/* See if there's a c= line for this media stream.
+			 * XXX There is no guarantee that we'll be grabbing the c= line for this
+			 * particular media stream here. However, this is the same logic used in process_sdp.
+			 */
+			c = get_sdp_iterate(&citerator, req, "c");
+			if (!ast_strlen_zero(c)) {
+				sscanf(c, "IN IP4 %256s", host);
+			}
+			break;
+		}
+	}
+
+	if (ast_strlen_zero(host) || x == 0) {
+		ast_log(LOG_WARNING, "Failed to read an alternate host or port in SDP. Expect %s problems\n", media == SDP_AUDIO ? "audio" : "video");
+		return -1;
+	}
+
+	hp = ast_gethostbyname(host, &audiohp);
+	if (!hp) {
+		ast_log(LOG_WARNING, "Could not look up IP address of alternate hostname. Expect %s problems\n", media == SDP_AUDIO? "audio" : "video");
+		return -1;
+	}
+
+	memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
+	sin->sin_port = htons(x);
+	return 0;
 }
 
 /*! \brief Process SIP SDP offer, select formats and activate RTP channels
@@ -17158,6 +17215,21 @@
 		} else {
 			/* We already have a pending invite. Sorry. You are on hold. */
 			p->glareinvite = seqno;
+			if (p->rtp && find_sdp(req)) {
+				struct sockaddr_in sin;
+				if (get_ip_and_port_from_sdp(req, SDP_AUDIO, &sin)) {
+					ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Audio may not work properly on this call.\n");
+				} else {
+					ast_rtp_set_alt_peer(p->rtp, &sin);
+				}
+				if (p->vrtp) {
+					if (get_ip_and_port_from_sdp(req, SDP_VIDEO, &sin)) {
+						ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Video may not work properly on this call.\n");
+					} else {
+						ast_rtp_set_alt_peer(p->vrtp, &sin);
+					}
+				}
+			}
 			transmit_response_reliable(p, "491 Request Pending", req);
 			ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
 			/* Don't destroy dialog here */

Modified: branches/1.6.0/include/asterisk/rtp.h
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.0/include/asterisk/rtp.h?view=diff&rev=197615&r1=197614&r2=197615
==============================================================================
--- branches/1.6.0/include/asterisk/rtp.h (original)
+++ branches/1.6.0/include/asterisk/rtp.h Thu May 28 10:34:48 2009
@@ -133,6 +133,23 @@
 
 void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
 
+/*! 
+ * \since 1.4.26
+ * \brief set potential alternate source for RTP media
+ *
+ * This function may be used to give the RTP stack a hint that there is a potential
+ * second source of media. One case where this is used is when the SIP stack receives
+ * a REINVITE to which it will be replying with a 491. In such a scenario, the IP and
+ * port information in the SDP of that REINVITE lets us know that we may receive media
+ * from that source/those sources even though the SIP transaction was unable to be completed
+ * successfully
+ *
+ * \param rtp The RTP structure we wish to set up an alternate host/port on
+ * \param alt The address information for the alternate media source
+ * \retval void
+ */
+void ast_rtp_set_alt_peer(struct ast_rtp *rtp, struct sockaddr_in *alt);
+
 /* Copies from rtp to them and returns 1 if there was a change or 0 if it was already the same */
 int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
 

Modified: branches/1.6.0/main/rtp.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.0/main/rtp.c?view=diff&rev=197615&r1=197614&r2=197615
==============================================================================
--- branches/1.6.0/main/rtp.c (original)
+++ branches/1.6.0/main/rtp.c Thu May 28 10:34:48 2009
@@ -150,6 +150,7 @@
 	unsigned int flags;
 	struct sockaddr_in us;		/*!< Socket representation of the local endpoint. */
 	struct sockaddr_in them;	/*!< Socket representation of the remote endpoint. */
+	struct sockaddr_in altthem;	/*!< Alternate source of remote media */
 	struct timeval rxcore;
 	struct timeval txcore;
 	double drxcore;                 /*!< The double representation of the first received packet */
@@ -214,6 +215,7 @@
 	int s;				/*!< Socket */
 	struct sockaddr_in us;		/*!< Socket representation of the local endpoint. */
 	struct sockaddr_in them;	/*!< Socket representation of the remote endpoint. */
+	struct sockaddr_in altthem;	/*!< Alternate source for RTCP */
 	unsigned int soc;		/*!< What they told us */
 	unsigned int spc;		/*!< What they told us */
 	unsigned int themrxlsr;		/*!< The middle 32 bits of the NTP timestamp in the last received SR*/
@@ -1128,8 +1130,10 @@
 	
 	if (rtp->nat) {
 		/* Send to whoever sent to us */
-		if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
-		    (rtp->rtcp->them.sin_port != sin.sin_port)) {
+		if (((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
+		    (rtp->rtcp->them.sin_port != sin.sin_port)) && 
+		    ((rtp->rtcp->altthem.sin_addr.s_addr != sin.sin_addr.s_addr) || 
+		    (rtp->rtcp->altthem.sin_port != sin.sin_port))) {
 			memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
 			if (option_debug || rtpdebug)
 				ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
@@ -1498,8 +1502,10 @@
 
 	/* Send to whoever send to us if NAT is turned on */
 	if (rtp->nat) {
-		if ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
-		    (rtp->them.sin_port != sin.sin_port)) {
+		if (((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
+		    (rtp->them.sin_port != sin.sin_port)) && 
+		    ((rtp->altthem.sin_addr.s_addr != sin.sin_addr.s_addr) ||
+		    (rtp->altthem.sin_port != sin.sin_port))) {
 			rtp->them = sin;
 			if (rtp->rtcp) {
 				memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
@@ -2397,6 +2403,16 @@
 	/* If strict RTP protection is enabled switch back to the learn state so we don't drop packets from above */
 	if (strictrtp)
 		rtp->strict_rtp_state = STRICT_RTP_LEARN;
+}
+
+void ast_rtp_set_alt_peer(struct ast_rtp *rtp, struct sockaddr_in *alt)
+{
+	rtp->altthem.sin_port = alt->sin_port;
+	rtp->altthem.sin_addr = alt->sin_addr;
+	if (rtp->rtcp) {
+		rtp->rtcp->altthem.sin_port = htons(ntohs(alt->sin_port) + 1);
+		rtp->rtcp->altthem.sin_addr = alt->sin_addr;
+	}
 }
 
 int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them)




More information about the asterisk-commits mailing list