Fix contact header, don't transmit BYE when INVITE are still outstanding

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@765 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer 2003-04-07 06:12:19 +00:00
parent 1680ccf66c
commit 5c18d407c5
2 changed files with 70 additions and 52 deletions

View File

@ -1,3 +1,4 @@
-- Management interface improvements
-- Add "hint" support
-- Improve call forwarding using new "Local" channel driver.
-- Add "Local" channel

View File

@ -193,6 +193,8 @@ static struct sip_pvt {
char realm[256]; /* Authorization realm */
char nonce[256]; /* Authorization nonce */
int amaflags; /* AMA Flags */
int pendinginvite; /* Any pending invite */
int pendingbye; /* Need to send bye after we ack? */
struct sip_request initreq; /* Initial request */
int maxtime; /* Max time for first response */
@ -420,6 +422,10 @@ static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *dat
pkt->next = p->packets;
p->packets = pkt;
__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
if (!strncasecmp(pkt->data, "INVITE", 6)) {
/* Note this is a pending invite */
p->pendinginvite = seqno;
}
return 0;
}
@ -457,9 +463,15 @@ static int __sip_ack(struct sip_pvt *p, int seqno, int resp)
{
struct sip_pkt *cur, *prev = NULL;
int res = -1;
int resetinvite = 0;
cur = p->packets;
while(cur) {
if ((cur->seqno == seqno) && (cur->resp == resp)) {
if (!resp && (seqno == p->pendinginvite)) {
ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite);
p->pendinginvite = 0;
resetinvite = 1;
}
/* this is our baby */
if (prev)
prev->next = cur->next;
@ -905,7 +917,7 @@ static int sip_hangup(struct ast_channel *ast)
if (!p->alreadygone && strlen(p->initreq.data)) {
if (needcancel) {
if (p->outgoing) {
transmit_request_with_auth(p, "CANCEL", 0, 1);
transmit_request_with_auth(p, "CANCEL", p->ocseq, 1);
/* Actually don't destroy us yet, wait for the 487 on our original
INVITE, but do set an autodestruct just in case. */
p->needdestroy = 0;
@ -913,8 +925,13 @@ static int sip_hangup(struct ast_channel *ast)
} else
transmit_response_reliable(p, "403 Forbidden", &p->initreq);
} else {
/* Send a hangup */
transmit_request_with_auth(p, "BYE", 1, 1);
if (!p->pendinginvite) {
/* Send a hangup */
transmit_request_with_auth(p, "BYE", 0, 1);
} else {
/* Note we will need a BYE when this all settles out */
p->pendingbye = 1;
}
}
}
ast_pthread_mutex_unlock(&p->lock);
@ -1838,7 +1855,7 @@ static int init_req(struct sip_request *req, char *resp, char *recip)
static void append_contact(struct sip_request *req, struct sip_pvt *p)
{
/* Add contact header */
char contact2[256] ="", *c, contact[256];
char contact2[256] ="", *c, *c2, contact[256];
char *from;
if (p->outgoing)
from = get_header(req, "From");
@ -1847,6 +1864,8 @@ static void append_contact(struct sip_request *req, struct sip_pvt *p)
strncpy(contact2, from, sizeof(contact2)-1);
if (strlen(contact2)) {
c = ditch_braces(contact2);
c2 = strchr(c, ';');
if (c2) *c2 = '\0';
snprintf(contact, sizeof(contact), "<%s>", c);
add_header(req, "Contact", contact);
}
@ -1864,10 +1883,10 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
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 */
if (strlen(p->theirtag))
if (strlen(p->theirtag) && p->outgoing)
snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
else if (p->tag)
snprintf(newto, sizeof(newto), "%s;tag=%08x", ot, p->tag);
else if (p->tag && !p->outgoing)
snprintf(newto, sizeof(newto), "%s;tag=as%08x", ot, p->tag);
else
strncpy(newto, ot, sizeof(newto) - 1);
ot = newto;
@ -1907,7 +1926,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
return 0;
}
static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int inc)
static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int seqno)
{
struct sip_request *orig = &p->initreq;
char stripped[80] ="";
@ -1918,8 +1937,10 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int in
memset(req, 0, sizeof(struct sip_request));
if (inc)
if (!seqno) {
p->ocseq++;
seqno = p->ocseq;
}
if (p->outgoing)
strncpy(stripped, get_header(orig, "To"), sizeof(stripped) - 1);
@ -1932,12 +1953,15 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int in
else
c = stripped;
n = strchr(c, '>');
if (n)
*n = '\0';
n = strchr(c, ';');
if (n)
*n = '\0';
init_req(req, msg, c);
snprintf(tmp, sizeof(tmp), "%d %s", p->ocseq, msg);
snprintf(tmp, sizeof(tmp), "%d %s", seqno, msg);
add_header(req, "Via", p->via);
if (p->route) {
@ -1956,7 +1980,7 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int in
if (p->outgoing && strlen(p->theirtag))
snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
else if (!p->outgoing)
snprintf(newto, sizeof(newto), "%s;tag=%08x", ot, p->tag);
snprintf(newto, sizeof(newto), "%s;tag=as%08x", ot, p->tag);
else
snprintf(newto, sizeof(newto), "%s", ot);
ot = newto;
@ -2208,13 +2232,18 @@ static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_r
static int transmit_reinvite_with_sdp(struct sip_pvt *p, struct ast_rtp *rtp)
{
struct sip_request resp;
struct sip_request req;
if (p->canreinvite == REINVITE_UPDATE)
reqprep(&resp, p, "UPDATE", 1);
reqprep(&req, p, "UPDATE", 0);
else
reqprep(&resp, p, "INVITE", 1);
add_sdp(&resp, p, rtp);
return send_request(p, &resp, 1, p->ocseq);
reqprep(&req, p, "INVITE", 0);
add_sdp(&req, p, rtp);
/* Use this as the basis */
copy_request(&p->initreq, &req);
parse(&p->initreq);
p->lastinvite = p->ocseq;
p->outgoing = 1;
return send_request(p, &req, 1, p->ocseq);
}
static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, char *vxml_url)
@ -2236,9 +2265,9 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
if (!n)
n = l;
if (ourport != 5060)
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%08x", n, l, strlen(p->fromdomain) ? p->fromdomain : inet_ntoa(p->ourip), ourport, p->tag);
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=as%08x", n, l, strlen(p->fromdomain) ? p->fromdomain : inet_ntoa(p->ourip), ourport, p->tag);
else
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%08x", n, l, strlen(p->fromdomain) ? p->fromdomain : inet_ntoa(p->ourip), p->tag);
snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=as%08x", n, l, strlen(p->fromdomain) ? p->fromdomain : inet_ntoa(p->ourip), p->tag);
if (strlen(p->username)) {
if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) {
@ -2325,7 +2354,7 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full)
}
mfrom = c;
reqprep(&req, p, "NOTIFY", 1);
reqprep(&req, p, "NOTIFY", 0);
if (p->subscribed == 1) {
strncpy(to, get_header(&p->initreq, "To"), sizeof(to)-1);
@ -2487,8 +2516,8 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth)
ast_log(LOG_NOTICE, "Scheduled a timeout # %d\n", r->timeout);
}
snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%08x", r->username, inet_ntoa(r->addr.sin_addr), p->tag);
snprintf(to, sizeof(to), "<sip:%s@%s>;tag=%08x", r->username, inet_ntoa(r->addr.sin_addr), p->tag);
snprintf(from, sizeof(from), "<sip:%s@%s>;tag=as%08x", r->username, inet_ntoa(r->addr.sin_addr), p->tag);
snprintf(to, sizeof(to), "<sip:%s@%s>;tag=as%08x", r->username, inet_ntoa(r->addr.sin_addr), p->tag);
snprintf(addr, sizeof(addr), "sip:%s", inet_ntoa(r->addr.sin_addr));
@ -2525,7 +2554,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth)
static int transmit_message_with_text(struct sip_pvt *p, char *text)
{
struct sip_request req;
reqprep(&req, p, "MESSAGE", 1);
reqprep(&req, p, "MESSAGE", 0);
add_text(&req, text);
return send_request(p, &req, 1, p->ocseq);
}
@ -2533,24 +2562,24 @@ static int transmit_message_with_text(struct sip_pvt *p, char *text)
static int transmit_info_with_digit(struct sip_pvt *p, char digit)
{
struct sip_request req;
reqprep(&req, p, "INFO", 1);
reqprep(&req, p, "INFO", 0);
add_digit(&req, digit);
return send_request(p, &req, 1, p->ocseq);
}
static int transmit_request(struct sip_pvt *p, char *msg, int inc, int reliable)
static int transmit_request(struct sip_pvt *p, char *msg, int seqno, int reliable)
{
struct sip_request resp;
reqprep(&resp, p, msg, inc);
reqprep(&resp, p, msg, seqno);
add_header(&resp, "Content-Length", "0");
add_blank_header(&resp);
return send_request(p, &resp, reliable, p->ocseq);
return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
}
static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int reliable)
static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int seqno, int reliable)
{
struct sip_request resp;
reqprep(&resp, p, msg, inc);
reqprep(&resp, p, msg, seqno);
if (*p->realm)
{
char digest[256];
@ -2561,7 +2590,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int
add_header(&resp, "Content-Length", "0");
add_blank_header(&resp);
return send_request(p, &resp, reliable, p->ocseq);
return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
}
static int expire_register(void *data)
@ -3705,7 +3734,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
if (peer->pokeexpire > -1)
ast_sched_del(sched, peer->pokeexpire);
if (!strcasecmp(msg, "INVITE"))
transmit_request(p, "ACK", 0, 0);
transmit_request(p, "ACK", seqno, 0);
p->needdestroy = 1;
/* Try again eventually */
if ((peer->lastms < 0) || (peer->lastms > peer->maxms))
@ -3772,7 +3801,12 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
ast_queue_control(p->owner, AST_CONTROL_ANSWER, 0);
}
}
transmit_request(p, "ACK", 0, 0);
transmit_request(p, "ACK", seqno, 0);
/* Go ahead and send bye at this point */
if (p->pendingbye) {
transmit_request(p, "BYE", 0, 1);
p->needdestroy = 1;
}
} else if (!strcasecmp(msg, "REGISTER")) {
/* char *exp; */
int expires;
@ -3795,30 +3829,13 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
}
break;
case 401: /* Not authorized on REGISTER */
/* XXX: Do I need to ACK the 401?
transmit_request(p, "ACK", 0);
*/
do_register_auth(p, req);
break;
case 407:
/* First we ACK */
transmit_request(p, "ACK", 0, 0);
transmit_request(p, "ACK", seqno, 0);
/* Then we AUTH */
do_proxy_auth(p, req);
/* This is just a hack to kill the channel while testing */
/*
p->alreadygone = 1;
if (p->rtp) {
rtp = p->rtp;
p->rtp = NULL;
ast_rtp_destroy(rtp);
}
if (p->owner)
ast_queue_hangup(p->owner,0);
transmit_request(p,"ACK",0);
sip_destroy(p);
p = NULL;
*/
break;
default:
if ((resp >= 300) && (resp < 700)) {
@ -3855,7 +3872,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
ast_queue_hangup(p->owner, 0);
break;
}
transmit_request(p, "ACK", 0, 0);
transmit_request(p, "ACK", seqno, 0);
p->alreadygone = 1;
if (!p->owner)
p->needdestroy = 1;
@ -3872,7 +3889,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
switch(resp) {
case 200:
if (!strcasecmp(msg, "INVITE") || !strcasecmp(msg, "REGISTER") )
transmit_request(p, "ACK", 0, 0);
transmit_request(p, "ACK", seqno, 0);
break;
}
}
@ -4187,7 +4204,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
}
}
/* Always increment on a BYE */
transmit_request_with_auth(p, "BYE", 1, 1);
transmit_request_with_auth(p, "BYE", 0, 1);
p->alreadygone = 1;
}
} else if (!strcasecmp(cmd, "CANCEL")) {