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/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@369028 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/11.2
Kinsey Moore 14 years ago
parent 88c9c6bef8
commit bf6ef69702

@ -5850,6 +5850,16 @@ static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi)
ast_free(mwi); 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 */ /*! \brief Execute destruction of SIP dialog structure, release memory */
void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist) void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
{ {
@ -5953,6 +5963,8 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
ast_free(req); ast_free(req);
} }
offered_media_list_destroy(p);
if (p->chanvars) { if (p->chanvars) {
ast_variables_destroy(p->chanvars); ast_variables_destroy(p->chanvars);
p->chanvars = NULL; p->chanvars = NULL;
@ -8033,6 +8045,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
ast_string_field_set(p, engine, default_engine); ast_string_field_set(p, engine, default_engine);
AST_LIST_HEAD_INIT_NOLOCK(&p->request_queue); AST_LIST_HEAD_INIT_NOLOCK(&p->request_queue);
AST_LIST_HEAD_INIT_NOLOCK(&p->offered_media);
/* Add to active dialog list */ /* Add to active dialog list */
@ -9119,6 +9132,18 @@ static int sockaddr_is_null_or_any(const struct ast_sockaddr *addr)
return ast_sockaddr_isnull(addr) || ast_sockaddr_is_any(addr); 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 /*! \brief Process SIP SDP offer, select formats and activate media channels
If offer is rejected, we will not change any properties of the call If offer is rejected, we will not change any properties of the call
Return 0 on success, a negative value on errors. Return 0 on success, a negative value on errors.
@ -9139,6 +9164,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
const char *m = NULL; /* SDP media offer */ const char *m = NULL; /* SDP media offer */
const char *nextm = NULL; const char *nextm = NULL;
int len = -1; int len = -1;
struct offered_media *offer;
/* Host information */ /* Host information */
struct ast_sockaddr sessionsa; struct ast_sockaddr sessionsa;
@ -9178,7 +9204,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
int sendonly = -1; int sendonly = -1;
int vsendonly = -1; int vsendonly = -1;
int numberofports; int numberofports;
int numberofmediastreams = 0;
int last_rtpmap_codec = 0; int last_rtpmap_codec = 0;
int red_data_pt[10]; /* For T.140 RED */ int red_data_pt[10]; /* For T.140 RED */
int red_num_gen = 0; /* For T.140 RED */ int red_num_gen = 0; /* For T.140 RED */
@ -9209,7 +9234,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
/* Update our last rtprx when we receive an SDP, too */ /* Update our last rtprx when we receive an SDP, too */
p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */ 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 */ /* Scan for the first media stream (m=) line to limit scanning of globals */
nextm = get_sdp_iterate(&next, req, "m"); nextm = get_sdp_iterate(&next, req, "m");
@ -9281,10 +9306,29 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
iterator = next; iterator = next;
nextm = get_sdp_iterate(&next, req, "m"); 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 */ /* Check for 'audio' media offer */
if (strncmp(m, "audio ", 6) == 0) { if (strncmp(m, "audio ", 6) == 0) {
if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 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)) { (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) { if (x == 0) {
ast_log(LOG_WARNING, "Ignoring audio media offer because port number is zero\n"); ast_log(LOG_WARNING, "Ignoring audio media offer because port number is zero\n");
continue; continue;
@ -9299,23 +9343,19 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
secure_audio = 1; secure_audio = 1;
} else if (strcmp(protocol, "AVP")) { } else if (strcmp(protocol, "AVP")) {
ast_log(LOG_WARNING, "Unknown RTP profile in audio offer: %s\n", m); ast_log(LOG_WARNING, "Unknown RTP profile in audio offer: %s\n", m);
res = -1; continue;
goto process_sdp_cleanup;
} }
if (p->offered_media[SDP_AUDIO].order_offered) { if (has_media_stream(p, SDP_AUDIO)) {
ast_log(LOG_WARNING, "Rejecting non-primary audio stream: %s\n", m); ast_log(LOG_WARNING, "Declining non-primary audio stream: %s\n", m);
res = -1; continue;
goto process_sdp_cleanup;
} }
audio = TRUE; audio = TRUE;
p->offered_media[SDP_AUDIO].order_offered = ++numberofmediastreams; offer->type = SDP_AUDIO;
portno = x; portno = x;
/* Scan through the RTP payload types specified in a "m=" line: */ /* 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)) { for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Invalid syntax in RTP audio format list: %s\n", codecs); ast_log(LOG_WARNING, "Invalid syntax in RTP audio format list: %s\n", codecs);
@ -9338,38 +9378,45 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
else if (strncmp(m, "video ", 6) == 0) { else if (strncmp(m, "video ", 6) == 0) {
if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 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)) { (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) { 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; continue;
} }
/* Check number of ports offered for stream */ /* Check number of ports offered for stream */
if (numberofports > 1) { 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")) { if (!strcmp(protocol, "SAVP")) {
secure_video = 1; secure_video = 1;
} else if (strcmp(protocol, "AVP")) { } else if (strcmp(protocol, "AVP")) {
ast_log(LOG_WARNING, "Unknown RTP profile in video offer: %s\n", m); ast_log(LOG_WARNING, "Unknown RTP profile in video offer: %s\n", m);
res = -1; continue;
goto process_sdp_cleanup;
} }
if (p->offered_media[SDP_VIDEO].order_offered) { if (has_media_stream(p, SDP_VIDEO)) {
ast_log(LOG_WARNING, "Rejecting non-primary video stream: %s\n", m); ast_log(LOG_WARNING, "Declining non-primary video stream: %s\n", m);
res = -1; continue;
goto process_sdp_cleanup;
} }
video = TRUE; video = TRUE;
p->novideo = FALSE; p->novideo = FALSE;
p->offered_media[SDP_VIDEO].order_offered = ++numberofmediastreams; offer->type = SDP_VIDEO;
vportno = x; vportno = x;
/* Scan through the RTP payload types specified in a "m=" line: */ /* 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)) { for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs); ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs);
@ -9391,30 +9438,38 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
else if (strncmp(m, "text ", 5) == 0) { else if (strncmp(m, "text ", 5) == 0) {
if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 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)) { (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0)) {
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) { if (x == 0) {
ast_log(LOG_WARNING, "Ignoring text media offer because port number is zero\n"); ast_log(LOG_WARNING, "Ignoring text stream offer because port number is zero\n");
continue; continue;
} }
/* Check number of ports offered for stream */ /* Check number of ports offered for stream */
if (numberofports > 1) { if (numberofports > 1) {
ast_log(LOG_WARNING, "%d ports offered for text media, not supported by Asterisk. Will try anyway...\n", numberofports); ast_log(LOG_WARNING, "%d ports offered for text stream, not supported by Asterisk. Will try anyway...\n", numberofports);
} }
if (p->offered_media[SDP_TEXT].order_offered) { if (has_media_stream(p, SDP_TEXT)) {
ast_log(LOG_WARNING, "Rejecting non-primary text stream: %s\n", m); ast_log(LOG_WARNING, "Declining non-primary text stream: %s\n", m);
res = -1; continue;
goto process_sdp_cleanup;
} }
text = TRUE; text = TRUE;
p->notext = FALSE; p->notext = FALSE;
p->offered_media[SDP_TEXT].order_offered = ++numberofmediastreams; offer->type = SDP_TEXT;
tportno = x; tportno = x;
/* Scan through the RTP payload types specified in a "m=" line: */ /* 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)) { for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs); ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs);
@ -9427,7 +9482,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec); ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec);
} }
} else { } 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; res = -1;
goto process_sdp_cleanup; goto process_sdp_cleanup;
} }
@ -9436,20 +9491,29 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
else if (strncmp(m, "image ", 6) == 0) { else if (strncmp(m, "image ", 6) == 0) {
if (((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 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))) { (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0))) {
/* 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;
}
/* guaranteed to be exactly the right length */
strcpy(offer->decline_m_line, "m=image 0 UDPTL t38");
if (x == 0) { if (x == 0) {
ast_log(LOG_WARNING, "Ignoring image media offer because port number is zero\n"); ast_log(LOG_WARNING, "Ignoring image stream offer because port number is zero\n");
continue; continue;
} }
if (initialize_udptl(p)) { if (initialize_udptl(p)) {
res = -1; ast_log(LOG_WARNING, "Failed to initialize UDPTL, declining image stream\n");
goto process_sdp_cleanup; continue;
} }
if (p->offered_media[SDP_IMAGE].order_offered) { if (has_media_stream(p, SDP_IMAGE)) {
ast_log(LOG_WARNING, "Rejecting non-primary image stream: %s\n", m); ast_log(LOG_WARNING, "Declining non-primary image stream: %s\n", m);
res = -1; continue;
goto process_sdp_cleanup;
} }
image = TRUE; image = TRUE;
@ -9457,7 +9521,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid); 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; udptlportno = x;
if (p->t38.state != T38_ENABLED) { if (p->t38.state != T38_ENABLED) {
@ -9473,9 +9537,26 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
goto process_sdp_cleanup; goto process_sdp_cleanup;
} }
} else { } else {
ast_log(LOG_WARNING, "Unsupported top-level media type in offer: %s\n", m); char type[20] = {0,};
res = -1; char *typelen = strchr(m, ' ');
goto process_sdp_cleanup; 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 */ /* Media stream specific parameters */
@ -9852,6 +9933,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
} }
process_sdp_cleanup: process_sdp_cleanup:
if (res) {
offered_media_list_destroy(p);
}
ast_format_cap_destroy(peercapability); ast_format_cap_destroy(peercapability);
ast_format_cap_destroy(vpeercapability); ast_format_cap_destroy(vpeercapability);
ast_format_cap_destroy(tpeercapability); ast_format_cap_destroy(tpeercapability);
@ -11817,6 +11901,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
struct ast_sockaddr udptldest = { {0,} }; struct ast_sockaddr udptldest = { {0,} };
/* SDP fields */ /* SDP fields */
struct offered_media *offer;
char *version = "v=0\r\n"; /* Protocol version */ char *version = "v=0\r\n"; /* Protocol version */
char subject[256]; /* Subject of the session */ char subject[256]; /* Subject of the session */
char owner[256]; /* Session owner/creator */ char owner[256]; /* Session owner/creator */
@ -11848,7 +11933,6 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
char codecbuf[SIPBUFSIZE]; char codecbuf[SIPBUFSIZE];
char buf[SIPBUFSIZE]; char buf[SIPBUFSIZE];
char dummy_answer[256];
/* Set the SDP session name */ /* Set the SDP session name */
snprintf(subject, sizeof(subject), "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession); snprintf(subject, sizeof(subject), "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession);
@ -12153,14 +12237,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
} }
add_content(resp, session_time); add_content(resp, session_time);
/* if this is a response to an invite, order our offers properly */ /* if this is a response to an invite, order our offers properly */
if (p->offered_media[SDP_AUDIO].order_offered || if (!AST_LIST_EMPTY(&p->offered_media)) {
p->offered_media[SDP_VIDEO].order_offered || AST_LIST_TRAVERSE(&p->offered_media, offer, next) {
p->offered_media[SDP_TEXT].order_offered || switch (offer->type) {
p->offered_media[SDP_IMAGE].order_offered) { case SDP_AUDIO:
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 (needaudio) { if (needaudio) {
add_content(resp, m_audio->str); add_content(resp, m_audio->str);
add_content(resp, a_audio->str); add_content(resp, a_audio->str);
@ -12169,10 +12249,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
add_content(resp, a_crypto); add_content(resp, a_crypto);
} }
} else { } else {
snprintf(dummy_answer, sizeof(dummy_answer), "m=audio 0 RTP/AVP %s\r\n", p->offered_media[SDP_AUDIO].codecs); add_content(resp, offer->decline_m_line);
add_content(resp, dummy_answer);
} }
} else if (p->offered_media[SDP_VIDEO].order_offered == i) { break;
case SDP_VIDEO:
if (needvideo) { /* only if video response is appropriate */ if (needvideo) { /* only if video response is appropriate */
add_content(resp, m_video->str); add_content(resp, m_video->str);
add_content(resp, a_video->str); add_content(resp, a_video->str);
@ -12181,10 +12261,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
add_content(resp, v_a_crypto); add_content(resp, v_a_crypto);
} }
} else { } else {
snprintf(dummy_answer, sizeof(dummy_answer), "m=video 0 RTP/AVP %s\r\n", p->offered_media[SDP_VIDEO].codecs); add_content(resp, offer->decline_m_line);
add_content(resp, dummy_answer);
} }
} else if (p->offered_media[SDP_TEXT].order_offered == i) { break;
case SDP_TEXT:
if (needtext) { /* only if text response is appropriate */ if (needtext) { /* only if text response is appropriate */
add_content(resp, m_text->str); add_content(resp, m_text->str);
add_content(resp, a_text->str); add_content(resp, a_text->str);
@ -12193,16 +12273,20 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
add_content(resp, t_a_crypto); add_content(resp, t_a_crypto);
} }
} else { } else {
snprintf(dummy_answer, sizeof(dummy_answer), "m=text 0 RTP/AVP %s\r\n", p->offered_media[SDP_TEXT].codecs); add_content(resp, offer->decline_m_line);
add_content(resp, dummy_answer);
} }
} else if (p->offered_media[SDP_IMAGE].order_offered == i) { break;
case SDP_IMAGE:
if (add_t38) { if (add_t38) {
add_content(resp, m_modem->str); add_content(resp, m_modem->str);
add_content(resp, a_modem->str); add_content(resp, a_modem->str);
} else { } 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 { } else {
@ -12452,7 +12536,8 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old
if (p->do_history) { if (p->do_history) {
append_history(p, "ReInv", "Re-invite sent"); 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); try_suggested_sip_codec(p);
if (t38version) { if (t38version) {
@ -12913,7 +12998,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
add_diversion_header(&req, p); add_diversion_header(&req, p);
} }
if (sdp) { 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) { 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>"); 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); add_sdp(&req, p, FALSE, FALSE, TRUE);

@ -467,6 +467,7 @@ enum media_type {
SDP_VIDEO, /*!< RTP/AVP Video */ SDP_VIDEO, /*!< RTP/AVP Video */
SDP_IMAGE, /*!< Image udptl, not TCP or RTP */ SDP_IMAGE, /*!< Image udptl, not TCP or RTP */
SDP_TEXT, /*!< RTP/AVP Realtime Text */ SDP_TEXT, /*!< RTP/AVP Realtime Text */
SDP_UNKNOWN, /*!< Unknown media type */
}; };
/*! \brief Authentication types - proxy or www authentication /*! \brief Authentication types - proxy or www authentication
@ -968,10 +969,11 @@ struct sip_st_cfg {
}; };
/*! \brief Structure for remembering offered media in an INVITE, to make sure we reply /*! \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 { struct offered_media {
int order_offered; /*!< Order the media was offered in. Not offered is 0 */ enum media_type type; /*!< The type of media that was offered */
char codecs[128]; 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. */ /*! Additional headers to send with MESSAGE method packet. */
@ -1194,7 +1196,7 @@ struct sip_pvt {
* *
* The large-scale changes would be a good idea for implementing during an SDP rewrite. * 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 ast_cc_config_params *cc_params;
struct sip_epa_entry *epa_entry; struct sip_epa_entry *epa_entry;
int fromdomainport; /*!< Domain port to show in from field */ int fromdomainport; /*!< Domain port to show in from field */

Loading…
Cancel
Save