You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
asterisk/patches/chan_sip_reinvite_197588.patch

186 lines
7.3 KiB

Index: include/asterisk/rtp.h
===================================================================
--- include/asterisk/rtp.h (revision 197587)
+++ include/asterisk/rtp.h (revision 197588)
@@ -127,6 +127,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);
Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c (revision 197587)
+++ channels/chan_sip.c (revision 197588)
@@ -5111,6 +5111,63 @@
return;
}
+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
If offer is rejected, we will not change any properties of the call
Return 0 on success, a negative value on errors.
@@ -14459,6 +14516,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);
if (option_debug)
ast_log(LOG_DEBUG, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
Index: main/rtp.c
===================================================================
--- main/rtp.c (revision 197587)
+++ main/rtp.c (revision 197588)
@@ -151,6 +151,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 */
@@ -209,6 +210,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*/
@@ -899,11 +901,13 @@
}
packetwords = res / 4;
-
+
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_log(LOG_DEBUG, "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));
@@ -1203,8 +1207,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));
@@ -2061,6 +2067,16 @@
rtp->rxseqno = 0;
}
+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)
{
if ((them->sin_family != AF_INET) ||