|
|
|
@ -143,6 +143,11 @@ struct sip_request {
|
|
|
|
|
|
|
|
|
|
struct sip_pkt;
|
|
|
|
|
|
|
|
|
|
struct sip_route {
|
|
|
|
|
struct sip_route *next;
|
|
|
|
|
char hop[0];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct sip_pvt {
|
|
|
|
|
pthread_mutex_t lock; /* Channel private lock */
|
|
|
|
|
char callid[80]; /* Global CallID */
|
|
|
|
@ -171,8 +176,7 @@ static struct sip_pvt {
|
|
|
|
|
char referred_by[AST_MAX_EXTENSION];/* Place to store REFERRED-BY extension */
|
|
|
|
|
char refer_contact[AST_MAX_EXTENSION];/* Place to store Contact info from a REFER extension */
|
|
|
|
|
struct sip_pvt *refer_call; /* Call we are referring */
|
|
|
|
|
char record_route[256];
|
|
|
|
|
char record_route_info[256];
|
|
|
|
|
struct sip_route *route; /* Head of linked list of routing steps (fm Record-Route) */
|
|
|
|
|
char remote_party_id[256];
|
|
|
|
|
char context[AST_MAX_EXTENSION];
|
|
|
|
|
char language[MAX_LANGUAGE];
|
|
|
|
@ -322,6 +326,7 @@ static int transmit_info_with_digit(struct sip_pvt *p, char digit);
|
|
|
|
|
static int transmit_message_with_text(struct sip_pvt *p, char *text);
|
|
|
|
|
static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req);
|
|
|
|
|
char *getsipuri(char *header);
|
|
|
|
|
static void free_old_route(struct sip_route *route);
|
|
|
|
|
|
|
|
|
|
static int __sip_xmit(struct sip_pvt *p, char *data, int len)
|
|
|
|
|
{
|
|
|
|
@ -714,6 +719,10 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner)
|
|
|
|
|
if (p->rtp) {
|
|
|
|
|
ast_rtp_destroy(p->rtp);
|
|
|
|
|
}
|
|
|
|
|
if (p->route) {
|
|
|
|
|
free_old_route(p->route);
|
|
|
|
|
p->route = NULL;
|
|
|
|
|
}
|
|
|
|
|
/* Unlink us from the owner if we have one */
|
|
|
|
|
if (p->owner) {
|
|
|
|
|
if (lockowner)
|
|
|
|
@ -1630,7 +1639,6 @@ static int copy_header(struct sip_request *req, struct sip_request *orig, char *
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
static int copy_all_header(struct sip_request *req, struct sip_request *orig, char *field)
|
|
|
|
|
{
|
|
|
|
|
char *tmp;
|
|
|
|
@ -1645,13 +1653,9 @@ static int copy_all_header(struct sip_request *req, struct sip_request *orig, ch
|
|
|
|
|
} else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!copied) {
|
|
|
|
|
ast_log(LOG_NOTICE, "No field '%s' present to copy\n", field);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
return copied ? 0 : -1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct sip_request *orig, char *field)
|
|
|
|
|
{
|
|
|
|
|
char *tmp;
|
|
|
|
@ -1662,6 +1666,8 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct s
|
|
|
|
|
tmp = __get_header(orig, field, &start);
|
|
|
|
|
if (strlen(tmp)) {
|
|
|
|
|
if (!copied && p->nat) {
|
|
|
|
|
/* SLD: FIXME: Nice try, but the received= should not have a port */
|
|
|
|
|
/* SLD: FIXME: See RFC2543 BNF in Section 6.40.5 */
|
|
|
|
|
if (ntohs(p->recv.sin_port) != DEFAULT_SIP_PORT)
|
|
|
|
|
snprintf(new, sizeof(new), "%s;received=%s:%d", tmp, inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
|
|
|
|
|
else
|
|
|
|
@ -1682,6 +1688,82 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct s
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add Route: header into request per learned route */
|
|
|
|
|
static void add_route(struct sip_request *req, struct sip_route *route)
|
|
|
|
|
{
|
|
|
|
|
char r[256], *p;
|
|
|
|
|
int n, rem = 255; /* sizeof(r)-1: Room for terminating 0 */
|
|
|
|
|
|
|
|
|
|
if (!route) return;
|
|
|
|
|
|
|
|
|
|
p = r;
|
|
|
|
|
while (route) {
|
|
|
|
|
n = strlen(route->hop);
|
|
|
|
|
if ((n+3)>rem) break;
|
|
|
|
|
if (p != r) {
|
|
|
|
|
*p++ = ',';
|
|
|
|
|
--rem;
|
|
|
|
|
}
|
|
|
|
|
*p++ = '<';
|
|
|
|
|
strcpy(p, route->hop); p += n;
|
|
|
|
|
*p++ = '>';
|
|
|
|
|
rem -= (n+2);
|
|
|
|
|
route = route->next;
|
|
|
|
|
}
|
|
|
|
|
*p = '\0';
|
|
|
|
|
add_header(req, "Route", r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void set_destination(struct sip_pvt *p, char *uri)
|
|
|
|
|
{
|
|
|
|
|
char *h, *maddr, hostname[256];
|
|
|
|
|
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][;...] */
|
|
|
|
|
|
|
|
|
|
if (sipdebug)
|
|
|
|
|
ast_verbose("set_destination: Parsing <%s> for address/port to send to\n", uri);
|
|
|
|
|
|
|
|
|
|
h = strchr(uri, '@');
|
|
|
|
|
if (!h) {
|
|
|
|
|
ast_log(LOG_WARNING, "set_destination: Can't parse sip URI '%s'\n", uri);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
++h;
|
|
|
|
|
hn = strcspn(h, ":;>");
|
|
|
|
|
hostname[255] = '\0';
|
|
|
|
|
strncpy(hostname, h, (hn>255)?255:hn);
|
|
|
|
|
h+=hn;
|
|
|
|
|
/* Is "port" present? if not default to 5060 */
|
|
|
|
|
if (*h == ':') {
|
|
|
|
|
/* Parse port */
|
|
|
|
|
++h;
|
|
|
|
|
port = strtol(h, &h, 10);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
port = 5060;
|
|
|
|
|
|
|
|
|
|
/* Got the hostname:port - but maybe there's a ";maddr=" to override address? */
|
|
|
|
|
maddr = strstr(h, ";maddr=");
|
|
|
|
|
if (maddr) {
|
|
|
|
|
maddr += 7;
|
|
|
|
|
hn = strspn(maddr, "0123456789.");
|
|
|
|
|
strncpy(hostname, maddr, (hn>255)?255:hn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hp = gethostbyname(hostname);
|
|
|
|
|
if (hp == NULL) {
|
|
|
|
|
ast_log(LOG_WARNING, "Can't find address for host '%s'\n", h);
|
|
|
|
|
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);
|
|
|
|
|
ast_verbose("set_destination: set destination to %s, port %d\n", inet_ntoa(p->sa.sin_addr), port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int init_resp(struct sip_request *req, char *resp, struct sip_request *orig)
|
|
|
|
|
{
|
|
|
|
|
/* Initialize a response */
|
|
|
|
@ -1726,9 +1808,11 @@ static void append_contact(struct sip_request *req, struct sip_pvt *p)
|
|
|
|
|
else
|
|
|
|
|
from = get_header(req, "To");
|
|
|
|
|
strncpy(contact2, from, sizeof(contact2)-1);
|
|
|
|
|
c = ditch_braces(contact2);
|
|
|
|
|
snprintf(contact, sizeof(contact), "<%s>", c);
|
|
|
|
|
add_header(req, "Contact", contact);
|
|
|
|
|
if (strlen(contact2)) {
|
|
|
|
|
c = ditch_braces(contact2);
|
|
|
|
|
snprintf(contact, sizeof(contact), "<%s>", c);
|
|
|
|
|
add_header(req, "Contact", contact);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, struct sip_request *req)
|
|
|
|
@ -1737,10 +1821,9 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
|
|
|
|
|
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");
|
|
|
|
|
copy_header(resp, req, "From");
|
|
|
|
|
ot = get_header(req, "To");
|
|
|
|
|
if (strlen(get_header(req, "Record-Route")))
|
|
|
|
|
copy_header(resp, req, "Record-Route");
|
|
|
|
|
if (!strstr(ot, "tag=")) {
|
|
|
|
|
/* Add the proper tag if we don't have it already. If they have specified
|
|
|
|
|
their tag, use it. Otherwise, use our own tag */
|
|
|
|
@ -1820,6 +1903,10 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int in
|
|
|
|
|
snprintf(tmp, sizeof(tmp), "%d %s", p->ocseq, msg);
|
|
|
|
|
|
|
|
|
|
add_header(req, "Via", p->via);
|
|
|
|
|
if (p->route) {
|
|
|
|
|
set_destination(p, p->route->hop);
|
|
|
|
|
add_route(req, p->route->next);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ot = get_header(orig, "To");
|
|
|
|
|
of = get_header(orig, "From");
|
|
|
|
@ -2113,6 +2200,8 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
|
|
|
|
|
snprintf(tmp, sizeof(tmp), "%d %s", ++p->ocseq, cmd);
|
|
|
|
|
|
|
|
|
|
add_header(req, "Via", p->via);
|
|
|
|
|
/* 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 */
|
|
|
|
|
add_header(req, "From", from);
|
|
|
|
|
{
|
|
|
|
|
char contact2[256] ="", *c, contact[256];
|
|
|
|
@ -2411,6 +2500,111 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void free_old_route(struct sip_route *route)
|
|
|
|
|
{
|
|
|
|
|
struct sip_route *next;
|
|
|
|
|
while (route) {
|
|
|
|
|
next = route->next;
|
|
|
|
|
free(route);
|
|
|
|
|
route = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void list_route(struct sip_route *route)
|
|
|
|
|
{
|
|
|
|
|
if (!route) {
|
|
|
|
|
ast_verbose("list_route: no route\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while (route) {
|
|
|
|
|
ast_verbose("list_route: hop: <%s>\n", route->hop);
|
|
|
|
|
route = route->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards)
|
|
|
|
|
{
|
|
|
|
|
struct sip_route *thishop, *head, *tail;
|
|
|
|
|
int start = 0;
|
|
|
|
|
int len;
|
|
|
|
|
char *rr, *contact, *c;
|
|
|
|
|
|
|
|
|
|
if (p->route) {
|
|
|
|
|
free_old_route(p->route);
|
|
|
|
|
p->route = NULL;
|
|
|
|
|
}
|
|
|
|
|
/* We build up head, then assign it to p->route when we're done */
|
|
|
|
|
head = NULL; tail = head;
|
|
|
|
|
/* 1st pass through all the hops in any Record-Route headers */
|
|
|
|
|
for (;;) {
|
|
|
|
|
/* Each Record-Route header */
|
|
|
|
|
rr = __get_header(req, "Record-Route", &start);
|
|
|
|
|
/*ast_verbose("Record-Route: %s\n", rr);*/
|
|
|
|
|
if (*rr == '\0') break;
|
|
|
|
|
for (;;) {
|
|
|
|
|
/* Each route entry */
|
|
|
|
|
/* Find < */
|
|
|
|
|
rr = strchr(rr, '<');
|
|
|
|
|
if (!rr) break; /* No more hops */
|
|
|
|
|
++rr;
|
|
|
|
|
len = strcspn(rr, ">");
|
|
|
|
|
/* Make a struct route */
|
|
|
|
|
thishop = (struct sip_route *)malloc(sizeof(struct sip_route)+len+1);
|
|
|
|
|
if (thishop) {
|
|
|
|
|
strncpy(thishop->hop, rr, len);
|
|
|
|
|
thishop->hop[len] = '\0';
|
|
|
|
|
ast_verbose("build_route: Record-Route hop: <%s>\n", thishop->hop);
|
|
|
|
|
/* Link in */
|
|
|
|
|
if (backwards) {
|
|
|
|
|
/* Link in at head so they end up in reverse order */
|
|
|
|
|
thishop->next = head;
|
|
|
|
|
head = thishop;
|
|
|
|
|
/* If this was the first then it'll be the tail */
|
|
|
|
|
if (!tail) tail = thishop;
|
|
|
|
|
} else {
|
|
|
|
|
/* Link in at the end */
|
|
|
|
|
if (tail)
|
|
|
|
|
tail->next = thishop;
|
|
|
|
|
else
|
|
|
|
|
head = thishop;
|
|
|
|
|
tail = thishop;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rr += len+1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* 2nd append the Contact: if there is one */
|
|
|
|
|
/* Can be multiple Contact headers, comma separated values - we just take the first */
|
|
|
|
|
contact = get_header(req, "Contact");
|
|
|
|
|
if (strlen(contact)) {
|
|
|
|
|
ast_log(LOG_DEBUG, "build_route: Contact hop: %s\n", contact);
|
|
|
|
|
/* Look for <: delimited address */
|
|
|
|
|
c = strchr(contact, '<');
|
|
|
|
|
if (c) {
|
|
|
|
|
/* Take to > */
|
|
|
|
|
++c;
|
|
|
|
|
len = strcspn(c, ">");
|
|
|
|
|
} else {
|
|
|
|
|
/* No <> - just take the lot */
|
|
|
|
|
c = contact; len = strlen(contact);
|
|
|
|
|
}
|
|
|
|
|
thishop = (struct sip_route *)malloc(sizeof(struct sip_route)+len+1);
|
|
|
|
|
strncpy(thishop->hop, c, len);
|
|
|
|
|
thishop->hop[len] = '\0';
|
|
|
|
|
/* Goes at the end */
|
|
|
|
|
if (tail)
|
|
|
|
|
tail->next = thishop;
|
|
|
|
|
else
|
|
|
|
|
head = thishop;
|
|
|
|
|
}
|
|
|
|
|
/* Store as new route */
|
|
|
|
|
p->route = head;
|
|
|
|
|
|
|
|
|
|
/* For debugging dump what we ended up with */
|
|
|
|
|
if (sipdebug)
|
|
|
|
|
list_route(p->route);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void md5_hash(char *output, char *input)
|
|
|
|
|
{
|
|
|
|
|
struct MD5Context md5;
|
|
|
|
@ -3357,6 +3551,8 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
|
|
|
|
|
} else if (!strcasecmp(msg, "INVITE")) {
|
|
|
|
|
if (strlen(get_header(req, "Content-Type")))
|
|
|
|
|
process_sdp(p, req);
|
|
|
|
|
/* Save Record-Route for any later requests we make on this dialogue */
|
|
|
|
|
build_route(p, req, 1);
|
|
|
|
|
if (p->owner) {
|
|
|
|
|
if (p->owner->_state != AST_STATE_UP) {
|
|
|
|
|
ast_setstate(p->owner, AST_STATE_UP);
|
|
|
|
@ -3700,6 +3896,8 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
|
|
|
|
|
p->tag = rand();
|
|
|
|
|
/* First invitation */
|
|
|
|
|
c = sip_new(p, AST_STATE_DOWN, strlen(p->username) ? p->username : NULL);
|
|
|
|
|
/* Save Record-Route for any later requests we make on this dialogue */
|
|
|
|
|
build_route(p, req, 0);
|
|
|
|
|
if (c) {
|
|
|
|
|
/* Pre-lock the call */
|
|
|
|
|
ast_pthread_mutex_lock(&c->lock);
|
|
|
|
|