From 5ee6af1a0ccbb79cb09ee2688c30d36f63bb3ef3 Mon Sep 17 00:00:00 2001 From: tilghman Date: Fri, 15 Aug 2008 22:33:42 +0000 Subject: More fixes for realtime peers. (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: http://svn.digium.com/svn/asterisk/branches/1.4@138258 f38db490-d61c-443f-a65b-d21fe96a405b --- channels/chan_sip.c | 71 ++++++++++++++++++++++++++++--------------------- configs/sip.conf.sample | 4 ++- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 3bb0ebd2b..133ca3204 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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) { diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 08eaf50b1..eab1dcf6d 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -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|) ; If set to yes, when the registration expires, the friend will -- cgit v1.2.3