Newer
Older
if (p != r) {
*p++ = ',';
--rem;
}
*p++ = '<';
Kevin P. Fleming
committed
ast_copy_string(p, route->hop, rem); p += n;
*p++ = '>';
rem -= (n+2);
}
*p = '\0';
add_header(req, "Route", r);
}
/*! \brief Set destination from SIP URI */
static void set_destination(struct sip_pvt *p, char *uri)
{
char *h, *maddr, hostname[256];
char iabuf[INET_ADDRSTRLEN];
int port, hn;
struct hostent *hp;
/* Parse uri to h (host) and port - uri is already just the part inside the <> */
/* general form we are expecting is sip[s]:username[:password]@host[:port][;...] */
ast_verbose("set_destination: Parsing <%s> for address/port to send to\n", uri);
if (h)
++h;
else {
h = uri;
if (strncmp(h, "sip:", 4) == 0)
h += 4;
else if (strncmp(h, "sips:", 5) == 0)
h += 5;
Kevin P. Fleming
committed
hn = strcspn(h, ":;>") + 1;
if (hn > sizeof(hostname))
hn = sizeof(hostname);
Kevin P. Fleming
committed
ast_copy_string(hostname, h, hn);
Kevin P. Fleming
committed
h += hn - 1;
/* Is "port" present? if not default to DEFAULT_SIP_PORT */
if (*h == ':') {
/* Parse port */
++h;
port = strtol(h, &h, 10);
}
else
/* Got the hostname:port - but maybe there's a "maddr=" to override address? */
maddr = strstr(h, "maddr=");
Kevin P. Fleming
committed
hn = strspn(maddr, "0123456789.") + 1;
if (hn > sizeof(hostname))
hn = sizeof(hostname);
hp = ast_gethostbyname(hostname, &ahp);
ast_log(LOG_WARNING, "Can't find address for host '%s'\n", hostname);
return;
}
p->sa.sin_family = AF_INET;
memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr));
p->sa.sin_port = htons(port);
Mark Spencer
committed
ast_verbose("set_destination: set destination to %s, port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), port);
/*! \brief Initialize SIP response, based on SIP request */
static int init_resp(struct sip_request *req, const char *resp, struct sip_request *orig)
{
/* Initialize a response */
if (req->headers || req->len) {
ast_log(LOG_WARNING, "Request already initialized?!?\n");
return -1;
}
req->method = SIP_RESPONSE;
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "SIP/2.0 %s\r\n", resp);
req->len += strlen(req->header[req->headers]);
/*! \brief Initialize SIP request */
static int init_req(struct sip_request *req, int sipmethod, const char *recip)
{
/* Initialize a response */
if (req->headers || req->len) {
ast_log(LOG_WARNING, "Request already initialized?!?\n");
return -1;
}
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
req->method = sipmethod;
/*! \brief Prepare SIP response packet */
static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, struct sip_request *req)
char newto[256];
const char *ot;
Mark Spencer
committed
memset(resp, 0, sizeof(*resp));
init_resp(resp, msg, req);
copy_via_headers(p, resp, req, "Via");
if (msg[0] == '2')
copy_all_header(resp, req, "Record-Route");
if (!strcasestr(ot, "tag=") && strncmp(msg, "100", 3)) {
/* Add the proper tag if we don't have it already. If they have specified
their tag, use it. Otherwise, use our own tag */
if (!ast_strlen_zero(p->theirtag) && ast_test_flag(&p->flags[0], SIP_OUTGOING))
snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
else if (p->tag && !ast_test_flag(&p->flags[0], SIP_OUTGOING))
Kevin P. Fleming
committed
snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->tag);
Mark Spencer
committed
else {
Kevin P. Fleming
committed
ast_copy_string(newto, ot, sizeof(newto));
Mark Spencer
committed
newto[sizeof(newto) - 1] = '\0';
}
ot = newto;
}
add_header(resp, "To", ot);
copy_header(resp, req, "Call-ID");
copy_header(resp, req, "CSeq");
add_header(resp, "User-Agent", global_useragent);
if (msg[0] == '2' && (p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER)) {
/* For registration responses, we also need expiry and
if (p->expiry) { /* Only add contact if we have an expiry time */
char contact[256];
snprintf(contact, sizeof(contact), "%s;expires=%d", p->our_contact, p->expiry);
add_header(resp, "Contact", contact); /* Not when we unregister */
}
Kevin P. Fleming
committed
} else if (p->our_contact[0]) {
add_header(resp, "Contact", p->our_contact);
/*! \brief Initialize a SIP request response packet */
static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch)
char stripped[80];
const char *c;
char *n;
const char *ot, *of;
int is_strict = FALSE; /*!< Strict routing flag */
memset(req, 0, sizeof(struct sip_request));
snprintf(p->lastmsg, sizeof(p->lastmsg), "Tx: %s", sip_methods[sipmethod].text);
if (!seqno) {
seqno = p->ocseq;
}
Mark Spencer
committed
if (newbranch) {
Tilghman Lesher
committed
p->branch ^= ast_random();
build_via(p);
Mark Spencer
committed
}
/* Check for strict or loose router */
if (p->route && !ast_strlen_zero(p->route->hop) && strstr(p->route->hop,";lr") == NULL) {
if (sipdebug)
ast_log(LOG_DEBUG, "Strict routing enforced for session %s\n", p->callid);
}
if (sipmethod == SIP_CANCEL) {
c = p->initreq.rlPart2; /* Use original URI */
} else if (sipmethod == SIP_ACK) {
/* Use URI from Contact: in 200 OK (if INVITE)
(we only have the contacturi on INVITEs) */
if (!ast_strlen_zero(p->okcontacturi))
c = is_strict ? p->route->hop : p->okcontacturi;
else
c = p->initreq.rlPart2;
} else if (!ast_strlen_zero(p->okcontacturi)) {
c = is_strict ? p->route->hop : p->okcontacturi; /* Use for BYE or REINVITE */
Mark Spencer
committed
} else if (!ast_strlen_zero(p->uri)) {
/* We have no URI, use To: or From: header as URI (depending on direction) */
ast_copy_string(stripped, get_header(orig, (ast_test_flag(&p->flags[0], SIP_OUTGOING)) ? "To" : "From"),
sizeof(stripped));
c = get_in_brackets(stripped);
n = strchr(c, ';');
if (n)
*n = '\0';
}
init_req(req, sipmethod, c);
snprintf(tmp, sizeof(tmp), "%d %s", seqno, sip_methods[sipmethod].text);
if (p->route) {
set_destination(p, p->route->hop);
add_route(req, is_strict ? p->route->next : p->route);
ot = get_header(orig, "To");
of = get_header(orig, "From");
/* Add tag *unless* this is a CANCEL, in which case we need to send it exactly
as our original request, including tag (or presumably lack thereof) */
if (!strcasestr(ot, "tag=") && sipmethod != SIP_CANCEL) {
/* Add the proper tag if we don't have it already. If they have specified
their tag, use it. Otherwise, use our own tag */
if (ast_test_flag(&p->flags[0], SIP_OUTGOING) && !ast_strlen_zero(p->theirtag))
snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
else if (!ast_test_flag(&p->flags[0], SIP_OUTGOING))
Kevin P. Fleming
committed
snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->tag);
else
snprintf(newto, sizeof(newto), "%s", ot);
if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
add_header(req, "From", of);
add_header(req, "To", ot);
} else {
add_header(req, "From", ot);
add_header(req, "To", of);
}
add_header(req, "Contact", p->our_contact);
add_header(req, "User-Agent", global_useragent);
add_header(req, "Max-Forwards", DEFAULT_MAX_FORWARDS);
Kevin P. Fleming
committed
if (!ast_strlen_zero(p->rpid))
Kevin P. Fleming
committed
add_header(req, "Remote-Party-ID", p->rpid);
/*! \brief Base transmit response function */
static int __transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req, enum xmittype reliable)
Kevin P. Fleming
committed
if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
return -1;
}
add_header_contentLength(&resp, 0);
Kevin P. Fleming
committed
/* If we are cancelling an incoming invite for some reason, add information
about the reason why we are doing this in clear text */
if (msg[0] != '1' && p->owner && p->owner->hangupcause) {
add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause));
Kevin P. Fleming
committed
}
return send_response(p, &resp, reliable, seqno);
}
/*! \brief Transmit response, no retransmits */
static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req)
{
return __transmit_response(p, msg, req, XMIT_UNRELIABLE);
/*! \brief Transmit response, no retransmits */
static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, struct sip_request *req, const char *unsupported)
{
struct sip_request resp;
respprep(&resp, p, msg, req);
append_date(&resp);
add_header(&resp, "Unsupported", unsupported);
return send_response(p, &resp, XMIT_UNRELIABLE, 0);
}
/*! \brief Transmit response, Make sure you get an ACK
This is only used for responses to INVITEs, where we need to make sure we get an ACK
*/
static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req)
return __transmit_response(p, msg, req, XMIT_CRITICAL);
/*! \brief Append date to SIP message */
static void append_date(struct sip_request *req)
{
char tmpdat[256];
struct tm tm;
time_t t = time(NULL);
gmtime_r(&t, &tm);
strftime(tmpdat, sizeof(tmpdat), "%a, %d %b %Y %T GMT", &tm);
add_header(req, "Date", tmpdat);
}
/*! \brief Append date and content length before transmitting response */
static int transmit_response_with_date(struct sip_pvt *p, char *msg, struct sip_request *req)
{
struct sip_request resp;
respprep(&resp, p, msg, req);
append_date(&resp);
add_header_contentLength(&resp, 0);
return send_response(p, &resp, XMIT_UNRELIABLE, 0);
/*! \brief Append Accept header, content length before transmitting response */
static int transmit_response_with_allow(struct sip_pvt *p, char *msg, struct sip_request *req, enum xmittype reliable)
{
struct sip_request resp;
respprep(&resp, p, msg, req);
add_header(&resp, "Accept", "application/sdp");
add_header_contentLength(&resp, 0);
return send_response(p, &resp, reliable, 0);
/*! \brief Respond with authorization request */
static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, struct sip_request *req, const char *randdata, enum xmittype reliable, const char *header, int stale)
{
struct sip_request resp;
char tmp[256];
Kevin P. Fleming
committed
if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
return -1;
}
Kevin P. Fleming
committed
/* Stale means that they sent us correct authentication, but
based it on an old challenge (nonce) */
snprintf(tmp, sizeof(tmp), "Digest realm=\"%s\", nonce=\"%s\"%s", global_realm, randdata, stale ? ", stale=true" : "");
Mark Spencer
committed
add_header(&resp, header, tmp);
add_header_contentLength(&resp, 0);
return send_response(p, &resp, reliable, seqno);
/*! \brief Add text body to SIP message */
Mark Spencer
committed
static int add_text(struct sip_request *req, const char *text)
{
/* XXX Convert \n's to \r\n's XXX */
add_header(req, "Content-Type", "text/plain");
add_header_contentLength(req, strlen(text));
/*! \brief Add DTMF INFO tone to sip message */
/* Always adds default duration 250 ms, regardless of what came in over the line */
static int add_digit(struct sip_request *req, char digit)
{
char tmp[256];
snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=250\r\n", digit);
add_header(req, "Content-Type", "application/dtmf-relay");
add_header_contentLength(req, strlen(tmp));
add_line(req, tmp);
return 0;
}
/*! \brief add XML encoded media control with update */
/*! \note XML: The only way to turn 0 bits of information into a few hundred. */
static int add_vidupdate(struct sip_request *req)
{
const char *xml_is_a_huge_waste_of_space =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
" <media_control>\r\n"
" <vc_primitive>\r\n"
" <to_encoder>\r\n"
" <picture_fast_update>\r\n"
" </picture_fast_update>\r\n"
" </to_encoder>\r\n"
" </vc_primitive>\r\n"
" </media_control>\r\n";
add_header(req, "Content-Type", "application/media_control+xml");
add_header_contentLength(req, strlen(xml_is_a_huge_waste_of_space));
add_line(req, xml_is_a_huge_waste_of_space);
return 0;
}
Kevin P. Fleming
committed
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,
int debug)
{
int rtp_code;
if (debug)
ast_verbose("Adding codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1)
return;
ast_build_string(m_buf, m_size, " %d", rtp_code);
ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
ast_rtp_lookup_mime_subtype(1, codec),
sample_rate);
if (codec == AST_FORMAT_G729A)
/* Indicate that we don't support VAD (G.729 annex B) */
Russell Bryant
committed
ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);
Kevin P. Fleming
committed
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
}
static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
int debug)
{
int rtp_code;
if (debug)
ast_verbose("Adding non-codec 0x%x (%s) to SDP\n", format, ast_rtp_lookup_mime_subtype(0, format));
if ((rtp_code = ast_rtp_lookup_code(p->rtp, 0, format)) == -1)
return;
ast_build_string(m_buf, m_size, " %d", rtp_code);
ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
ast_rtp_lookup_mime_subtype(0, format),
sample_rate);
if (format == AST_RTP_DTMF)
/* Indicate we support DTMF and FLASH... */
ast_build_string(a_buf, a_size, "a=fmtp:%d 0-16\r\n", rtp_code);
}
/*! \brief Add Session Description Protocol message */
static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
Kevin P. Fleming
committed
int pref_codec;
struct sockaddr_in vsin;
char v[256];
char s[256];
char o[256];
char c[256];
char t[256];
Kevin P. Fleming
committed
char m_audio[256];
char m_video[256];
char a_audio[1024];
char a_video[1024];
char *m_audio_next = m_audio;
char *m_video_next = m_video;
size_t m_audio_left = sizeof(m_audio);
size_t m_video_left = sizeof(m_video);
char *a_audio_next = a_audio;
char *a_video_next = a_video;
size_t a_audio_left = sizeof(a_audio);
size_t a_video_left = sizeof(a_video);
char iabuf[INET_ADDRSTRLEN];
Kevin P. Fleming
committed
int x;
int capability;
Mark Spencer
committed
struct sockaddr_in vdest = { 0, };
Kevin P. Fleming
committed
int debug;
debug = sip_debug_test_pvt(p);
if (!p->rtp) {
ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
return -1;
}
capability = p->jointcapability;
if (!p->sessionid) {
p->sessionid = getpid();
p->sessionversion = p->sessionid;
} else
p->sessionversion++;
if (p->vrtp)
ast_rtp_get_us(p->vrtp, &vsin);
if (p->redirip.sin_addr.s_addr) {
dest.sin_port = p->redirip.sin_port;
dest.sin_addr = p->redirip.sin_addr;
if (p->redircodecs)
capability = p->redircodecs;
} else {
dest.sin_addr = p->ourip;
dest.sin_port = sin.sin_port;
}
/* Determine video destination */
if (p->vrtp) {
if (p->vredirip.sin_addr.s_addr) {
vdest.sin_port = p->vredirip.sin_port;
vdest.sin_addr = p->vredirip.sin_addr;
} else {
vdest.sin_addr = p->ourip;
vdest.sin_port = vsin.sin_port;
}
}
if (debug) {
Mark Spencer
committed
ast_verbose("We're at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(sin.sin_port));
Mark Spencer
committed
ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(vsin.sin_port));
Kevin P. Fleming
committed
/* We break with the "recommendation" and send our IP, in order that our
peer doesn't have to ast_gethostbyname() us */
Mark Spencer
committed
snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr));
Mark Spencer
committed
snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr));
if ((p->vrtp) &&
(!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
(capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
Kevin P. Fleming
committed
ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
/* Prefer the codec we were requested to use, first, no matter what */
Kevin P. Fleming
committed
if (p->prefcodec <= AST_FORMAT_MAX_AUDIO)
add_codec_to_sdp(p, p->prefcodec, 8000,
&m_audio_next, &m_audio_left,
&a_audio_next, &a_audio_left,
debug);
else
add_codec_to_sdp(p, p->prefcodec, 90000,
&m_video_next, &m_video_left,
&a_video_next, &a_video_left,
debug);
alreadysent |= p->prefcodec;
}
Kevin P. Fleming
committed
/* Start by sending our preferred codecs */
Kevin P. Fleming
committed
for (x = 0; x < 32; x++) {
if (!(pref_codec = ast_codec_pref_index(&p->prefs, x)))
Kevin P. Fleming
committed
if (!(capability & pref_codec))
continue;
if (alreadysent & pref_codec)
continue;
if (pref_codec <= AST_FORMAT_MAX_AUDIO)
add_codec_to_sdp(p, pref_codec, 8000,
&m_audio_next, &m_audio_left,
&a_audio_next, &a_audio_left,
debug);
else
add_codec_to_sdp(p, pref_codec, 90000,
&m_video_next, &m_video_left,
&a_video_next, &a_video_left,
debug);
alreadysent |= pref_codec;
/* Now send any other common codecs, and non-codec formats: */
for (x = 1;
x <= ((ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO);
x <<= 1) {
Kevin P. Fleming
committed
if (!(capability & x))
continue;
if (alreadysent & x)
continue;
if (x <= AST_FORMAT_MAX_AUDIO)
add_codec_to_sdp(p, x, 8000,
&m_audio_next, &m_audio_left,
&a_audio_next, &a_audio_left,
debug);
else
add_codec_to_sdp(p, x, 90000,
&m_video_next, &m_video_left,
&a_video_next, &a_video_left,
debug);
Kevin P. Fleming
committed
for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
Kevin P. Fleming
committed
if (!(p->noncodeccapability & x))
continue;
add_noncodec_to_sdp(p, x, 8000,
&m_audio_next, &m_audio_left,
&a_audio_next, &a_audio_left,
debug);
Kevin P. Fleming
committed
if(!ast_internal_timing_enabled(p->owner))
ast_build_string(&a_audio_next, &a_audio_left, "a=silenceSupp:off - - - -\r\n");
Kevin P. Fleming
committed
if ((m_audio_left < 2) || (m_video_left < 2) || (a_audio_left == 0) || (a_video_left == 0))
ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
Kevin P. Fleming
committed
ast_build_string(&m_audio_next, &m_audio_left, "\r\n");
ast_build_string(&m_video_next, &m_video_left, "\r\n");
len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m_audio) + strlen(a_audio);
if ((p->vrtp) &&
(!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
(capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
Kevin P. Fleming
committed
add_header(resp, "Content-Type", "application/sdp");
add_header_contentLength(resp, len);
if ((p->vrtp) &&
(!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
(capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
Kevin P. Fleming
committed
add_line(resp, m_audio);
add_line(resp, a_audio);
if ((p->vrtp) &&
(!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
(capability & VIDEO_CODEC_MASK)) { /* only if video response is appropriate */
Kevin P. Fleming
committed
add_line(resp, m_video);
add_line(resp, a_video);
Kevin P. Fleming
committed
/* Update lastrtprx when we send our SDP */
time(&p->lastrtprx);
Kevin P. Fleming
committed
/*! \brief copy SIP request (mostly used to save request for responses) */
static void copy_request(struct sip_request *dst, struct sip_request *src)
{
long offset;
int x;
offset = ((void *)dst) - ((void *)src);
/* First copy stuff */
memcpy(dst, src, sizeof(*dst));
/* Now fix pointer arithmetic */
for (x=0; x < src->headers; x++)
for (x=0; x < src->lines; x++)
/*! \brief Used for 200 OK and 183 early media */
static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, enum xmittype reliable)
Kevin P. Fleming
committed
if (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1) {
ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
return -1;
}
if (p->rtp) {
Olle Johansson
committed
try_suggested_sip_codec(p);
add_sdp(&resp, p);
} else {
ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid);
}
return send_response(p, &resp, reliable, seqno);
/*! \brief Parse first line of incoming SIP request */
static int determine_firstline_parts( struct sip_request *req )
{
char *e, *cmd;
int len;
cmd = ast_skip_blanks(req->header[0]);
if (!*cmd)
e = ast_skip_nonblanks(cmd);
/* Get the command */
if (*e)
*e++ = '\0';
e = ast_skip_blanks(e);
if ( !*e )
if ( !strcasecmp(cmd, "SIP/2.0") ) {
/* We have a response */
req->rlPart2 = e;
len = strlen( req->rlPart2 );
ast_trim_blanks(e);
req->rlPart2 = e; /* URI */
if ( ( e= strrchr( req->rlPart2, 'S' ) ) == NULL ) {
/* XXX maybe trim_blanks() ? */
} else {
*(++e)= '\0';
}
}
return 1;
/*! \brief Transmit reinvite with SDP
\note A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
INVITE that opened the SIP dialogue
We reinvite so that the audio stream (RTP) go directly between
the SIP UAs. SIP Signalling stays with * in the path.
*/
static int transmit_reinvite_with_sdp(struct sip_pvt *p)
struct sip_request req;
if (ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE))
reqprep(&req, p, SIP_UPDATE, 0, 1);
Mark Spencer
committed
else
reqprep(&req, p, SIP_INVITE, 0, 1);
Mark Spencer
committed
Russell Bryant
committed
if (sipdebug)
add_header(&req, "X-asterisk-info", "SIP re-invite (RTP bridge)");
if (recordhistory)
append_history(p, "%s", "Re-invite sent");
add_sdp(&req, p);
/* Use this as the basis */
copy_request(&p->initreq, &req);
parse_request(&p->initreq);
if (sip_debug_test_pvt(p))
ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
p->lastinvite = p->ocseq;
ast_set_flag(&p->flags[0], SIP_OUTGOING);
return send_request(p, &req, 1, p->ocseq);
/*! \brief Check Contact: URI of SIP message */
static void extract_uri(struct sip_pvt *p, struct sip_request *req)
{
char stripped[256];
Kevin P. Fleming
committed
ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
c = get_in_brackets(stripped);
n = strchr(c, ';');
if (n)
*n = '\0';
if (!ast_strlen_zero(c))
ast_string_field_set(p, uri, c);
/*! \brief Build contact header - the contact header we send out */
static void build_contact(struct sip_pvt *p)
{
char iabuf[INET_ADDRSTRLEN];
/* Construct Contact: header */
if (ourport != 5060) /* Needs to be 5060, according to the RFC */
ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport);
ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip));
/*! \brief Build the Remote Party-ID & From using callingpres options */
Kevin P. Fleming
committed
static void build_rpid(struct sip_pvt *p)
{
const char *privacy=NULL;
const char *screen=NULL;
Kevin P. Fleming
committed
char buf[256];
const char *clid = default_callerid;
const char *clin = NULL;
char iabuf[INET_ADDRSTRLEN];
const char *fromdomain;
if (!ast_strlen_zero(p->rpid) || !ast_strlen_zero(p->rpid_from))
Kevin P. Fleming
committed
return;
if (p->owner && p->owner->cid.cid_num)
clid = p->owner->cid.cid_num;
if (p->owner && p->owner->cid.cid_name)
clin = p->owner->cid.cid_name;
if (ast_strlen_zero(clin))
Kevin P. Fleming
committed
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
clin = clid;
switch (p->callingpres) {
case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
privacy = "off";
screen = "no";
break;
case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
privacy = "off";
screen = "pass";
break;
case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
privacy = "off";
screen = "fail";
break;
case AST_PRES_ALLOWED_NETWORK_NUMBER:
privacy = "off";
screen = "yes";
break;
case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
privacy = "full";
screen = "no";
break;
case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
privacy = "full";
screen = "pass";
break;
case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
privacy = "full";
screen = "fail";
break;
case AST_PRES_PROHIB_NETWORK_NUMBER:
privacy = "full";
Kevin P. Fleming
committed
break;
case AST_PRES_NUMBER_NOT_AVAILABLE:
Kevin P. Fleming
committed
break;
default:
ast_log(LOG_WARNING, "Unsupported callingpres (%d)\n", p->callingpres);
if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)
privacy = "full";
else
privacy = "off";
screen = "no";
break;
}
fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip));
Kevin P. Fleming
committed
snprintf(buf, sizeof(buf), "\"%s\" <sip:%s@%s>", clin, clid, fromdomain);
if (send_pres_tags)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";privacy=%s;screen=%s", privacy, screen);
ast_string_field_set(p, rpid, buf);
Kevin P. Fleming
committed
ast_string_field_build(p, rpid_from, "\"%s\" <sip:%s@%s>;tag=%s", clin,
fromdomain, p->tag);
Kevin P. Fleming
committed
}
/*! \brief Initiate new SIP request to peer/user */
static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod)
char invite_buf[256] = "";
char *invite = invite_buf;
size_t invite_max = sizeof(invite_buf);
char tmp[BUFSIZ/2];
char tmp2[BUFSIZ/2];
char iabuf[INET_ADDRSTRLEN];
const char *l = NULL, *n = NULL;
int x;
char urioptions[256]="";
if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
/* Test p->username against allowed characters in AST_DIGIT_ANY
If it matches the allowed characters list, then sipuser = ";user=phone"
If not, then sipuser = ""
*/
/* + is allowed in first position in a tel: uri */
if (p->username && p->username[0] == '+')
for (; x < strlen(p->username); x++) {
if (!strchr(AST_DIGIT_ANYNUM, p->username[x])) {
/* If we have only digits, add ;user=phone to the uri */
if (onlydigits)
strcpy(urioptions, ";user=phone");
snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text);
if (p->owner) {
l = p->owner->cid.cid_num;
n = p->owner->cid.cid_name;
}
/* if we are not sending RPID and user wants his callerid restricted */
if (!ast_test_flag(&p->flags[0], SIP_SENDRPID) &&
((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)) {
Martin Pycko
committed
l = CALLERID_UNKNOWN;
n = l;
}
if (!l)
l = default_callerid;
if (ast_strlen_zero(n))
Mark Spencer
committed
/* Allow user to be overridden */
if (!ast_strlen_zero(p->fromuser))
Mark Spencer
committed
l = p->fromuser;
else /* Save for any further attempts */
ast_string_field_set(p, fromuser, l);
/* Allow user to be overridden */
if (!ast_strlen_zero(p->fromname))
n = p->fromname;
else /* Save for any further attempts */
ast_string_field_set(p, fromname, n);
if (pedanticsipchecking) {
ast_uri_encode(n, tmp, sizeof(tmp), 0);
n = tmp;
ast_uri_encode(l, tmp2, sizeof(tmp2), 0);
l = tmp2;
}
if ((ourport != 5060) && ast_strlen_zero(p->fromdomain)) /* Needs to be 5060 */
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip)), ourport, p->tag);
Mark Spencer
committed
else
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip)), p->tag);
/* If we're calling a registered SIP peer, use the fullcontact to dial to the peer */
if (!ast_strlen_zero(p->fullcontact)) {
/* If we have full contact, trust it */
ast_build_string(&invite, &invite_max, "%s", p->fullcontact);
/* Otherwise, use the username while waiting for registration */
ast_build_string(&invite, &invite_max, "sip:");
if (!ast_strlen_zero(p->username)) {
n = p->username;
if (pedanticsipchecking) {
ast_uri_encode(n, tmp, sizeof(tmp), 0);
n = tmp;
}
ast_build_string(&invite, &invite_max, "%s@", n);
}
ast_build_string(&invite, &invite_max, "%s", p->tohost);
if (ntohs(p->sa.sin_port) != 5060) /* Needs to be 5060 */
ast_build_string(&invite, &invite_max, ":%d", ntohs(p->sa.sin_port));
ast_build_string(&invite, &invite_max, "%s", urioptions);
/* If custom URI options have been provided, append them */
if (p->options && p->options->uri_options)
ast_build_string(&invite, &invite_max, ";%s", p->options->uri_options);
ast_string_field_set(p, uri, invite_buf);
if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) {
/* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */
snprintf(to, sizeof(to), "<sip:%s>;tag=%s", p->uri, p->theirtag);
} else if (p->options && p->options->vxml_url) {
/* If there is a VXML URL append it to the SIP URL */
snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
} else {
snprintf(to, sizeof(to), "<%s>", p->uri);
memset(req, 0, sizeof(struct sip_request));
init_req(req, sipmethod, p->uri);
snprintf(tmp, sizeof(tmp), "%d %s", ++p->ocseq, sip_methods[sipmethod].text);
/* SLD: FIXME?: do Route: here too? I think not cos this is the first request.
* OTOH, then we won't have anything in p->route anyway */
Kevin P. Fleming
committed
/* Build Remote Party-ID and From */
if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) {
Kevin P. Fleming
committed
build_rpid(p);
Kevin P. Fleming
committed
add_header(req, "From", p->rpid_from);