]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
More fixes for realtime peers.
authorTilghman Lesher <tilghman@meg.abyt.es>
Fri, 15 Aug 2008 22:33:42 +0000 (22:33 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Fri, 15 Aug 2008 22:33:42 +0000 (22:33 +0000)
(closes issue #12921)
 Reported by: Nuitari
 Patches:
       20080804__bug12921.diff.txt uploaded by Corydon76 (license 14)
       20080815__bug12921.diff.txt uploaded by Corydon76 (license 14)
 Tested by: Corydon76

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

channels/chan_sip.c
configs/sip.conf.sample

index 3bb0ebd2bb35b959f61c3758310801cbe53463a1..133ca3204270c9dad26d81696f46456f2352a12c 100644 (file)
@@ -1435,7 +1435,7 @@ static int sip_poke_peer_s(const void *data);
 static void set_peer_defaults(struct sip_peer *peer);
 static struct sip_peer *temp_peer(const char *name);
 static void register_peer_exten(struct sip_peer *peer, int onoff);
-static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime);
+static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only);
 static struct sip_user *find_user(const char *name, int realtime);
 static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
 static int expire_register(const void *data);
@@ -1447,7 +1447,7 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
 static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey);
 static struct sip_user *realtime_user(const char *username);
 static void update_peer(struct sip_peer *p, int expiry);
-static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
+static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin, int devstate_only);
 static int sip_prune_realtime(int fd, int argc, char *argv[]);
 
 /*--- Internal UA client handling (outbound registrations) */
@@ -2509,7 +2509,7 @@ static void update_peer(struct sip_peer *p, int expiry)
  * \todo Consider adding check of port address when matching here to follow the same
  *     algorithm as for static peers. Will we break anything by adding that?
 */
-static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin)
+static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin, int devstate_only)
 {
        struct sip_peer *peer=NULL;
        struct ast_variable *var = NULL;
@@ -2628,7 +2628,7 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i
                return NULL;
        }
 
-       if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
+       if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) && !devstate_only) {
                /* Cache peer */
                ast_copy_flags(&peer->flags[1],&global_flags[1], SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS);
                if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
@@ -2665,7 +2665,7 @@ static int sip_addrcmp(char *name, struct sockaddr_in *sin)
 /*! \brief Locate peer by name or ip address 
  *     This is used on incoming SIP message to find matching peer on ip
        or outgoing message to find matching peer on name */
-static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
+static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only)
 {
        struct sip_peer *p = NULL;
 
@@ -2674,8 +2674,8 @@ static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int
        else
                p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp);
 
-       if (!p && realtime)
-               p = realtime_peer(peer, sin);
+       if (!p && (realtime || devstate_only))
+               p = realtime_peer(peer, sin, devstate_only);
 
        return p;
 }
@@ -2902,7 +2902,7 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer)
                *port++ = '\0';
        dialog->sa.sin_family = AF_INET;
        dialog->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC 3261) */
-       p = find_peer(peer, NULL, 1);
+       p = find_peer(peer, NULL, 1, 0);
 
        if (p) {
                int res = create_addr_from_peer(dialog, p);
@@ -3230,7 +3230,7 @@ static int update_call_counter(struct sip_pvt *fup, int event)
                inuse = &u->inUse;
                call_limit = &u->call_limit;
                inringing = NULL;
-       } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1) ) ) { /* Try to find peer */
+       } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1, 0) ) ) { /* Try to find peer */
                inuse = &p->inUse;
                call_limit = &p->call_limit;
                inringing = &p->inRinging;
@@ -8079,8 +8079,7 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
        return TRUE;            
 }
 
-/*! \brief Change the other partys IP address based on given contact */
-static int set_address_from_contact(struct sip_pvt *pvt)
+static int __set_address_from_contact(const char *fullcontact, struct sockaddr_in *sin)
 {
        struct hostent *hp;
        struct ast_hostent ahp;
@@ -8089,15 +8088,8 @@ static int set_address_from_contact(struct sip_pvt *pvt)
        char contact_buf[256];
        char *contact;
 
-       if (ast_test_flag(&pvt->flags[0], SIP_NAT_ROUTE)) {
-               /* NAT: Don't trust the contact field.  Just use what they came to us
-                  with. */
-               pvt->sa = pvt->recv;
-               return 0;
-       }
-
        /* Work on a copy */
-       ast_copy_string(contact_buf, pvt->fullcontact, sizeof(contact_buf));
+       ast_copy_string(contact_buf, fullcontact, sizeof(contact_buf));
        contact = contact_buf;
 
        /* Make sure it's a SIP URL */
@@ -8134,13 +8126,26 @@ static int set_address_from_contact(struct sip_pvt *pvt)
                ast_log(LOG_WARNING, "Invalid host name in Contact: (can't resolve in DNS) : '%s'\n", host);
                return -1;
        }
-       pvt->sa.sin_family = AF_INET;
-       memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
-       pvt->sa.sin_port = htons(port);
+       sin->sin_family = AF_INET;
+       memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
+       sin->sin_port = htons(port);
 
        return 0;
 }
 
+/*! \brief Change the other partys IP address based on given contact */
+static int set_address_from_contact(struct sip_pvt *pvt)
+{
+       if (ast_test_flag(&pvt->flags[0], SIP_NAT_ROUTE)) {
+               /* NAT: Don't trust the contact field.  Just use what they came to us
+                  with. */
+               pvt->sa = pvt->recv;
+               return 0;
+       }
+
+       return __set_address_from_contact(pvt->fullcontact, &pvt->sa);
+}
+
 
 /*! \brief Parse contact header and save registration (peer registration) */
 static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req)
@@ -8610,7 +8615,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
 /*! \brief Change onhold state of a peer using a pvt structure */
 static void sip_peer_hold(struct sip_pvt *p, int hold)
 {
-       struct sip_peer *peer = find_peer(p->peername, NULL, 1);
+       struct sip_peer *peer = find_peer(p->peername, NULL, 1, 0);
 
        if (!peer)
                return;
@@ -8730,7 +8735,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr
 
        ast_string_field_set(p, exten, name);
        build_contact(p);
-       peer = find_peer(name, NULL, 1);
+       peer = find_peer(name, NULL, 1, 0);
        if (!(peer && ast_apply_ha(peer->ha, sin))) {
                /* Peer fails ACL check */
                if (peer) {
@@ -9591,13 +9596,13 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                /* If we didn't find a user match, check for peers */
                if (sipmethod == SIP_SUBSCRIBE)
                        /* For subscribes, match on peer name only */
-                       peer = find_peer(of, NULL, 1);
+                       peer = find_peer(of, NULL, 1, 0);
                else
                        /* Look for peer based on the IP address we received data from */
                        /* If peer is registered from this IP address or have this as a default
                           IP address, this call is from the peer 
                        */
-                       peer = find_peer(NULL, &p->recv, 1);
+                       peer = find_peer(NULL, &p->recv, 1, 0);
 
                if (peer) {
                        /* Set Frame packetization */
@@ -10457,7 +10462,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m
                return RESULT_SHOWUSAGE;
 
        load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
-       peer = find_peer(argv[3], NULL, load_realtime);
+       peer = find_peer(argv[3], NULL, load_realtime, 0);
        if (s) {        /* Manager */
                if (peer) {
                        const char *id = astman_get_header(m,"ActionID");
@@ -11353,7 +11358,7 @@ static int sip_do_debug_peer(int fd, int argc, char *argv[])
        struct sip_peer *peer;
        if (argc != 5)
                return RESULT_SHOWUSAGE;
-       peer = find_peer(argv[4], NULL, 1);
+       peer = find_peer(argv[4], NULL, 1, 0);
        if (peer) {
                if (peer->addr.sin_addr.s_addr) {
                        debugaddr.sin_family = AF_INET;
@@ -11904,7 +11909,7 @@ static int function_sippeer(struct ast_channel *chan, char *cmd, char *data, cha
        else
                colname = "ip";
 
-       if (!(peer = find_peer(data, NULL, 1)))
+       if (!(peer = find_peer(data, NULL, 1, 0)))
                return -1;
 
        if (!strcasecmp(colname, "ip")) {
@@ -16342,7 +16347,7 @@ static int sip_devicestate(void *data)
         * load it BACK into memory, thus defeating the point of trying to trying to
         * clear dead hosts out of memory.
         */
-       if ((p = find_peer(host, NULL, 0))) {
+       if ((p = find_peer(host, NULL, 0, 1))) {
                if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) {
                        /* we have an address for the peer */
                
@@ -17220,6 +17225,12 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
        }
        if (!ast_strlen_zero(fullcontact)) {
                ast_copy_string(peer->fullcontact, fullcontact, sizeof(peer->fullcontact));
+               /* We have a hostname in the fullcontact, but if we don't have an
+                * address listed on the entry (or if it's 'dynamic'), then we need to
+                * parse the entry to obtain the IP address, so a dynamic host can be
+                * contacted immediately after reload (as opposed to waiting for it to
+                * register once again). */
+               __set_address_from_contact(fullcontact, &peer->addr);
        }
 
        if (!ast_test_flag(&global_flags[1], SIP_PAGE2_IGNOREREGEXPIRE) && ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC) && realtime) {
index 08eaf50b1f3f9846f957bd5301f6743dba00f55f..eab1dcf6d891efaccb7034428491ea7a75f9498e 100644 (file)
@@ -344,7 +344,9 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
                                 ; If set to yes, when a SIP UA registers successfully, the ip address,
                                 ; the origination port, the registration period, and the username of
                                 ; the UA will be set to database via realtime. 
-                                ; If not present, defaults to 'yes'.
+                                ; If not present, defaults to 'yes'. Note: realtime peers will
+                                ; probably not function across reloads in the way that you expect, if
+                                ; you turn this option off.
 ;rtautoclear=yes                ; Auto-Expire friends created on the fly on the same schedule
                                 ; as if it had just registered? (yes|no|<seconds>)
                                 ; If set to yes, when the registration expires, the friend will