Fix regressions with regards to route-set creation on early dialogs.
authorMark Michelson <mmichelson@digium.com>
Fri, 17 Feb 2012 19:22:22 +0000 (19:22 +0000)
committerMark Michelson <mmichelson@digium.com>
Fri, 17 Feb 2012 19:22:22 +0000 (19:22 +0000)
This fixes two main issues:

1. Asterisk would send a CANCEL to the route created by the provisional response
   instead of using the same destination it did in the initial INVITE.
2. If a new route set arrives in a 200 OK than was in the 1XX response (perfectly
   possible if our outbound INVITE gets forked), then the route set in the 200 OK
   needs to overwrite the route set in the 1XX response.

(closes issue ASTERISK-19358)
Reported by: Karsten Wemheuer
Tested by: Karsten Wemheuer
patches:
   ASTERISK-19358.patch uploaded by Mark Michelson (license 5049)
   ASTERISK-19358.patch uploaded by Stefan Schmidt (license 6034)

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

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

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

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

channels/chan_sip.c

index 1d8d4db..d846737 100644 (file)
@@ -1296,7 +1296,7 @@ static int auto_congest(const void *arg);
 static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *addr, const int intended_method);
 static void free_old_route(struct sip_route *route);
 static void list_route(struct sip_route *route);
-static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards);
+static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp);
 static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
                                              struct sip_request *req, const char *uri);
 static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
@@ -8184,7 +8184,7 @@ static void forked_invite_init(struct sip_request *req, const char *new_theirtag
        ast_string_field_set(p, our_contact, original->our_contact);
        ast_string_field_set(p, fullcontact, original->fullcontact);
        parse_ok_contact(p, req);
-       build_route(p, req, 1);
+       build_route(p, req, 1, 0);
 
        transmit_request(p, SIP_ACK, p->ocseq, XMIT_UNRELIABLE, TRUE);
        transmit_request(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
@@ -10663,7 +10663,11 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, ui
        snprintf(tmp, sizeof(tmp), "%u %s", seqno, sip_methods[sipmethod].text);
 
        add_header(req, "Via", p->via);
-       if (p->route) {
+       /*
+        * Use the learned route set unless this is a CANCEL. For a CANCEL
+        * we have to send to the same destination as the original INVITE.
+        */
+       if (p->route && sipmethod != SIP_CANCEL) {
                set_destination(p, p->route->hop);
                add_route(req, is_strict ? p->route->next : p->route);
        }
@@ -14632,8 +14636,9 @@ static void list_route(struct sip_route *route)
        }
 }
 
-/*! \brief Build route list from Record-Route header */
-static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards)
+/*! \brief Build route list from Record-Route header 
+    \param resp the SIP response code or 0 for a request */
+static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp)
 {
        struct sip_route *thishop, *head, *tail;
        int start = 0;
@@ -14651,8 +14656,11 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward
                p->route = NULL;
        }
 
-       /* We only want to create the route set the first time this is called */
-       p->route_persistent = 1;
+       /* We only want to create the route set the first time this is called except
+          it is called from a provisional response.*/
+       if ((resp < 100) || (resp > 199)) {
+               p->route_persistent = 1;
+       }
 
        /* Build a tailq, then assign it to p->route when done.
         * If backwards, we add entries from the head so they end up
@@ -20775,7 +20783,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                 * */
                parse_ok_contact(p, req);
                if (!reinvite) {
-                       build_route(p, req, 1);
+                       build_route(p, req, 1, resp);
                }
                if (!req->ignore && p->owner) {
                        if (get_rpid(p, req)) {
@@ -20826,7 +20834,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                 * */
                parse_ok_contact(p, req);
                if (!reinvite) {
-                       build_route(p, req, 1);
+                       build_route(p, req, 1, resp);
                }
                if (!req->ignore && p->owner) {
                        struct ast_party_redirecting redirecting;
@@ -20853,7 +20861,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                 * */
                parse_ok_contact(p, req);
                if (!reinvite) {
-                       build_route(p, req, 1);
+                       build_route(p, req, 1, resp);
                }
                if (!req->ignore && p->owner) {
                        if (get_rpid(p, req)) {
@@ -20955,7 +20963,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                        parse_ok_contact(p, req);
                        /* Save Record-Route for any later requests we make on this dialogue */
                        if (!reinvite) {
-                               build_route(p, req, 1);
+                               build_route(p, req, 1, resp);
                        }
 
                        if(set_address_from_contact(p)) {
@@ -23530,7 +23538,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        *recount = 1;
 
                        /* Save Record-Route for any later requests we make on this dialogue */
-                       build_route(p, req, 0);
+                       build_route(p, req, 0, 0);
 
                        if (c) {
                                ast_party_redirecting_init(&redirecting);
@@ -25567,7 +25575,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
                if (sipdebug)
                        ast_debug(4, "Initializing initreq for method %s - callid %s\n", sip_methods[req->method].text, p->callid);
                check_via(p, req);
-               build_route(p, req, 0);
+               build_route(p, req, 0, 0);
        } else if (req->debug && req->ignore)
                ast_verbose("Ignoring this SUBSCRIBE request\n");