Fix contact header, don't transmit BYE when INVITE are still outstanding
authorMark Spencer <markster@digium.com>
Mon, 7 Apr 2003 06:12:19 +0000 (06:12 +0000)
committerMark Spencer <markster@digium.com>
Mon, 7 Apr 2003 06:12:19 +0000 (06:12 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@765 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
channels/chan_sip.c

diff --git a/CHANGES b/CHANGES
index 334c478..c8377ba 100755 (executable)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+ -- Management interface improvements
  -- Add "hint" support
  -- Improve call forwarding using new "Local" channel driver.
  -- Add "Local" channel
index e924d3a..4875200 100755 (executable)
@@ -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);
@@ -1934,10 +1955,13 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int in
        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")) {