Merged revisions 28380,28384 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.2

........
r28380 | kpfleming | 2006-05-18 15:24:07 -0500 (Thu, 18 May 2006) | 2 lines

handle incoming multipart/mixed message bodies in SIP and find the SDP, if presnet (issue #7124 reported and patched by eborgstrom, but very different fix)

........
r28384 | kpfleming | 2006-05-18 15:43:42 -0500 (Thu, 18 May 2006) | 2 lines

fix up a few more places to find the SDP properly (fallout from fix for #7124)

........


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@28394 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kevin P. Fleming 2006-05-18 21:02:21 +00:00
parent e274a70d52
commit 0c73d47618
1 changed files with 105 additions and 26 deletions

View File

@ -519,11 +519,13 @@ struct sip_request {
int len; /*!< Length */
int headers; /*!< # of SIP Headers */
int method; /*!< Method of this request */
int lines; /*!< SDP Content */
int lines; /*!< Body Content */
unsigned int flags; /*!< SIP_PKT Flags for this packet */
char *header[SIP_MAX_HEADERS];
char *line[SIP_MAX_LINES];
char data[SIP_MAX_PACKET];
unsigned int sdp_start; /*!< the line number where the SDP begins */
unsigned int sdp_end; /*!< the line number where the SDP ends */
};
/*
@ -1091,9 +1093,9 @@ static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *si
/*--- Codec handling / SDP */
static void try_suggested_sip_codec(struct sip_pvt *p);
static const char *get_sdp_by_line(const char* line, const char *name, int nameLen);
static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
static const char *get_sdp(struct sip_request *req, const char *name);
static int find_sdp(struct sip_request *req);
static int process_sdp(struct sip_pvt *p, struct sip_request *req);
static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
@ -3270,37 +3272,55 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
}
/*! \brief Reads one line of SIP message body */
static const char *get_sdp_by_line(const char* line, const char *name, int nameLen)
static char *get_body_by_line(const char *line, const char *name, int nameLen)
{
if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=')
return ast_skip_blanks(line + nameLen + 1);
return "";
}
/*! \brief get_sdp_iterate: lookup 'name' in the request starting
/*! \brief Lookup 'name' in the SDP starting
* at the 'start' line. Returns the matching line, and 'start'
* is updated with the next line number.
*/
static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name)
static const char *get_sdp_iterate(int *start, struct sip_request *req, const char *name)
{
int len = strlen(name);
while (*start < req->lines) {
const char *r = get_sdp_by_line(req->line[(*start)++], name, len);
while (*start < req->sdp_end) {
const char *r = get_body_by_line(req->line[(*start)++], name, len);
if (r[0] != '\0')
return r;
}
return "";
}
/*! \brief get_sdp: Gets all kind of SIP message bodies, including SDP,
but the name wrongly applies _only_ sdp */
/*! \brief Get a line from an SDP message body */
static const char *get_sdp(struct sip_request *req, const char *name)
{
int dummy = 0;
return get_sdp_iterate(&dummy, req, name);
}
/*! \brief Get a specific line from the message body */
static char *get_body(struct sip_request *req, char *name)
{
int x;
int len = strlen(name);
char *r;
for (x = 0; x < req->lines; x++) {
r = get_body_by_line(req->line[x], name, len);
if (r[0] != '\0')
return r;
}
return "";
}
/*! \brief Find compressed SIP alias */
static const char *find_alias(const char *name, const char *_default)
{
@ -3329,9 +3349,11 @@ static const char *find_alias(const char *name, const char *_default)
{ "Session-Expires", "x" },
};
int x;
for (x=0; x<sizeof(aliases) / sizeof(aliases[0]); x++)
if (!strcasecmp(aliases[x].fullname, name))
return aliases[x].shortname;
return _default;
}
@ -3860,7 +3882,69 @@ static void parse_request(struct sip_request *req)
determine_firstline_parts(req);
}
/*! \brief Process SIP SDP and activate RTP channels*/
/*!
\brief Determine whether a SIP message contains an SDP in its body
\param req the SIP request to process
\return 1 if SDP found, 0 if not found
Also updates req->sdp_start and req->sdp_end to indicate where the SDP
lives in the message body.
*/
static int find_sdp(struct sip_request *req)
{
const char *content_type;
const char *search;
char *boundary;
unsigned int x;
content_type = get_header(req, "Content-Type");
/* if the body contains only SDP, this is easy */
if (!strcasecmp(content_type, "application/sdp")) {
req->sdp_start = 0;
req->sdp_end = req->lines;
return 1;
}
/* if it's not multipart/mixed, there cannot be an SDP */
if (strncasecmp(content_type, "multipart/mixed", 15))
return 0;
/* if there is no boundary marker, it's invalid */
if (!(search = strcasestr(content_type, ";boundary=")))
return 0;
search += 10;
if (ast_strlen_zero(search))
return 0;
/* make a duplicate of the string, with two extra characters
at the beginning */
boundary = ast_strdupa(search - 2);
boundary[0] = boundary[1] = '-';
/* search for the boundary marker, but stop when there are not enough
lines left for it, the Content-Type header and at least one line of
body */
for (x = 0; x < (req->lines - 2); x++) {
if (!strncasecmp(req->line[x], boundary, strlen(boundary)) &&
!strcasecmp(req->line[x + 1], "Content-Type: application/sdp")) {
req->sdp_start = x + 2;
/* search for the end of the body part */
for ( ; x < req->lines; x++) {
if (!strncasecmp(req->line[x], boundary, strlen(boundary)))
break;
}
req->sdp_end = x;
return 1;
}
}
return 0;
}
/*! \brief Process SIP SDP and activate RTP channels---*/
static int process_sdp(struct sip_pvt *p, struct sip_request *req)
{
const char *m;
@ -3894,13 +3978,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
time(&p->lastrtprx);
time(&p->lastrtptx);
/* Get codec and RTP info from SDP */
if (strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
ast_log(LOG_NOTICE, "Content is '%s', not 'application/sdp'\n", get_header(req, "Content-Type"));
return -1;
}
m = get_sdp(req, "m");
destiterator = 0;
destiterator = req->sdp_start;
c = get_sdp_iterate(&destiterator, req, "c");
if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
@ -3916,7 +3995,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
return -1;
}
iterator = 0;
iterator = req->sdp_start;
ast_set_flag(&p->flags[0], SIP_NOVIDEO);
while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
int found = 0;
@ -4015,7 +4094,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
/* Next, scan through each "a=rtpmap:" line, noting each
* specified RTP payload type (with corresponding MIME subtype):
*/
iterator = 0;
iterator = req->sdp_start;
while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
if (!strcasecmp(a, "sendonly")) {
@ -9142,7 +9221,7 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
!strcasecmp(c, "application/vnd.nortelnetworks.digits")) {
/* Try getting the "signal=" part */
if (ast_strlen_zero(c = get_sdp(req, "Signal")) && ast_strlen_zero(c = get_sdp(req, "d"))) {
if (ast_strlen_zero(c = get_body(req, "Signal")) && ast_strlen_zero(c = get_body(req, "d"))) {
ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from %s\n", p->callid);
transmit_response(p, "200 OK", req); /* Should return error */
return;
@ -10002,7 +10081,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
if (p->owner->_state != AST_STATE_UP)
ast_setstate(p->owner, AST_STATE_RINGING);
}
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
if (find_sdp(req)) {
process_sdp(p, req);
if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
/* Queue a progress frame only if we have SDP in 180 */
@ -10014,7 +10093,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
if (!ast_test_flag(req, SIP_PKT_IGNORE))
sip_cancel_destroy(p);
/* Ignore 183 Session progress without SDP */
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
if (find_sdp(req)) {
process_sdp(p, req);
if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
/* Queue a progress frame */
@ -10026,7 +10105,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
if (!ast_test_flag(req, SIP_PKT_IGNORE))
sip_cancel_destroy(p);
p->authtries = 0;
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp"))
if (find_sdp(req))
process_sdp(p, req);
/* Parse contact header for continued conversation */
@ -10594,7 +10673,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
} else if ((resp >= 100) && (resp < 200)) {
if (sipmethod == SIP_INVITE) {
sip_cancel_destroy(p);
if (!ast_strlen_zero(get_header(req, "Content-Type")))
if (find_sdp(req))
process_sdp(p, req);
if (p->owner) {
/* Queue a progress frame */
@ -11155,7 +11234,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
parse_ok_contact(p, req);
} else { /* Re-invite on existing call */
/* Handle SDP here if we already have an owner */
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
if (find_sdp(req)) {
if (process_sdp(p, req)) {
transmit_response(p, "488 Not acceptable here", req);
if (!p->lastinvite)
@ -11186,7 +11265,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
}
/* We have a succesful authentication, process the SDP portion if there is one */
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp") ) {
if (find_sdp(req)) {
if (process_sdp(p, req)) {
/* Unacceptable codecs */
transmit_response_reliable(p, "488 Not acceptable here", req);
@ -11986,7 +12065,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
if (seqno == p->pendinginvite) {
p->pendinginvite = 0;
__sip_ack(p, seqno, FLAG_RESPONSE, 0, FALSE);
if (!ast_strlen_zero(get_header(req, "Content-Type"))) {
if (find_sdp(req)) {
if (process_sdp(p, req))
return -1;
}