allow minimum/maximum registration intervals to be set on server side (issue #51111)
authorKevin P. Fleming <kpfleming@digium.com>
Thu, 15 Sep 2005 02:25:06 +0000 (02:25 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Thu, 15 Sep 2005 02:25:06 +0000 (02:25 +0000)
respect server-provided registration interval on client side

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

channels/chan_iax2.c
configs/iax.conf.sample

index 5bc883e..b540c4f 100755 (executable)
@@ -163,7 +163,8 @@ static int iaxdefaulttimeout = 5;           /* Default to wait no more than 5 seconds for
 
 static int tos = 0;
 
-static int expirey = IAX_DEFAULT_REG_EXPIRE;
+static int min_reg_expire;
+static int max_reg_expire;
 
 static int timingfd = -1;                              /* Timing file descriptor */
 
@@ -311,8 +312,8 @@ struct iax2_peer {
        char cid_num[AST_MAX_EXTENSION];                /* Default context (for transfer really) */
        char cid_name[AST_MAX_EXTENSION];               /* Default context (for transfer really) */
        
-       int expire;                                     /* Schedule entry for expirey */
-       int expirey;                                    /* How soon to expire */
+       int expire;                                     /* Schedule entry for expiry */
+       int expiry;                                     /* How soon to expire */
        int capability;                                 /* Capability */
        char zonetag[80];                               /* Time Zone */
 
@@ -485,8 +486,8 @@ struct chan_iax2_pvt {
        struct ast_channel *owner;
        /* What's our state? */
        int state;
-       /* Expirey (optional) */
-       int expirey;
+       /* Expiry (optional) */
+       int expiry;
        /* Next outgoing sequence number */
        unsigned char oseqno;
        /* Next sequence number they have not yet acknowledged */
@@ -625,7 +626,7 @@ static struct iax2_dpcache {
        char peercontext[AST_MAX_CONTEXT];
        char exten[AST_MAX_EXTENSION];
        struct timeval orig;
-       struct timeval expirey;
+       struct timeval expiry;
        int flags;
        unsigned short callno;
        int waiters[256];
@@ -1068,7 +1069,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
                        iaxs[x]->peercallno = callno;
                        iaxs[x]->callno = x;
                        iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
-                       iaxs[x]->expirey = expirey;
+                       iaxs[x]->expiry = min_reg_expire;
                        iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
                        iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
                        iaxs[x]->amaflags = amaflags;
@@ -1981,7 +1982,7 @@ static int iax2_show_cache(int fd, int argc, char *argv[])
        dp = dpcache;
        ast_cli(fd, "%-20.20s %-12.12s %-9.9s %-8.8s %s\n", "Peer/Context", "Exten", "Exp.", "Wait.", "Flags");
        while(dp) {
-               s = dp->expirey.tv_sec - tv.tv_sec;
+               s = dp->expiry.tv_sec - tv.tv_sec;
                tmp[0] = '\0';
                if (dp->flags & CACHE_FLAG_EXISTS)
                        strncat(tmp, "EXISTS|", sizeof(tmp) - strlen(tmp) - 1);
@@ -5056,9 +5057,9 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                return -1;
        }
        ast_copy_string(iaxs[callno]->peer, peer, sizeof(iaxs[callno]->peer));
-       /* Choose lowest expirey number */
-       if (expire && (expire < iaxs[callno]->expirey)) 
-               iaxs[callno]->expirey = expire;
+       /* Choose lowest expiry number */
+       if (expire && (expire < iaxs[callno]->expiry)) 
+               iaxs[callno]->expiry = expire;
 
        ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
 
@@ -5216,7 +5217,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 {
        char exten[256] = "";
        int status = CACHE_FLAG_UNKNOWN;
-       int expirey = iaxdefaultdpcache;
+       int expiry = iaxdefaultdpcache;
        int x;
        int matchmore = 0;
        struct iax2_dpcache *dp, *prev;
@@ -5235,7 +5236,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
                /* Don't really do anything with this */
        }
        if (ies->refresh)
-               expirey = ies->refresh;
+               expiry = ies->refresh;
        if (ies->dpstatus & IAX_DPSTATUS_MATCHMORE)
                matchmore = CACHE_FLAG_MATCHMORE;
        ast_mutex_lock(&dpcache_lock);
@@ -5250,7 +5251,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
                                pvt->dpentries = dp->peer;
                        dp->peer = NULL;
                        dp->callno = 0;
-                       dp->expirey.tv_sec = dp->orig.tv_sec + expirey;
+                       dp->expiry.tv_sec = dp->orig.tv_sec + expiry;
                        if (dp->flags & CACHE_FLAG_PENDING) {
                                dp->flags &= ~CACHE_FLAG_PENDING;
                                dp->flags |= status;
@@ -5352,7 +5353,7 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        }
        reg = iaxs[callno]->reg;
        if (!reg) {
-               ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
+               ast_log(LOG_WARNING, "Registry acknowledge on unknown registry '%s'\n", peer);
                return -1;
        }
        memcpy(&oldus, &reg->us, sizeof(oldus));
@@ -5363,13 +5364,13 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        }
        memcpy(&reg->us, &us, sizeof(reg->us));
        reg->messages = ies->msgcount;
-       if (refresh && (reg->refresh > refresh)) {
-               /* Refresh faster if necessary */
-               reg->refresh = refresh;
-               if (reg->expire > -1)
-                       ast_sched_del(sched, reg->expire);
-               reg->expire = ast_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
-       }
+       /* always refresh the registration at the interval requested by the server
+          we are registering to
+       */
+       reg->refresh = refresh;
+       if (reg->expire > -1)
+               ast_sched_del(sched, reg->expire);
+       reg->expire = ast_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
        if ((inaddrcmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) && (option_verbose > 2)) {
                if (reg->messages > 65534)
                        snprintf(msgstatus, sizeof(msgstatus), " with message(s) waiting\n");
@@ -5468,8 +5469,8 @@ static int expire_registry(void *data)
        memset(&p->addr, 0, sizeof(p->addr));
        /* Reset expire notice */
        p->expire = -1;
-       /* Reset expirey value */
-       p->expirey = expirey;
+       /* Reset expiry value */
+       p->expiry = min_reg_expire;
        if (!ast_test_flag(p, IAX_TEMPONLY))
                ast_db_del("IAX/Registry", p->name);
        register_peer_exten(p, 0);
@@ -5508,7 +5509,7 @@ static void reg_source_db(struct iax2_peer *p)
                                                ast_verbose(VERBOSE_PREFIX_3 "Seeding '%s' at %s:%d for %d\n", p->name, 
                                                ast_inet_ntoa(iabuf, sizeof(iabuf), in), atoi(c), atoi(d));
                                        iax2_poke_peer(p, 0);
-                                       p->expirey = atoi(d);
+                                       p->expiry = atoi(d);
                                        memset(&p->addr, 0, sizeof(p->addr));
                                        p->addr.sin_family = AF_INET;
                                        p->addr.sin_addr = in;
@@ -5516,7 +5517,7 @@ static void reg_source_db(struct iax2_peer *p)
                                        if (p->expire > -1)
                                                ast_sched_del(sched, p->expire);
                                        ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
-                                       p->expire = ast_sched_add(sched, (p->expirey + 10) * 1000, expire_registry, (void *)p);
+                                       p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p);
                                        if (iax2_regfunk)
                                                iax2_regfunk(p->name, 1);
                                        register_peer_exten(p, 1);
@@ -5527,7 +5528,7 @@ static void reg_source_db(struct iax2_peer *p)
        }
 }
 
-static int update_registry(char *name, struct sockaddr_in *sin, int callno, char *devtype, int fd)
+static int update_registry(char *name, struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
 {
        /* Called from IAX thread only, with proper iaxsl lock */
        struct iax_ie_data ied;
@@ -5536,79 +5537,92 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
        char data[80];
        char iabuf[INET_ADDRSTRLEN];
        int version;
+
        memset(&ied, 0, sizeof(ied));
-       p = find_peer(name, 1);
-       if (p) {
-               if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
-                       realtime_update_peer(name, sin);
-               if (inaddrcmp(&p->addr, sin)) {
-                       if (iax2_regfunk)
-                               iax2_regfunk(p->name, 1);
-                       snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), p->expirey);
-                       if (!ast_test_flag(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
-                               ast_db_put("IAX/Registry", p->name, data);
-                               if  (option_verbose > 2)
+
+       if (!(p = find_peer(name, 1))) {
+               ast_log(LOG_WARNING, "No such peer '%s'\n", name);
+               return -1;
+       }
+
+       if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
+               realtime_update_peer(name, sin);
+       if (inaddrcmp(&p->addr, sin)) {
+               if (iax2_regfunk)
+                       iax2_regfunk(p->name, 1);
+               snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), p->expiry);
+               if (!ast_test_flag(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
+                       ast_db_put("IAX/Registry", p->name, data);
+                       if  (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Registered IAX2 '%s' (%s) at %s:%d\n", p->name, 
-                                       iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
-                               manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
-                               ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
-                               register_peer_exten(p, 1);
-                       } else if (!ast_test_flag(p, IAX_TEMPONLY)) {
-                               if  (option_verbose > 2)
+                                           iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
+                       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
+                       ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
+                       register_peer_exten(p, 1);
+               } else if (!ast_test_flag(p, IAX_TEMPONLY)) {
+                       if  (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Unregistered IAX2 '%s' (%s)\n", p->name, 
-                                       iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED");
-                               manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
-                               ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
-                               register_peer_exten(p, 0);
-                               ast_db_del("IAX/Registry", p->name);
-                       }
-                       /* Update the host */
-                       memcpy(&p->addr, sin, sizeof(p->addr));
-                       /* Verify that the host is really there */
-                       iax2_poke_peer(p, callno);
-               }               
-               /* Store socket fd */
-               p->sockfd = fd;
-               /* Setup the expirey */
-               if (p->expire > -1)
-                       ast_sched_del(sched, p->expire);
-               if (p->expirey && sin->sin_addr.s_addr)
-                       p->expire = ast_sched_add(sched, (p->expirey + 10) * 1000, expire_registry, (void *)p);
-               iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
-               iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
-               if (sin->sin_addr.s_addr) {
-                       iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expirey);
-                       iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &p->addr);
-                       if (!ast_strlen_zero(p->mailbox)) {
-                               if (ast_test_flag(p, IAX_MESSAGEDETAIL)) {
-                                       int new, old;
-                                       ast_app_messagecount(p->mailbox, &new, &old);
-                                       if (new > 255)
-                                               new = 255;
-                                       if (old > 255)
-                                               old = 255;
-                                       msgcount = (old << 8) | new;
-                               } else {
-                                       msgcount = ast_app_has_voicemail(p->mailbox, NULL);
-                                       if (msgcount)
-                                               msgcount = 65535;
-                               }
-                               iax_ie_append_short(&ied, IAX_IE_MSGCOUNT, msgcount);
-                       }
-                       if (ast_test_flag(p, IAX_HASCALLERID)) {
-                               iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, p->cid_num);
-                               iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
+                                           iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED");
+                       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
+                       ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
+                       register_peer_exten(p, 0);
+                       ast_db_del("IAX/Registry", p->name);
+               }
+               /* Update the host */
+               memcpy(&p->addr, sin, sizeof(p->addr));
+               /* Verify that the host is really there */
+               iax2_poke_peer(p, callno);
+       }               
+       /* Store socket fd */
+       p->sockfd = fd;
+       /* Setup the expiry */
+       if (p->expire > -1)
+               ast_sched_del(sched, p->expire);
+       if (refresh > max_reg_expire) {
+               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, max_reg_expire, refresh);
+               p->expiry = max_reg_expire;
+       } else if (refresh < min_reg_expire) {
+               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, min_reg_expire, refresh);
+               p->expiry = min_reg_expire;
+       } else {
+               p->expiry = refresh;
+       }
+       if (p->expiry && sin->sin_addr.s_addr)
+               p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p);
+       iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
+       iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
+       if (sin->sin_addr.s_addr) {
+               iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expiry);
+               iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &p->addr);
+               if (!ast_strlen_zero(p->mailbox)) {
+                       if (ast_test_flag(p, IAX_MESSAGEDETAIL)) {
+                               int new, old;
+                               ast_app_messagecount(p->mailbox, &new, &old);
+                               if (new > 255)
+                                       new = 255;
+                               if (old > 255)
+                                       old = 255;
+                               msgcount = (old << 8) | new;
+                       } else {
+                               msgcount = ast_app_has_voicemail(p->mailbox, NULL);
+                               if (msgcount)
+                                       msgcount = 65535;
                        }
+                       iax_ie_append_short(&ied, IAX_IE_MSGCOUNT, msgcount);
+               }
+               if (ast_test_flag(p, IAX_HASCALLERID)) {
+                       iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, p->cid_num);
+                       iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
                }
-               version = iax_check_version(devtype);
-               if (version) 
-                       iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
-               if (ast_test_flag(p, IAX_TEMPONLY))
-                       destroy_peer(p);
-               return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
        }
-       ast_log(LOG_WARNING, "No such peer '%s'\n", name);
-       return -1;
+       version = iax_check_version(devtype);
+       if (version) 
+               iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
+       if (ast_test_flag(p, IAX_TEMPONLY))
+               destroy_peer(p);
+       return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
 }
 
 static int registry_authrequest(char *name, int callno)
@@ -7268,7 +7282,7 @@ retryowner2:
                                if ((ast_strlen_zero(iaxs[fr.callno]->secret) && ast_strlen_zero(iaxs[fr.callno]->inkeys)) || (iaxs[fr.callno]->state & IAX_STATE_AUTHENTICATED)) {
                                        if (f.subclass == IAX_COMMAND_REGREL)
                                                memset(&sin, 0, sizeof(sin));
-                                       if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype, fd))
+                                       if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype, fd, ies.refresh))
                                                ast_log(LOG_WARNING, "Registry error\n");
                                        if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr)
                                                check_provisioning(&sin, fd, ies.serviceident, ies.provver);
@@ -8021,7 +8035,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                if (!found) {
                        ast_copy_string(peer->name, name, sizeof(peer->name));
                        peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
-                       peer->expirey = expirey;
+                       peer->expiry = min_reg_expire;
                }
                peer->prefs = prefs;
                peer->capability = iax2_capability;
@@ -8480,6 +8494,9 @@ static int set_config(char *config_file, int reload)
        nochecksums = 0;
 #endif
 
+       min_reg_expire = IAX_DEFAULT_REG_EXPIRE;
+       max_reg_expire = IAX_DEFAULT_REG_EXPIRE;
+
        v = ast_variable_browse(cfg, "general");
 
        /* Seed initial tos value */
@@ -8525,6 +8542,10 @@ static int set_config(char *config_file, int reload)
                        lagrq_time = atoi(v->value);
                else if (!strcasecmp(v->name, "dropcount")) 
                        iax2_dropcount = atoi(v->value);
+               else if (!strcasecmp(v->name, "maxregexpire")) 
+                       max_reg_expire = atoi(v->value);
+               else if (!strcasecmp(v->name, "minregexpire")) 
+                       min_reg_expire = atoi(v->value);
                else if (!strcasecmp(v->name, "bindaddr")) {
                        if (reload) {
                                ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n");
@@ -8635,6 +8656,11 @@ static int set_config(char *config_file, int reload)
                /*      ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
                v = v->next;
        }
+       if (min_reg_expire > max_reg_expire) {
+               ast_log(LOG_WARNING, "Minimum registration interval of %d is more than maximum of %d, resetting minimum to %d\n",
+                       min_reg_expire, max_reg_expire, max_reg_expire);
+               min_reg_expire = max_reg_expire;
+       }
        iax2_capability = capability;
        cat = ast_category_browse(cfg, NULL);
        while(cat) {
@@ -8797,7 +8823,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
        while(dp) {
                next = dp->next;
                /* Expire old caches */
-               if (ast_tvcmp(tv, dp->expirey) > 0) {
+               if (ast_tvcmp(tv, dp->expiry) > 0) {
                                /* It's expired, let it disappear */
                                if (prev)
                                        prev->next = dp->next;
@@ -8834,10 +8860,10 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
                memset(dp, 0, sizeof(struct iax2_dpcache));
                ast_copy_string(dp->peercontext, data, sizeof(dp->peercontext));
                ast_copy_string(dp->exten, exten, sizeof(dp->exten));
-               gettimeofday(&dp->expirey, NULL);
-               dp->orig = dp->expirey;
+               gettimeofday(&dp->expiry, NULL);
+               dp->orig = dp->expiry;
                /* Expires in 30 mins by default */
-               dp->expirey.tv_sec += iaxdefaultdpcache;
+               dp->expiry.tv_sec += iaxdefaultdpcache;
                dp->next = dpcache;
                dp->flags = CACHE_FLAG_PENDING;
                for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
@@ -8915,7 +8941,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
                                dp->flags |= CACHE_FLAG_TIMEOUT;
                                /* Expire after only 60 seconds now.  This is designed to help reduce backlog in heavily loaded
                                   systems without leaving it unavailable once the server comes back online */
-                               dp->expirey.tv_sec = dp->orig.tv_sec + 60;
+                               dp->expiry.tv_sec = dp->orig.tv_sec + 60;
                                for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
                                        if (dp->waiters[x] > -1)
                                                write(dp->waiters[x], "asdf", 4);
index 745f171..0ebcdc8 100755 (executable)
@@ -154,8 +154,11 @@ forcejitterbuffer=no
 ; they do not also need to have it enabled.
 ;
 ; trunktimestamps=yes
-
 ;
+; Minimum and maximum amounts of time that IAX peers can request as
+; a registration expiration interval (in seconds).
+; minregexpire = 60
+; maxregexpire = 60
 ;
 ; We can register with another IAX server to let him know where we are
 ; in case we have a dynamic IP address for example