mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-26 06:26:41 +00:00
Fix several bugs with SDP parsing and well-formedness of responses
Fix bug ASTERISK-16558 which dealt with the order of responses to incoming streams defined by SDP. Fix unreported bug where offering multiple same-type streams would cause Asterisk to reply with an incorrect SDP response missing one or more streams without a proper declination. Fix bugs related to a single non-audio stream being offered with responses requesting codecs that were not offered in the initial invite along with an additional audio stream that was not in the initial invite. Review: https://reviewboard.asterisk.org/r/1516/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@344385 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -8841,9 +8841,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||||||
ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
|
ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (p->offered_media[SDP_AUDIO].order_offered) {
|
||||||
|
ast_log(LOG_WARNING, "Multiple audio streams are not supported\n");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
audio = TRUE;
|
audio = TRUE;
|
||||||
p->offered_media[SDP_AUDIO].offered = TRUE;
|
p->offered_media[SDP_AUDIO].order_offered = ++numberofmediastreams;
|
||||||
numberofmediastreams++;
|
|
||||||
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: */
|
||||||
@@ -8868,10 +8871,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||||||
ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
|
ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (p->offered_media[SDP_VIDEO].order_offered) {
|
||||||
|
ast_log(LOG_WARNING, "Multiple video streams are not supported\n");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
video = TRUE;
|
video = TRUE;
|
||||||
p->novideo = FALSE;
|
p->novideo = FALSE;
|
||||||
p->offered_media[SDP_VIDEO].offered = TRUE;
|
p->offered_media[SDP_VIDEO].order_offered = ++numberofmediastreams;
|
||||||
numberofmediastreams++;
|
|
||||||
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: */
|
||||||
@@ -8889,10 +8895,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||||||
/* Search for text media definition */
|
/* Search for text media definition */
|
||||||
} else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0 && x) ||
|
} else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0 && x) ||
|
||||||
(sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0 && x)) {
|
(sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0 && x)) {
|
||||||
|
if (p->offered_media[SDP_TEXT].order_offered) {
|
||||||
|
ast_log(LOG_WARNING, "Multiple text streams are not supported\n");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
text = TRUE;
|
text = TRUE;
|
||||||
p->notext = FALSE;
|
p->notext = FALSE;
|
||||||
p->offered_media[SDP_TEXT].offered = TRUE;
|
p->offered_media[SDP_TEXT].order_offered = ++numberofmediastreams;
|
||||||
numberofmediastreams++;
|
|
||||||
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: */
|
||||||
@@ -8910,12 +8919,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||||||
/* Search for image media definition */
|
/* Search for image media definition */
|
||||||
} else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0 && x) ||
|
} else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0 && x) ||
|
||||||
(sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0 && x) )) {
|
(sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0 && x) )) {
|
||||||
|
if (p->offered_media[SDP_IMAGE].order_offered) {
|
||||||
|
ast_log(LOG_WARNING, "Multiple T.38 streams are not supported\n");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
image = TRUE;
|
image = TRUE;
|
||||||
if (debug)
|
if (debug)
|
||||||
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].offered = TRUE;
|
p->offered_media[SDP_IMAGE].order_offered = ++numberofmediastreams;
|
||||||
udptlportno = x;
|
udptlportno = x;
|
||||||
numberofmediastreams++;
|
|
||||||
|
|
||||||
if (p->t38.state != T38_ENABLED) {
|
if (p->t38.state != T38_ENABLED) {
|
||||||
memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
|
memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
|
||||||
@@ -9016,12 +9028,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numberofmediastreams > 3) {
|
|
||||||
/* We have too many fax, audio and/or video and/or text media streams, fail this offer */
|
|
||||||
ast_log(LOG_WARNING, "Faling due to too many media streams\n");
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
|
if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
|
||||||
ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
|
ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
|
||||||
return -4;
|
return -4;
|
||||||
@@ -9081,12 +9087,23 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||||||
ast_rtp_lookup_mime_multiple2(s2, peernoncodeccapability, 0, 0),
|
ast_rtp_lookup_mime_multiple2(s2, peernoncodeccapability, 0, 0),
|
||||||
ast_rtp_lookup_mime_multiple2(s3, newnoncodeccapability, 0, 0));
|
ast_rtp_lookup_mime_multiple2(s3, newnoncodeccapability, 0, 0));
|
||||||
}
|
}
|
||||||
if (!newjointcapability && (portno != -1)) {
|
if (!newjointcapability && udptlportno == -1) {
|
||||||
ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
|
ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
|
||||||
/* Do NOT Change current setting */
|
/* Do NOT Change current setting */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
|
||||||
|
they are acceptable */
|
||||||
|
p->jointcapability = newjointcapability; /* Our joint codec profile for this call */
|
||||||
|
p->peercapability = newpeercapability; /* The other sides capability in latest offer */
|
||||||
|
p->jointnoncodeccapability = newnoncodeccapability; /* DTMF capabilities */
|
||||||
|
|
||||||
|
/* respond with single most preferred joint codec, limiting the other side's choice */
|
||||||
|
if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) {
|
||||||
|
p->jointcapability = ast_codec_choose(&p->prefs, p->jointcapability, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup audio address and port */
|
/* Setup audio address and port */
|
||||||
if (p->rtp) {
|
if (p->rtp) {
|
||||||
if (portno > 0) {
|
if (portno > 0) {
|
||||||
@@ -9096,15 +9113,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||||||
ast_verbose("Peer audio RTP is at port %s\n",
|
ast_verbose("Peer audio RTP is at port %s\n",
|
||||||
ast_sockaddr_stringify(sa));
|
ast_sockaddr_stringify(sa));
|
||||||
}
|
}
|
||||||
/* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
|
|
||||||
they are acceptable */
|
|
||||||
p->jointcapability = newjointcapability; /* Our joint codec profile for this call */
|
|
||||||
p->peercapability = newpeercapability; /* The other sides capability in latest offer */
|
|
||||||
p->jointnoncodeccapability = newnoncodeccapability; /* DTMF capabilities */
|
|
||||||
|
|
||||||
if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) { /* respond with single most preferred joint codec, limiting the other side's choice */
|
|
||||||
p->jointcapability = ast_codec_choose(&p->prefs, p->jointcapability, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_rtp_codecs_payloads_copy(&newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp);
|
ast_rtp_codecs_payloads_copy(&newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp);
|
||||||
/* Ensure RTCP is enabled since it may be inactive
|
/* Ensure RTCP is enabled since it may be inactive
|
||||||
@@ -11405,47 +11413,94 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
|
|||||||
add_content(resp, owner);
|
add_content(resp, owner);
|
||||||
add_content(resp, subject);
|
add_content(resp, subject);
|
||||||
add_content(resp, connection);
|
add_content(resp, connection);
|
||||||
if (needvideo) /* only if video response is appropriate */
|
/* only if video response is appropriate */
|
||||||
|
if (needvideo) {
|
||||||
add_content(resp, bandwidth);
|
add_content(resp, bandwidth);
|
||||||
|
}
|
||||||
add_content(resp, session_time);
|
add_content(resp, session_time);
|
||||||
if (needaudio) {
|
/* if this is a response to an invite, order our offers properly */
|
||||||
add_content(resp, m_audio->str);
|
if (p->offered_media[SDP_AUDIO].order_offered ||
|
||||||
add_content(resp, a_audio->str);
|
p->offered_media[SDP_VIDEO].order_offered ||
|
||||||
add_content(resp, hold);
|
p->offered_media[SDP_TEXT].order_offered ||
|
||||||
if (a_crypto) {
|
p->offered_media[SDP_IMAGE].order_offered) {
|
||||||
add_content(resp, a_crypto);
|
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) {
|
||||||
|
add_content(resp, m_audio->str);
|
||||||
|
add_content(resp, a_audio->str);
|
||||||
|
add_content(resp, hold);
|
||||||
|
if (a_crypto) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
} else if (p->offered_media[SDP_VIDEO].order_offered == i) {
|
||||||
|
if (needvideo) { /* only if video response is appropriate */
|
||||||
|
add_content(resp, m_video->str);
|
||||||
|
add_content(resp, a_video->str);
|
||||||
|
add_content(resp, hold); /* Repeat hold for the video stream */
|
||||||
|
if (v_a_crypto) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
} else if (p->offered_media[SDP_TEXT].order_offered == i) {
|
||||||
|
if (needtext) { /* only if text response is appropriate */
|
||||||
|
add_content(resp, m_text->str);
|
||||||
|
add_content(resp, a_text->str);
|
||||||
|
add_content(resp, hold); /* Repeat hold for the text stream */
|
||||||
|
if (t_a_crypto) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
} else if (p->offered_media[SDP_IMAGE].order_offered == i) {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (p->offered_media[SDP_AUDIO].offered) {
|
} else {
|
||||||
snprintf(dummy_answer, sizeof(dummy_answer), "m=audio 0 RTP/AVP %s\r\n", p->offered_media[SDP_AUDIO].codecs);
|
/* generate new SDP from scratch, no offers */
|
||||||
add_content(resp, dummy_answer);
|
if (needaudio) {
|
||||||
}
|
add_content(resp, m_audio->str);
|
||||||
if (needvideo) { /* only if video response is appropriate */
|
add_content(resp, a_audio->str);
|
||||||
add_content(resp, m_video->str);
|
add_content(resp, hold);
|
||||||
add_content(resp, a_video->str);
|
if (a_crypto) {
|
||||||
add_content(resp, hold); /* Repeat hold for the video stream */
|
add_content(resp, a_crypto);
|
||||||
if (v_a_crypto) {
|
}
|
||||||
add_content(resp, v_a_crypto);
|
|
||||||
}
|
}
|
||||||
} else if (p->offered_media[SDP_VIDEO].offered) {
|
if (needvideo) { /* only if video response is appropriate */
|
||||||
snprintf(dummy_answer, sizeof(dummy_answer), "m=video 0 RTP/AVP %s\r\n", p->offered_media[SDP_VIDEO].codecs);
|
add_content(resp, m_video->str);
|
||||||
add_content(resp, dummy_answer);
|
add_content(resp, a_video->str);
|
||||||
}
|
add_content(resp, hold); /* Repeat hold for the video stream */
|
||||||
if (needtext) { /* only if text response is appropriate */
|
if (v_a_crypto) {
|
||||||
add_content(resp, m_text->str);
|
add_content(resp, v_a_crypto);
|
||||||
add_content(resp, a_text->str);
|
}
|
||||||
add_content(resp, hold); /* Repeat hold for the text stream */
|
}
|
||||||
if (t_a_crypto) {
|
if (needtext) { /* only if text response is appropriate */
|
||||||
add_content(resp, t_a_crypto);
|
add_content(resp, m_text->str);
|
||||||
|
add_content(resp, a_text->str);
|
||||||
|
add_content(resp, hold); /* Repeat hold for the text stream */
|
||||||
|
if (t_a_crypto) {
|
||||||
|
add_content(resp, t_a_crypto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (add_t38) {
|
||||||
|
add_content(resp, m_modem->str);
|
||||||
|
add_content(resp, a_modem->str);
|
||||||
}
|
}
|
||||||
} else if (p->offered_media[SDP_TEXT].offered) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (add_t38) {
|
|
||||||
add_content(resp, m_modem->str);
|
|
||||||
add_content(resp, a_modem->str);
|
|
||||||
} else if (p->offered_media[SDP_IMAGE].offered) {
|
|
||||||
add_content(resp, "m=image 0 udptl t38\r\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update lastrtprx when we send our SDP */
|
/* Update lastrtprx when we send our SDP */
|
||||||
|
|||||||
@@ -913,7 +913,7 @@ 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. In theory. In practise, we try our best. */
|
||||||
struct offered_media {
|
struct offered_media {
|
||||||
int offered;
|
int order_offered; /*!< Order the media was offered in. Not offered is 0 */
|
||||||
char codecs[128];
|
char codecs[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user