Merged revisions 221360 via svnmerge from
[asterisk/asterisk.git] / channels / chan_sip.c
index 908bc80..a43783c 100644 (file)
@@ -1776,6 +1776,7 @@ struct sip_pvt {
        long branch;                            /*!< The branch identifier of this session */
        long invite_branch;                     /*!< The branch used when we sent the initial INVITE */
        int64_t sessionversion_remote;          /*!< Remote UA's SDP Session Version */
+       int portinuri:1;                        /*!< Non zero if a port has been specified, will also disable srv lookups */
        struct sockaddr_in sa;                  /*!< Our peer */
        struct sockaddr_in redirip;             /*!< Where our RTP should be going if not to us */
        struct sockaddr_in vredirip;            /*!< Where our Video RTP should be going if not to us */
@@ -2029,6 +2030,7 @@ struct sip_peer {
        struct sip_proxy *outboundproxy;        /*!< Outbound proxy for this peer */
        struct ast_dnsmgr_entry *dnsmgr;/*!<  DNS refresh manager for peer */
        struct sockaddr_in addr;        /*!<  IP address of peer */
+       int portinuri:1;                /*!< Whether the port should be included in the URI */
        struct sip_pvt *call;           /*!<  Call pointer */
        int pokeexpire;                 /*!<  Qualification: When to expire poke (qualify= checking) */
        int lastms;                     /*!<  Qualification: How long last response took (in ms), or -1 for no response */
@@ -3209,11 +3211,15 @@ static int proxy_update(struct sip_proxy *proxy)
  *  pt buffer is provided or the pt has errors when being converted
  *  to an int value, the port provided as the standard is used.
  */
-static int port_str2int(const char *pt, unsigned int standard)
+static int port_str2int(const char *pt, unsigned int standard, int *found_port)
 {
        int port = standard;
        if (ast_strlen_zero(pt) || (sscanf(pt, "%30d", &port) != 1) || (port < 1) || (port > 65535)) {
                port = standard;
+               if (found_port)
+                       *found_port = 0;
+       } else if (found_port) {
+               *found_port = 1;
        }
 
        return port;
@@ -3233,7 +3239,7 @@ static struct sip_proxy *proxy_allocate(char *name, char *port, int force)
                return NULL;
        proxy->force = force;
        ast_copy_string(proxy->name, name, sizeof(proxy->name));
-       proxy->ip.sin_port = htons(port_str2int(port, STANDARD_SIP_PORT));
+       proxy->ip.sin_port = htons(port_str2int(port, STANDARD_SIP_PORT, NULL));
        proxy_update(proxy);
        return proxy;
 }
@@ -5277,6 +5283,8 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
                dialog->noncodeccapability &= ~AST_RTP_DTMF;
        if (peer->call_limit)
                ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
+       if (!dialog->portinuri)
+               dialog->portinuri = peer->portinuri;
        
        dialog->chanvars = copy_vars(peer->chanvars);
 
@@ -5299,8 +5307,10 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd
 
        ast_copy_string(peername, opeer, sizeof(peername));
        port = strchr(peername, ':');
-       if (port)
+       if (port) {
                *port++ = '\0';
+               dialog->portinuri = 1;
+       }
        dialog->sa.sin_family = AF_INET;
        dialog->timer_t1 = global_t1; /* Default SIP retransmission timer T1 (RFC 3261) */
        dialog->timer_b = global_timer_b; /* Default SIP transaction timer B (RFC 3261) */
@@ -5335,7 +5345,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd
                /* This address should be updated using dnsmgr */
                memcpy(&dialog->sa.sin_addr, &sin->sin_addr, sizeof(dialog->sa.sin_addr));
                if (!sin->sin_port) {
-                       portno = port_str2int(port, (dialog->socket.type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT);
+                       portno = port_str2int(port, (dialog->socket.type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT, NULL);
                } else {
                        portno = ntohs(sin->sin_port);
                }
@@ -5362,7 +5372,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockadd
                        }
                }
                if (!portno)
-                       portno = port_str2int(port, (dialog->socket.type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT);
+                       portno = port_str2int(port, (dialog->socket.type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT, NULL);
                hp = ast_gethostbyname(hostn, &ahp);
                if (!hp) {
                        ast_log(LOG_WARNING, "No such host: %s\n", peername);
@@ -10804,7 +10814,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
                        ast_str_append(&invite, 0, "%s@", n);
                }
                ast_str_append(&invite, 0, "%s", p->tohost);
-               if (ntohs(p->sa.sin_port) != STANDARD_SIP_PORT)
+               if (p->portinuri)
                        ast_str_append(&invite, 0, ":%d", ntohs(p->sa.sin_port));
                ast_str_append(&invite, 0, "%s", urioptions);
        }
@@ -12192,6 +12202,7 @@ static int expire_register(const void *data)
                return 0;
 
        peer->expire = -1;
+       peer->portinuri = 0;
        memset(&peer->addr, 0, sizeof(peer->addr));
 
        destroy_association(peer);      /* remove registration data from storage */
@@ -12343,9 +12354,9 @@ static int __set_address_from_contact(const char *fullcontact, struct sockaddr_i
 
        /* set port */
        if (((get_transport_str2enum(transport) == SIP_TRANSPORT_TLS)) || !(strncasecmp(fullcontact, "sips", 4))) {
-               port = port_str2int(pt, STANDARD_TLS_PORT);
+               port = port_str2int(pt, STANDARD_TLS_PORT, NULL);
        } else {
-               port = port_str2int(pt, STANDARD_SIP_PORT);
+               port = port_str2int(pt, STANDARD_SIP_PORT, NULL);
        }
 
 
@@ -12390,6 +12401,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
        int expire = atoi(expires);
        char *curi, *host, *pt, *transport;
        int port;
+       int portinuri;
        int transport_type;
        const char *useragent;
        struct hostent *hp;
@@ -12443,6 +12455,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
                ast_string_field_set(peer, useragent, "");
                peer->sipoptions = 0;
                peer->lastms = 0;
+               peer->portinuri = 0;
                pvt->expiry = 0;
 
                ast_verb(3, "Unregistered SIP '%s'\n", peer->name);
@@ -12468,11 +12481,12 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
                 * default port to match the specified transport.  This may or may not be the
                 * same transport used by the pvt struct for the Register dialog. */
                
-               port = port_str2int(pt, (transport_type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT);
+               port = port_str2int(pt, (transport_type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT, &portinuri);
        } else {
-               port = port_str2int(pt, STANDARD_SIP_PORT);
+               port = port_str2int(pt, STANDARD_SIP_PORT, &portinuri);
                transport_type = pvt->socket.type;
        }
+       peer->portinuri = portinuri;
 
        /* if the peer's socket type is different than the Registration
         * transport type, change it.  If it got this far, it is a
@@ -14145,7 +14159,7 @@ static void check_via(struct sip_pvt *p, struct sip_request *req)
                if (pt)
                        *pt++ = '\0';   /* remember port pointer */
                p->sa = p->recv;
-               p->sa.sin_port = htons(port_str2int(pt, STANDARD_SIP_PORT));
+               p->sa.sin_port = htons(port_str2int(pt, STANDARD_SIP_PORT, NULL));
 
                if (sip_debug_test_pvt(p)) {
                        const struct sockaddr_in *dst = sip_real_dst(p);
@@ -24214,6 +24228,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                /* XXX should unregister ? */
        }
 
+       if (found)
+               peer->portinuri = 0;
+
        /* If we have realm authentication information, remove them (reload) */
        clear_realm_authentication(peer->auth);
        peer->auth = NULL;
@@ -24365,6 +24382,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                        ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
                                }
                        } else if (!strcasecmp(v->name, "port")) {
+                               peer->portinuri = 1;
                                if (!realtime && peer->host_dynamic) {
                                        peer->defaddr.sin_port = htons(atoi(v->value));
                                } else {
@@ -24620,7 +24638,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
 
                        snprintf(transport, sizeof(transport), "_sip._%s", get_transport(peer->socket.type));
 
-                       if (ast_dnsmgr_lookup(_srvlookup, &peer->addr, &peer->dnsmgr, sip_cfg.srvlookup ? transport : NULL)) {
+                       if (ast_dnsmgr_lookup(_srvlookup, &peer->addr, &peer->dnsmgr, sip_cfg.srvlookup && !peer->portinuri ? transport : NULL)) {
                                ast_log(LOG_ERROR, "srvlookup failed for host: %s, on peer %s, removing peer\n", _srvlookup, peer->name);
                                unref_peer(peer, "getting rid of a peer pointer");
                                return NULL;