[asterisk-commits] kmoore: trunk r369028 - in /trunk/channels: chan_sip.c sip/include/sip.h
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jun 15 12:13:24 CDT 2012
Author: kmoore
Date: Fri Jun 15 12:13:20 2012
New Revision: 369028
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=369028
Log:
Allow chan_sip to decline unwanted media streams
This change replaces the static array of four representable media
streams with an AST_LIST so that chan_sip can keep track of offered
media streams. This allows chan_sip to deal with offers containing
multiple same-type streams and many other situations without rejecting
the SDP offer in its entirety, yet still generating a valid response.
This also covers cases where Asterisk can not comprehend the offer if
it is in the correct format.
Previously, chan_sip would reject SDP offers or entirely ignore
individual stream offers in an effort to be more compatible which
would often result in invalid SDP responses.
Review: https://reviewboard.asterisk.org/r/1988/
Modified:
trunk/channels/chan_sip.c
trunk/channels/sip/include/sip.h
Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=369028&r1=369027&r2=369028
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Fri Jun 15 12:13:20 2012
@@ -5850,6 +5850,16 @@
ast_free(mwi);
}
+/*! \brief Destroy SDP media offer list */
+static void offered_media_list_destroy(struct sip_pvt *p)
+{
+ struct offered_media *offer;
+ while ((offer = AST_LIST_REMOVE_HEAD(&p->offered_media, next))) {
+ ast_free(offer->decline_m_line);
+ ast_free(offer);
+ }
+}
+
/*! \brief Execute destruction of SIP dialog structure, release memory */
void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
{
@@ -5952,6 +5962,8 @@
while ((req = AST_LIST_REMOVE_HEAD(&p->request_queue, next))) {
ast_free(req);
}
+
+ offered_media_list_destroy(p);
if (p->chanvars) {
ast_variables_destroy(p->chanvars);
@@ -8033,6 +8045,7 @@
ast_string_field_set(p, engine, default_engine);
AST_LIST_HEAD_INIT_NOLOCK(&p->request_queue);
+ AST_LIST_HEAD_INIT_NOLOCK(&p->offered_media);
/* Add to active dialog list */
@@ -9119,6 +9132,18 @@
return ast_sockaddr_isnull(addr) || ast_sockaddr_is_any(addr);
}
+/*! \brief Check the media stream list to see if the given type already exists */
+static int has_media_stream(struct sip_pvt *p, enum media_type m)
+{
+ struct offered_media *offer = NULL;
+ AST_LIST_TRAVERSE(&p->offered_media, offer, next) {
+ if (m == offer->type) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*! \brief Process SIP SDP offer, select formats and activate media channels
If offer is rejected, we will not change any properties of the call
Return 0 on success, a negative value on errors.
@@ -9139,6 +9164,7 @@
const char *m = NULL; /* SDP media offer */
const char *nextm = NULL;
int len = -1;
+ struct offered_media *offer;
/* Host information */
struct ast_sockaddr sessionsa;
@@ -9178,7 +9204,6 @@
int sendonly = -1;
int vsendonly = -1;
int numberofports;
- int numberofmediastreams = 0;
int last_rtpmap_codec = 0;
int red_data_pt[10]; /* For T.140 RED */
int red_num_gen = 0; /* For T.140 RED */
@@ -9209,7 +9234,7 @@
/* Update our last rtprx when we receive an SDP, too */
p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
- memset(p->offered_media, 0, sizeof(p->offered_media));
+ offered_media_list_destroy(p);
/* Scan for the first media stream (m=) line to limit scanning of globals */
nextm = get_sdp_iterate(&next, req, "m");
@@ -9281,10 +9306,29 @@
iterator = next;
nextm = get_sdp_iterate(&next, req, "m");
+ if (!(offer = ast_calloc(1, sizeof(*offer)))) {
+ ast_log(LOG_WARNING, "Failed to allocate memory for SDP offer list\n");
+ res = -1;
+ goto process_sdp_cleanup;
+ }
+ AST_LIST_INSERT_TAIL(&p->offered_media, offer, next);
+ offer->type = SDP_UNKNOWN;
+
/* Check for 'audio' media offer */
if (strncmp(m, "audio ", 6) == 0) {
if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) ||
(sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) {
+ codecs = m + len;
+ /* produce zero-port m-line since it may be needed later
+ * length is "m=audio 0 RTP/" + protocol + " " + codecs + "\0" */
+ if (!(offer->decline_m_line = ast_malloc(14 + strlen(protocol) + 1 + strlen(codecs) + 1))) {
+ ast_log(LOG_WARNING, "Failed to allocate memory for SDP offer declination\n");
+ res = -1;
+ goto process_sdp_cleanup;
+ }
+ /* guaranteed to be exactly the right length */
+ sprintf(offer->decline_m_line, "m=audio 0 RTP/%s %s", protocol, codecs);
+
if (x == 0) {
ast_log(LOG_WARNING, "Ignoring audio media offer because port number is zero\n");
continue;
@@ -9299,23 +9343,19 @@
secure_audio = 1;
} else if (strcmp(protocol, "AVP")) {
ast_log(LOG_WARNING, "Unknown RTP profile in audio offer: %s\n", m);
- res = -1;
- goto process_sdp_cleanup;
+ continue;
}
- if (p->offered_media[SDP_AUDIO].order_offered) {
- ast_log(LOG_WARNING, "Rejecting non-primary audio stream: %s\n", m);
- res = -1;
- goto process_sdp_cleanup;
+ if (has_media_stream(p, SDP_AUDIO)) {
+ ast_log(LOG_WARNING, "Declining non-primary audio stream: %s\n", m);
+ continue;
}
audio = TRUE;
- p->offered_media[SDP_AUDIO].order_offered = ++numberofmediastreams;
+ offer->type = SDP_AUDIO;
portno = x;
/* Scan through the RTP payload types specified in a "m=" line: */
- codecs = m + len;
- ast_copy_string(p->offered_media[SDP_AUDIO].codecs, codecs, sizeof(p->offered_media[SDP_AUDIO].codecs));
for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Invalid syntax in RTP audio format list: %s\n", codecs);
@@ -9338,38 +9378,45 @@
else if (strncmp(m, "video ", 6) == 0) {
if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) ||
(sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) {
+ codecs = m + len;
+ /* produce zero-port m-line since it may be needed later
+ * length is "m=video 0 RTP/" + protocol + " " + codecs + "\0" */
+ if (!(offer->decline_m_line = ast_malloc(14 + strlen(protocol) + 1 + strlen(codecs) + 1))) {
+ ast_log(LOG_WARNING, "Failed to allocate memory for SDP offer declination\n");
+ res = -1;
+ goto process_sdp_cleanup;
+ }
+ /* guaranteed to be exactly the right length */
+ sprintf(offer->decline_m_line, "m=video 0 RTP/%s %s", protocol, codecs);
+
if (x == 0) {
- ast_log(LOG_WARNING, "Ignoring video media offer because port number is zero\n");
+ ast_log(LOG_WARNING, "Ignoring video stream offer because port number is zero\n");
continue;
}
/* Check number of ports offered for stream */
if (numberofports > 1) {
- ast_log(LOG_WARNING, "%d ports offered for video media, not supported by Asterisk. Will try anyway...\n", numberofports);
+ ast_log(LOG_WARNING, "%d ports offered for video stream, not supported by Asterisk. Will try anyway...\n", numberofports);
}
if (!strcmp(protocol, "SAVP")) {
secure_video = 1;
} else if (strcmp(protocol, "AVP")) {
ast_log(LOG_WARNING, "Unknown RTP profile in video offer: %s\n", m);
- res = -1;
- goto process_sdp_cleanup;
+ continue;
}
- if (p->offered_media[SDP_VIDEO].order_offered) {
- ast_log(LOG_WARNING, "Rejecting non-primary video stream: %s\n", m);
- res = -1;
- goto process_sdp_cleanup;
+ if (has_media_stream(p, SDP_VIDEO)) {
+ ast_log(LOG_WARNING, "Declining non-primary video stream: %s\n", m);
+ continue;
}
video = TRUE;
p->novideo = FALSE;
- p->offered_media[SDP_VIDEO].order_offered = ++numberofmediastreams;
+ offer->type = SDP_VIDEO;
vportno = x;
/* Scan through the RTP payload types specified in a "m=" line: */
- codecs = m + len;
- ast_copy_string(p->offered_media[SDP_VIDEO].codecs, codecs, sizeof(p->offered_media[SDP_VIDEO].codecs));
for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs);
@@ -9391,30 +9438,38 @@
else if (strncmp(m, "text ", 5) == 0) {
if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
(sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0)) {
- if (x == 0) {
- ast_log(LOG_WARNING, "Ignoring text media offer because port number is zero\n");
- continue;
- }
-
- /* Check number of ports offered for stream */
- if (numberofports > 1) {
- ast_log(LOG_WARNING, "%d ports offered for text media, not supported by Asterisk. Will try anyway...\n", numberofports);
- }
-
- if (p->offered_media[SDP_TEXT].order_offered) {
- ast_log(LOG_WARNING, "Rejecting non-primary text stream: %s\n", m);
+ codecs = m + len;
+ /* produce zero-port m-line since it may be needed later
+ * length is "m=text 0 RTP/AVP " + codecs + "\0" */
+ if (!(offer->decline_m_line = ast_malloc(17 + strlen(codecs) + 1))) {
+ ast_log(LOG_WARNING, "Failed to allocate memory for SDP offer declination\n");
res = -1;
goto process_sdp_cleanup;
}
+ /* guaranteed to be exactly the right length */
+ sprintf(offer->decline_m_line, "m=text 0 RTP/AVP %s", codecs);
+
+ if (x == 0) {
+ ast_log(LOG_WARNING, "Ignoring text stream offer because port number is zero\n");
+ continue;
+ }
+
+ /* Check number of ports offered for stream */
+ if (numberofports > 1) {
+ ast_log(LOG_WARNING, "%d ports offered for text stream, not supported by Asterisk. Will try anyway...\n", numberofports);
+ }
+
+ if (has_media_stream(p, SDP_TEXT)) {
+ ast_log(LOG_WARNING, "Declining non-primary text stream: %s\n", m);
+ continue;
+ }
text = TRUE;
p->notext = FALSE;
- p->offered_media[SDP_TEXT].order_offered = ++numberofmediastreams;
+ offer->type = SDP_TEXT;
tportno = x;
/* Scan through the RTP payload types specified in a "m=" line: */
- codecs = m + len;
- ast_copy_string(p->offered_media[SDP_TEXT].codecs, codecs, sizeof(p->offered_media[SDP_TEXT].codecs));
for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs);
@@ -9427,7 +9482,7 @@
ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec);
}
} else {
- ast_log(LOG_WARNING, "Rejecting text media offer due to invalid or unsupported syntax: %s\n", m);
+ ast_log(LOG_WARNING, "Rejecting text stream offer due to invalid or unsupported syntax: %s\n", m);
res = -1;
goto process_sdp_cleanup;
}
@@ -9436,20 +9491,29 @@
else if (strncmp(m, "image ", 6) == 0) {
if (((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0) ||
(sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0))) {
- if (x == 0) {
- ast_log(LOG_WARNING, "Ignoring image media offer because port number is zero\n");
- continue;
- }
-
- if (initialize_udptl(p)) {
+ /* produce zero-port m-line since it may be needed later
+ * length is "m=image 0 UDPTL t38" + "\0" */
+ if (!(offer->decline_m_line = ast_malloc(20))) {
+ ast_log(LOG_WARNING, "Failed to allocate memory for SDP offer declination\n");
res = -1;
goto process_sdp_cleanup;
}
-
- if (p->offered_media[SDP_IMAGE].order_offered) {
- ast_log(LOG_WARNING, "Rejecting non-primary image stream: %s\n", m);
- res = -1;
- goto process_sdp_cleanup;
+ /* guaranteed to be exactly the right length */
+ strcpy(offer->decline_m_line, "m=image 0 UDPTL t38");
+
+ if (x == 0) {
+ ast_log(LOG_WARNING, "Ignoring image stream offer because port number is zero\n");
+ continue;
+ }
+
+ if (initialize_udptl(p)) {
+ ast_log(LOG_WARNING, "Failed to initialize UDPTL, declining image stream\n");
+ continue;
+ }
+
+ if (has_media_stream(p, SDP_IMAGE)) {
+ ast_log(LOG_WARNING, "Declining non-primary image stream: %s\n", m);
+ continue;
}
image = TRUE;
@@ -9457,7 +9521,7 @@
ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
}
- p->offered_media[SDP_IMAGE].order_offered = ++numberofmediastreams;
+ offer->type = SDP_IMAGE;
udptlportno = x;
if (p->t38.state != T38_ENABLED) {
@@ -9473,9 +9537,26 @@
goto process_sdp_cleanup;
}
} else {
- ast_log(LOG_WARNING, "Unsupported top-level media type in offer: %s\n", m);
- res = -1;
- goto process_sdp_cleanup;
+ char type[20] = {0,};
+ char *typelen = strchr(m, ' ');
+ if (typelen && typelen - m < 20 &&
+ ((sscanf(m, "%s %30u/%30u %n", type, &x, &numberofports, &len) == 2 && len > 0) ||
+ (sscanf(m, "%s %30u %n", type, &x, &len) == 1 && len > 0))) {
+ /* produce zero-port m-line since it may be needed later
+ * length is "m=" + type + " 0 " + remainder + "\0" */
+ if (!(offer->decline_m_line = ast_malloc(2 + strlen(type) + 3 + strlen(m + len) + 1))) {
+ ast_log(LOG_WARNING, "Failed to allocate memory for SDP offer declination\n");
+ res = -1;
+ goto process_sdp_cleanup;
+ }
+ /* guaranteed to be long enough */
+ sprintf(offer->decline_m_line, "m=%s 0 %s", type, m + len);
+ continue;
+ } else {
+ ast_log(LOG_WARNING, "Unsupported top-level media type in offer: %s\n", m);
+ res = -1;
+ goto process_sdp_cleanup;
+ }
}
/* Media stream specific parameters */
@@ -9852,6 +9933,9 @@
}
process_sdp_cleanup:
+ if (res) {
+ offered_media_list_destroy(p);
+ }
ast_format_cap_destroy(peercapability);
ast_format_cap_destroy(vpeercapability);
ast_format_cap_destroy(tpeercapability);
@@ -11817,6 +11901,7 @@
struct ast_sockaddr udptldest = { {0,} };
/* SDP fields */
+ struct offered_media *offer;
char *version = "v=0\r\n"; /* Protocol version */
char subject[256]; /* Subject of the session */
char owner[256]; /* Session owner/creator */
@@ -11848,7 +11933,6 @@
char codecbuf[SIPBUFSIZE];
char buf[SIPBUFSIZE];
- char dummy_answer[256];
/* Set the SDP session name */
snprintf(subject, sizeof(subject), "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession);
@@ -12153,14 +12237,10 @@
}
add_content(resp, session_time);
/* if this is a response to an invite, order our offers properly */
- if (p->offered_media[SDP_AUDIO].order_offered ||
- p->offered_media[SDP_VIDEO].order_offered ||
- p->offered_media[SDP_TEXT].order_offered ||
- p->offered_media[SDP_IMAGE].order_offered) {
- int i;
- /* we have up to 3 streams as limited by process_sdp */
- for (i = 1; i <= 3; i++) {
- if (p->offered_media[SDP_AUDIO].order_offered == i) {
+ if (!AST_LIST_EMPTY(&p->offered_media)) {
+ AST_LIST_TRAVERSE(&p->offered_media, offer, next) {
+ switch (offer->type) {
+ case SDP_AUDIO:
if (needaudio) {
add_content(resp, m_audio->str);
add_content(resp, a_audio->str);
@@ -12169,10 +12249,10 @@
add_content(resp, a_crypto);
}
} else {
- snprintf(dummy_answer, sizeof(dummy_answer), "m=audio 0 RTP/AVP %s\r\n", p->offered_media[SDP_AUDIO].codecs);
- add_content(resp, dummy_answer);
+ add_content(resp, offer->decline_m_line);
}
- } else if (p->offered_media[SDP_VIDEO].order_offered == i) {
+ break;
+ case SDP_VIDEO:
if (needvideo) { /* only if video response is appropriate */
add_content(resp, m_video->str);
add_content(resp, a_video->str);
@@ -12181,10 +12261,10 @@
add_content(resp, v_a_crypto);
}
} else {
- snprintf(dummy_answer, sizeof(dummy_answer), "m=video 0 RTP/AVP %s\r\n", p->offered_media[SDP_VIDEO].codecs);
- add_content(resp, dummy_answer);
+ add_content(resp, offer->decline_m_line);
}
- } else if (p->offered_media[SDP_TEXT].order_offered == i) {
+ break;
+ case SDP_TEXT:
if (needtext) { /* only if text response is appropriate */
add_content(resp, m_text->str);
add_content(resp, a_text->str);
@@ -12193,16 +12273,20 @@
add_content(resp, t_a_crypto);
}
} else {
- snprintf(dummy_answer, sizeof(dummy_answer), "m=text 0 RTP/AVP %s\r\n", p->offered_media[SDP_TEXT].codecs);
- add_content(resp, dummy_answer);
+ add_content(resp, offer->decline_m_line);
}
- } else if (p->offered_media[SDP_IMAGE].order_offered == i) {
+ break;
+ case SDP_IMAGE:
if (add_t38) {
add_content(resp, m_modem->str);
add_content(resp, a_modem->str);
} else {
- add_content(resp, "m=image 0 udptl t38\r\n");
+ add_content(resp, offer->decline_m_line);
}
+ break;
+ case SDP_UNKNOWN:
+ add_content(resp, offer->decline_m_line);
+ break;
}
}
} else {
@@ -12452,7 +12536,8 @@
if (p->do_history) {
append_history(p, "ReInv", "Re-invite sent");
}
- memset(p->offered_media, 0, sizeof(p->offered_media));
+
+ offered_media_list_destroy(p);
try_suggested_sip_codec(p);
if (t38version) {
@@ -12913,7 +12998,7 @@
add_diversion_header(&req, p);
}
if (sdp) {
- memset(p->offered_media, 0, sizeof(p->offered_media));
+ offered_media_list_destroy(p);
if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
ast_debug(1, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? ast_channel_name(p->owner) : "<none>");
add_sdp(&req, p, FALSE, FALSE, TRUE);
Modified: trunk/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/include/sip.h?view=diff&rev=369028&r1=369027&r2=369028
==============================================================================
--- trunk/channels/sip/include/sip.h (original)
+++ trunk/channels/sip/include/sip.h Fri Jun 15 12:13:20 2012
@@ -467,6 +467,7 @@
SDP_VIDEO, /*!< RTP/AVP Video */
SDP_IMAGE, /*!< Image udptl, not TCP or RTP */
SDP_TEXT, /*!< RTP/AVP Realtime Text */
+ SDP_UNKNOWN, /*!< Unknown media type */
};
/*! \brief Authentication types - proxy or www authentication
@@ -968,10 +969,11 @@
};
/*! \brief Structure for remembering offered media in an INVITE, to make sure we reply
- to all media streams. In theory. In practise, we try our best. */
+ to all media streams. */
struct offered_media {
- int order_offered; /*!< Order the media was offered in. Not offered is 0 */
- char codecs[128];
+ enum media_type type; /*!< The type of media that was offered */
+ char *decline_m_line; /*!< Used if the media type is unknown/unused or a media stream is declined */
+ AST_LIST_ENTRY(offered_media) next;
};
/*! Additional headers to send with MESSAGE method packet. */
@@ -1194,7 +1196,7 @@
*
* The large-scale changes would be a good idea for implementing during an SDP rewrite.
*/
- struct offered_media offered_media[OFFERED_MEDIA_COUNT];
+ AST_LIST_HEAD_NOLOCK(, offered_media) offered_media;
struct ast_cc_config_params *cc_params;
struct sip_epa_entry *epa_entry;
int fromdomainport; /*!< Domain port to show in from field */
More information about the asterisk-commits
mailing list