mirror of https://github.com/sipwise/asterisk.git
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.
186 lines
7.3 KiB
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) ||
|