Re-fix how local tag is generated when sending a 481 to an INVITE.
authorMark Michelson <mmichelson@digium.com>
Mon, 25 Jun 2012 19:26:31 +0000 (19:26 +0000)
committerMark Michelson <mmichelson@digium.com>
Mon, 25 Jun 2012 19:26:31 +0000 (19:26 +0000)
Match our local tag to whatever to-tag was sent in the initial INVITE.
Because the size of the to-tag may not fit in the buffer in the sip_pvt,
it has been changed to a string field.

(closes issue ASTERISK-19892)
reported by Walter Doekes

Review: https://reviewboard.asterisk.org/r/1977
........

Merged revisions 369352 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 369353 from http://svn.asterisk.org/svn/asterisk/branches/10

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@369367 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
channels/sip/include/sip.h

index 94154dc..5efbfbf 100644 (file)
@@ -1557,7 +1557,7 @@ static char *generate_random_string(char *buf, size_t size);
 static void build_callid_pvt(struct sip_pvt *pvt);
 static void change_callid_pvt(struct sip_pvt *pvt, const char *callid);
 static void build_callid_registry(struct sip_registry *reg, const struct ast_sockaddr *ourip, const char *fromdomain);
-static void make_our_tag(char *tagbuf, size_t len);
+static void make_our_tag(struct sip_pvt *pvt);
 static int add_header(struct sip_request *req, const char *var, const char *value);
 static int add_header_max_forwards(struct sip_pvt *dialog, struct sip_request *req);
 static int add_content(struct sip_request *req, const char *line);
@@ -7855,9 +7855,9 @@ static void build_callid_registry(struct sip_registry *reg, const struct ast_soc
 }
 
 /*! \brief Make our SIP dialog tag */
-static void make_our_tag(char *tagbuf, size_t len)
+static void make_our_tag(struct sip_pvt *pvt)
 {
-       snprintf(tagbuf, len, "as%08lx", ast_random());
+       ast_string_field_build(pvt, tag, "as%08lx", ast_random());
 }
 
 /*! \brief Allocate Session-Timers struct w/in dialog */
@@ -7999,7 +7999,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
        p->do_history = recordhistory;
 
        p->branch = ast_random();       
-       make_our_tag(p->tag, sizeof(p->tag));
+       make_our_tag(p);
        p->ocseq = INITIAL_CSEQ;
        p->allowed_methods = UINT_MAX;
 
@@ -8294,7 +8294,7 @@ static void forked_invite_init(struct sip_request *req, const char *new_theirtag
        memcpy(&p->flags, &original->flags, sizeof(p->flags));
        copy_request(&p->initreq, &original->initreq);
        ast_string_field_set(p, theirtag, new_theirtag);
-       ast_copy_string(p->tag, original->tag, sizeof(p->tag));
+       ast_string_field_set(p, tag, original->tag);
        ast_string_field_set(p, uri, original->uri);
        ast_string_field_set(p, our_contact, original->our_contact);
        ast_string_field_set(p, fullcontact, original->fullcontact);
@@ -11103,7 +11103,7 @@ static int transmit_response_using_temp(ast_string_field callid, struct ast_sock
        }
 
        p->branch = ast_random();
-       make_our_tag(p->tag, sizeof(p->tag));
+       make_our_tag(p);
        p->ocseq = INITIAL_CSEQ;
 
        if (useglobal_nat && addr) {
@@ -13970,7 +13970,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
                        return 0;
                } else {
                        p = dialog_ref(r->call, "getting a copy of the r->call dialog in transmit_register");
-                       make_our_tag(p->tag, sizeof(p->tag));   /* create a new local tag for every register attempt */
+                       make_our_tag(p);        /* create a new local tag for every register attempt */
                        ast_string_field_set(p, theirtag, NULL);        /* forget their old tag, so we don't match tags when getting response */
                }
        } else {
@@ -23929,7 +23929,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                ast_string_field_set(p, exten, "s");
                        /* Initialize our tag */
 
-                       make_our_tag(p->tag, sizeof(p->tag));
+                       make_our_tag(p);
                        /* First invitation - create the channel.  Allocation
                         * failures are handled below. */
 
@@ -26119,7 +26119,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
 
        /* Initialize tag for new subscriptions */      
        if (ast_strlen_zero(p->tag))
-               make_our_tag(p->tag, sizeof(p->tag));
+               make_our_tag(p);
 
        if (!strncmp(eventheader, "presence", MAX(event_len, 8)) || !strncmp(eventheader, "dialog", MAX(event_len, 6))) { /* Presence, RFC 3842 */
                unsigned int pidf_xml;
@@ -26627,14 +26627,15 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as
                if (!p->initreq.headers && req->has_to_tag) {
                        /* If this is a first request and it got a to-tag, it is not for us */
                        if (!req->ignore && req->method == SIP_INVITE) {
-                               /* We will be subversive here. By blanking out the to-tag of the request,
-                                * it will cause us to attach our own generated to-tag instead. This way,
-                                * when we receive an ACK, the ACK will contain the to-tag we generated,
-                                * resulting in a proper to-tag match.
+                               /* Just because we think this is a dialog-starting INVITE with a to-tag
+                                * doesn't mean it actually is. It could be a reinvite for an established, but
+                                * unknown dialog. In such a case, we need to change our tag to the
+                                * incoming INVITE's to-tag so that they will recognize the 481 we send and
+                                * so that we will properly match their incoming ACK.
                                 */
-                               char *to_header = (char *) sip_get_header(req, "To");
-                               char *tag = strstr(to_header, ";tag=");
-                               *tag = '\0';
+                               char totag[128];
+                               gettag(req, "To", totag, sizeof(totag));
+                               ast_string_field_set(p, tag, totag);
                                p->pendinginvite = p->icseq;
                                transmit_response_reliable(p, "481 Call/Transaction Does Not Exist", req);
                                /* Will cease to exist after ACK */
index a9b7e02..dbf5723 100644 (file)
@@ -1025,6 +1025,7 @@ struct sip_pvt {
                AST_STRING_FIELD(rdnis);        /*!< Referring DNIS */
                AST_STRING_FIELD(redircause);   /*!< Referring cause */
                AST_STRING_FIELD(theirtag);     /*!< Their tag */
+               AST_STRING_FIELD(tag);          /*!< Our tag for this session */
                AST_STRING_FIELD(username);     /*!< [user] name */
                AST_STRING_FIELD(peername);     /*!< [peer] name, not set if [user] */
                AST_STRING_FIELD(authname);     /*!< Who we use for authentication */
@@ -1076,7 +1077,6 @@ struct sip_pvt {
                                               */
        unsigned short req_secure_signaling:1;/*!< Whether we are required to have secure signaling or not */
        unsigned short natdetected:1;         /*!< Whether we detected a NAT when processing the Via */
-       char tag[11];                     /*!< Our tag for this session */
        int timer_t1;                     /*!< SIP timer T1, ms rtt */
        int timer_b;                      /*!< SIP timer B, ms */
        unsigned int sipoptions;          /*!< Supported SIP options on the other end */