Merge tony's IAX/SIP realtime cache (bug #3509)
authorMark Spencer <markster@digium.com>
Thu, 10 Feb 2005 20:04:42 +0000 (20:04 +0000)
committerMark Spencer <markster@digium.com>
Thu, 10 Feb 2005 20:04:42 +0000 (20:04 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5003 65c4cc65-6c06-0410-ace0-fbb531ad65f3

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

index b14d502..7f80d47 100755 (executable)
@@ -207,8 +207,14 @@ struct iax2_context {
 #define IAX_CODEC_USER_FIRST (1 << 14)  /* are we willing to let the other guy choose the codec? */
 #define IAX_CODEC_NOPREFS (1 << 15) /* Force old behaviour by turning off prefs */
 #define IAX_CODEC_NOCAP (1 << 16) /* only consider requested format and ignore capabilities*/
+#define IAX_RTCACHEFRIENDS (1 << 17) /* let realtime stay till your reload */
+#define IAX_RTNOUPDATE (1 << 18) /* Don't send a realtime update */
+#define IAX_RTAUTOCLEAR (1 << 19) /* erase me on expire */ 
+
+static int global_rtautoclear = 120;
 
 static struct iax2_peer *realtime_peer(const char *peername);
+static int reload_config(void);
 
 struct iax2_user {
        char name[80];
@@ -576,8 +582,15 @@ static int send_command_locked(unsigned short callno, char, int, unsigned int, c
 static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int);
 static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int);
 static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, char *, int);
+static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly);
+static void destroy_user(struct iax2_user *user);
+static int expire_registry(void *data);
+static int iax2_write(struct ast_channel *c, struct ast_frame *f);
+static int iax2_do_register(struct iax2_registry *reg);
+static void prune_peers(void);
+static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
+static int iax2_provision(struct sockaddr_in *end, char *dest, const char *template, int force);
 
-static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, struct ast_frame *f);
 
 static int send_ping(void *data)
 {
@@ -653,7 +666,7 @@ static int uncompress_subclass(unsigned char csub)
                return csub;
 }
 
-static struct iax2_peer *find_peer(const char *name) 
+static struct iax2_peer *find_peer(const char *name, int realtime) 
 {
        struct iax2_peer *peer;
        ast_mutex_lock(&peerl.lock);
@@ -663,7 +676,7 @@ static struct iax2_peer *find_peer(const char *name)
                }
        }
        ast_mutex_unlock(&peerl.lock);
-       if(!peer)
+       if(!peer && realtime)
                peer = realtime_peer(name);
        return peer;
 }
@@ -1623,6 +1636,29 @@ static char jitter_usage[] =
 "to establish the maximum excess jitter buffer that is permitted before the jitter\n"
 "buffer size is reduced.";
 
+static int iax2_prune_realtime(int fd, int argc, char *argv[])
+{
+       struct iax2_peer *peer;
+
+       if (argc != 4)
+        return RESULT_SHOWUSAGE;
+       if (!strcmp(argv[3],"all")) {
+               reload_config();
+               ast_cli(fd, "OK cache is flushed.\n");
+       } else if ((peer = find_peer(argv[3], 0))) {
+               if(ast_test_flag(peer, IAX_RTCACHEFRIENDS)) {
+                       ast_set_flag(peer, IAX_RTAUTOCLEAR);
+                       expire_registry(peer);
+                       ast_cli(fd, "OK peer %s was removed from the cache.\n", argv[3]);
+               } else {
+                       ast_cli(fd, "SORRY peer %s is not eligible for this operation.\n", argv[3]);
+               }
+       } else {
+               ast_cli(fd, "SORRY peer %s was not found in the cache.\n", argv[3]);
+       }
+       
+       return RESULT_SUCCESS;
+}
 
 /*--- iax2_show_peer: Show one peer in detail ---*/
 static int iax2_show_peer(int fd, int argc, char *argv[])
@@ -1632,11 +1668,14 @@ static int iax2_show_peer(int fd, int argc, char *argv[])
        char iabuf[INET_ADDRSTRLEN];
        struct iax2_peer *peer;
        char codec_buf[512];
-       int x = 0, codec = 0;
+       int x = 0, codec = 0, load_realtime = 0;
 
-       if (argc != 4)
+       if (argc < 4)
                return RESULT_SHOWUSAGE;
-       peer = find_peer(argv[3]);
+
+       load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? 1 : 0;
+
+       peer = find_peer(argv[3], load_realtime);
        if (peer) {
                ast_cli(fd,"\n\n");
                ast_cli(fd, "  * Name       : %s\n", peer->name);
@@ -1798,6 +1837,10 @@ static char show_peer_usage[] =
 "Usage: iax show peer <name>\n"
 "       Display details on specific IAX peer\n";
 
+static char prune_realtime_usage[] =
+"Usage: iax2 prune realtime [<peername>|all]\n"
+"       Prunes object(s) from the cache\n";
+
 static struct ast_cli_entry cli_set_jitter = 
 { { "iax2", "set", "jitter", NULL }, iax2_set_jitter, "Sets IAX jitter buffer", jitter_usage };
 
@@ -1810,6 +1853,9 @@ static struct ast_cli_entry cli_show_cache =
 static struct ast_cli_entry  cli_show_peer =
        { { "iax2", "show", "peer", NULL }, iax2_show_peer, "Show details on specific IAX peer", show_peer_usage, complete_iax2_show_peer };
 
+static struct ast_cli_entry  cli_prune_realtime =
+       { { "iax2", "prune", "realtime", NULL }, iax2_prune_realtime, "Prune a cached realtime lookup", prune_realtime_usage, complete_iax2_show_peer };
+
 static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset);
 
 #ifdef BRIDGE_OPTIMIZATION
@@ -2142,6 +2188,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly);
 
 static void destroy_user(struct iax2_user *user);
+static int expire_registry(void *data);
 
 static struct iax2_peer *realtime_peer(const char *peername)
 {
@@ -2153,10 +2200,9 @@ static struct iax2_peer *realtime_peer(const char *peername)
        var = ast_load_realtime("iaxfriends", "name", peername, NULL);
        if (var) {
                /* Make sure it's not a user only... */
-               peer = build_peer(peername, var, 1);
+               peer = build_peer(peername, var, ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS) ? 0 : 1);
+
                if (peer) {
-                       /* Add some finishing touches, addresses, etc */
-                       ast_set_flag(peer, IAX_TEMPONLY);       
                        tmp = var;
                        while(tmp) {
                                if (!strcasecmp(tmp->name, "type")) {
@@ -2180,6 +2226,20 @@ static struct iax2_peer *realtime_peer(const char *peername)
                                }
                                tmp = tmp->next;
                        }
+
+                       /* Add some finishing touches, addresses, etc */
+                       if(ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
+                               ast_mutex_lock(&peerl.lock);
+                               peer->next = peerl.peers;
+                               peerl.peers = peer;
+                               ast_mutex_unlock(&peerl.lock);
+                               ast_copy_flags(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
+                               if (ast_test_flag(peer, IAX_RTAUTOCLEAR))
+                                       peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, (void *)peer);
+                       } else {
+                               ast_set_flag(peer, IAX_TEMPONLY);       
+                       }
+
                        if (peer && dynamic) {
                                time(&nowtime);
                                if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) {
@@ -2202,10 +2262,18 @@ static struct iax2_user *realtime_user(const char *username)
        var = ast_load_realtime("iaxfriends", "name", username, NULL);
        if (var) {
                /* Make sure it's not a user only... */
-               user = build_user(username, var, 1);
+               user = build_user(username, var, !ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS));
                if (user) {
                        /* Add some finishing touches, addresses, etc */
-                       ast_set_flag(user, IAX_TEMPONLY);       
+                       if(ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
+                               ast_mutex_lock(&userl.lock);
+                               user->next = userl.users;
+                               userl.users = user;
+                               ast_mutex_unlock(&userl.lock);
+                               ast_set_flag(user, IAX_RTCACHEFRIENDS);
+                       } else {
+                               ast_set_flag(user, IAX_TEMPONLY);       
+                       }
                        tmp = var;
                        while(tmp) {
                                if (!strcasecmp(tmp->name, "type")) {
@@ -2259,7 +2327,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani,
        if (sockfd)
                *sockfd = defaultsockfd;
        sin->sin_family = AF_INET;
-       p = find_peer(peer);
+       p = find_peer(peer, 1);
        if (p) {
                found++;
                if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
@@ -4344,7 +4412,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        /* We release the lock for the call to prevent a deadlock, but it's okay because
           only the current thread could possibly make it go away or make changes */
        ast_mutex_unlock(&iaxsl[callno]);
-       p = find_peer(peer);
+       p = find_peer(peer, 1);
        ast_mutex_lock(&iaxsl[callno]);
 
        if (!p) {
@@ -4835,6 +4903,7 @@ static void register_peer_exten(struct iax2_peer *peer, int onoff)
                }
        }
 }
+static void prune_peers(void);
 
 static int expire_registry(void *data)
 {
@@ -4850,6 +4919,12 @@ static int expire_registry(void *data)
        register_peer_exten(p, 0);
        if (iax2_regfunk)
                iax2_regfunk(p->name, 0);
+
+       if (!ast_test_flag(p, IAX_RTAUTOCLEAR)) {
+               ast_set_flag(p, IAX_DELME);
+               prune_peers();
+       }
+
        return 0;
 }
 
@@ -4904,9 +4979,9 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
        char iabuf[INET_ADDRSTRLEN];
        int version;
        memset(&ied, 0, sizeof(ied));
-       p = find_peer(name);
+       p = find_peer(name, 1);
        if (p) {
-               if (ast_test_flag(p, IAX_TEMPONLY))
+               if (!ast_test_flag((&globalflags), IAX_RTNOUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
                        realtime_update_peer(name, sin);
                if (inaddrcmp(&p->addr, sin)) {
                        if (iax2_regfunk)
@@ -4980,7 +5055,7 @@ static int registry_authrequest(char *name, int callno)
 {
        struct iax_ie_data ied;
        struct iax2_peer *p;
-       p = find_peer(name);
+       p = find_peer(name, 1);
        if (p) {
                memset(&ied, 0, sizeof(ied));
                iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
@@ -7626,7 +7701,18 @@ static int set_config(char *config_file, int reload)
                        delayreject = ast_true(v->value);
                else if (!strcasecmp(v->name, "mailboxdetail"))
                        ast_set2_flag((&globalflags), ast_true(v->value), IAX_MESSAGEDETAIL);   
-               else if (!strcasecmp(v->name, "trunkfreq")) {
+               else if (!strcasecmp(v->name, "rtcachefriends"))
+                       ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTCACHEFRIENDS);  
+               else if (!strcasecmp(v->name, "rtnoupdate"))
+                       ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTNOUPDATE);      
+               else if (!strcasecmp(v->name, "rtautoclear")) {
+                       int i = atoi(v->value);
+                       if(i > 0)
+                               global_rtautoclear = i;
+                       else
+                               i = 0;
+                       ast_set2_flag((&globalflags), i || ast_true(v->value), IAX_RTAUTOCLEAR);        
+               } else if (!strcasecmp(v->name, "trunkfreq")) {
                        trunkfreq = atoi(v->value);
                        if (trunkfreq < 10)
                                trunkfreq = 10;
@@ -8151,6 +8237,7 @@ static int __unload_module(void)
        ast_cli_unregister(&cli_show_stats);
        ast_cli_unregister(&cli_show_cache);
        ast_cli_unregister(&cli_show_peer);
+       ast_cli_unregister(&cli_prune_realtime);
        ast_unregister_switch(&iax2_switch);
        ast_channel_unregister(channeltype);
        delete_users();
@@ -8222,6 +8309,7 @@ int load_module(void)
        ast_cli_register(&cli_show_peers);
        ast_cli_register(&cli_show_firmware);
        ast_cli_register(&cli_show_registry);
+       ast_cli_register(&cli_prune_realtime);
        ast_cli_register(&cli_provision);
        ast_cli_register(&cli_debug);
        ast_cli_register(&cli_trunk_debug);
index fb00430..d575adc 100755 (executable)
@@ -138,6 +138,7 @@ static char default_fromdomain[AST_MAX_EXTENSION] = "";
 static char default_notifymime[AST_MAX_EXTENSION] = DEFAULT_NOTIFYMIME;
 
 static struct ast_flags global_flags = {0};            /* global SIP_ flags */
+static struct ast_flags global_flags_page2 = {0};              /* more global SIP_ flags */
 
 static int srvlookup = 0;              /* SRV Lookup on or off. Default is off, RFC behavior is on */
 
@@ -302,6 +303,13 @@ struct sip_history {
 #define SIP_OSPAUTH_YES                (1 << 26)
 #define SIP_OSPAUTH_EXCLUSIVE  (2 << 26)
 
+/* a new page of flags */
+#define SIP_PAGE2_RTCACHEFRIENDS       (1 << 0)
+#define SIP_PAGE2_RTNOUPDATE           (1 << 1)
+#define SIP_PAGE2_RTAUTOCLEAR          (1 << 2)
+
+static int global_rtautoclear = 120;
+
 /* sip_pvt: PVT structures are used for each SIP conversation, ie. a call  */
 static struct sip_pvt {
        ast_mutex_t lock;                       /* Channel private lock */
@@ -469,6 +477,7 @@ struct sip_peer {
        int lastmsgssent;
        time_t  lastmsgcheck;           /* Last time we checked for MWI */
        unsigned int flags;             /* SIP_ flags */        
+       struct ast_flags flags_page2; /* SIP_PAGE2 flags */
        int expire;                     /* Registration expiration */
        int expiry;
        int capability;                 /* Codec capability */
@@ -586,7 +595,7 @@ static int build_reply_digest(struct sip_pvt *p, char *orig_header, char *digest
 static int update_user_counter(struct sip_pvt *fup, int event);
 static void prune_peers(void);
 static int sip_do_reload(void);
-
+static int expire_register(void *data);
 static int callevents = 0;
 
 /*--- sip_debug_test_addr: See if we pass debug IP filter */
@@ -1109,7 +1118,9 @@ static void sip_destroy_peer(struct sip_peer *peer)
 /*--- update_peer: Update peer data in database (if used) ---*/
 static void update_peer(struct sip_peer *p, int expiry)
 {
-       if (ast_test_flag(p, SIP_REALTIME))
+       if (!ast_test_flag((&global_flags_page2), SIP_PAGE2_RTNOUPDATE) && 
+               (ast_test_flag(p, SIP_REALTIME) || 
+                ast_test_flag(&(p->flags_page2), SIP_PAGE2_RTCACHEFRIENDS)))
                realtime_update_peer(p->name, &p->addr, p->username, expiry);
 }
 
@@ -1144,9 +1155,18 @@ static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *
                tmp = tmp->next;
        }
 
-       peer = build_peer(peername, var, 1);
-       if (peer)
-               ast_set_flag(peer, SIP_REALTIME);
+       peer = build_peer(peername, var, ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS) ? 0 : 1);
+       if (peer) {
+               if(ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
+                       ast_copy_flags((&peer->flags_page2),(&global_flags_page2), SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS);
+                       if(ast_test_flag((&global_flags_page2), SIP_PAGE2_RTAUTOCLEAR)) {
+                               peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_register, (void *)peer);
+                       }
+                       ASTOBJ_CONTAINER_LINK(&peerl,peer);
+               } else {
+                       ast_set_flag(peer, SIP_REALTIME);
+               }
+       }
        ast_variables_destroy(var);
        return peer;
 }
@@ -1161,7 +1181,7 @@ static int sip_addrcmp(char *name, struct sockaddr_in *sin)
 }
 
 /*--- find_peer: Locate peer by name or ip address */
-static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin)
+static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
 {
        struct sip_peer *p = NULL;
 
@@ -1170,7 +1190,7 @@ static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin)
        else
                p = ASTOBJ_CONTAINER_FIND_FULL(&peerl,sin,name,sip_addr_hashfunc,1,sip_addrcmp);
 
-       if (!p) {
+       if (!p && realtime) {
                p = realtime_peer(peer, sin);
        }
 
@@ -1206,20 +1226,29 @@ static struct sip_user *realtime_user(const char *username)
        tmp = var;
        while (tmp) {
                if (!strcasecmp(tmp->name, "type") &&
-                   !strcasecmp(tmp->value, "peer")) {
+                       !strcasecmp(tmp->value, "peer")) {
                        ast_variables_destroy(var);
                        return NULL;
                }
                tmp = tmp->next;
        }
+       
+
 
-       user = build_user(username, var, 1);
+       user = build_user(username, var, !ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS));
+       
        if (user) {
-               /* Move counter from s to r... */
-               suserobjs--;
-               ruserobjs++;
                /* Add some finishing touches, addresses, etc */
-               ast_set_flag(user, SIP_REALTIME);       
+               if(ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
+                       suserobjs++;
+
+            ASTOBJ_CONTAINER_LINK(&userl,user);
+        } else {
+                       /* Move counter from s to r... */
+                       suserobjs--;
+                       ruserobjs++;
+            ast_set_flag(user, SIP_REALTIME);
+        }
        }
        ast_variables_destroy(var);
        return user;
@@ -1258,7 +1287,7 @@ static int create_addr(struct sip_pvt *r, char *opeer)
                port++;
        }
        r->sa.sin_family = AF_INET;
-       p = find_peer(peer, NULL);
+       p = find_peer(peer, NULL, 1);
 
        if (p) {
                found++;
@@ -4458,7 +4487,7 @@ static int expire_register(void *data)
        register_peer_exten(p, 0);
        p->expire = -1;
        ast_device_state_changed("SIP/%s", p->name);
-       if (ast_test_flag(p, SIP_SELFDESTRUCT)) {
+       if (ast_test_flag(p, SIP_SELFDESTRUCT) || ast_test_flag((&p->flags_page2), SIP_PAGE2_RTAUTOCLEAR)) {
                ASTOBJ_MARK(p); 
                prune_peers();
        }
@@ -5074,7 +5103,7 @@ static int register_verify(struct sip_pvt *p, struct sockaddr_in *sin, struct si
                *c = '\0';
        strncpy(p->exten, name, sizeof(p->exten) - 1);
        build_contact(p);
-       peer = find_peer(name, NULL);
+       peer = find_peer(name, NULL, 1);
        if (!(peer && ast_apply_ha(peer->ha, sin))) {
                if (peer)
                        ASTOBJ_UNREF(peer,sip_destroy_peer);
@@ -5670,7 +5699,7 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                /* If peer is registred from this IP address or have this as a default
                   IP address, this call is from the peer 
                */
-               peer = find_peer(NULL, &p->recv);
+               peer = find_peer(NULL, &p->recv, 1);
                if (peer) {
                        if (debug)
                                ast_verbose("Found peer '%s'\n", peer->name);
@@ -5863,7 +5892,7 @@ static int sip_show_users(int fd, int argc, char *argv[])
        regex_t regexbuf;
        int havepattern = 0;
 
-#define FORMAT  "%-25.25s  %-15.15s  %-15.15s  %-15.15s  %-5.5s%-5.5s\n"
+#define FORMAT  "%-25.25s  %-15.15s  %-15.15s  %-15.15s  %-5.5s%-10.10s\n"
 
        if (argc > 4)
                return RESULT_SHOWUSAGE;
@@ -6051,6 +6080,30 @@ static const char *insecure2str(int mode)
        return "<error>";
 }
 
+static int sip_prune_realtime(int fd, int argc, char *argv[])
+{
+       struct sip_peer *peer;
+
+       if (argc != 4)
+        return RESULT_SHOWUSAGE;
+       if (!strcmp(argv[3],"all")) {
+               sip_do_reload();
+               ast_cli(fd, "OK Cache is flushed.\n");
+       } else if ((peer = find_peer(argv[3], NULL, 0))) {
+               if(ast_test_flag((&peer->flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) {
+                       ast_set_flag((&peer->flags_page2), SIP_PAGE2_RTAUTOCLEAR);
+                       expire_register(peer);
+                       ast_cli(fd, "OK peer %s was removed from the cache.\n", argv[3]);
+               } else {
+                       ast_cli(fd, "SORRY peer %s is not eligible for this operation.\n", argv[3]);
+               }
+       } else {
+               ast_cli(fd, "SORRY peer %s was not found in the cache.\n", argv[3]);
+       }
+       
+       return RESULT_SUCCESS;
+}
+
 /*--- sip_show_peer: Show one peer in detail ---*/
 static int sip_show_peer(int fd, int argc, char *argv[])
 {
@@ -6060,11 +6113,13 @@ static int sip_show_peer(int fd, int argc, char *argv[])
        struct sip_peer *peer;
        char codec_buf[512];
        struct ast_codec_pref *pref;
-       int x = 0, codec = 0;
+       int x = 0, codec = 0, load_realtime = 0;
 
-       if (argc != 4)
+       if (argc < 4)
                return RESULT_SHOWUSAGE;
-       peer = find_peer(argv[3], NULL);
+
+       load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? 1 : 0;
+       peer = find_peer(argv[3], NULL, load_realtime);
        if (peer) {
                ast_cli(fd,"\n\n");
                ast_cli(fd, "  * Name       : %s\n", peer->name);
@@ -6530,7 +6585,7 @@ static int sip_do_debug_peer(int fd, int argc, char *argv[])
        char iabuf[INET_ADDRSTRLEN];
        if (argc != 4)
                return RESULT_SHOWUSAGE;
-       peer = find_peer(argv[3], NULL);
+       peer = find_peer(argv[3], NULL, 1);
        if (peer) {
                if (peer->addr.sin_addr.s_addr) {
                        debugaddr.sin_family = AF_INET;
@@ -6875,6 +6930,10 @@ static char show_peer_usage[] =
 "Usage: sip show peer <peername>\n"
 "       Lists all details on one SIP peer and the current status.\n";
 
+static char prune_realtime_usage[] =
+"Usage: sip prune realtime [<peername>|all]\n"
+"       Prunes object(s) from the cache\n";
+
 static char show_reg_usage[] =
 "Usage: sip show registry\n"
 "       Lists all registration requests and status.\n";
@@ -6913,6 +6972,9 @@ static char show_objects_usage[] =
 "Usage: sip show objects\n" 
 "       Shows status of known SIP objects\n";
 
+
+
+
 static struct ast_cli_entry  cli_notify =
        { { "sip", "notify", NULL }, sip_notify, "Send a notify packet to a SIP peer", notify_usage, complete_sipnotify };
 static struct ast_cli_entry  cli_show_objects = 
@@ -6935,6 +6997,8 @@ static struct ast_cli_entry  cli_show_peer =
        { { "sip", "show", "peer", NULL }, sip_show_peer, "Show details on specific SIP peer", show_peer_usage, complete_sip_show_peer };
 static struct ast_cli_entry  cli_show_peers =
        { { "sip", "show", "peers", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
+static struct ast_cli_entry  cli_prune_realtime =
+       { { "sip", "prune", "realtime", NULL }, sip_prune_realtime, "Prune a cached realtime lookup", prune_realtime_usage, complete_sip_show_peer };
 static struct ast_cli_entry  cli_inuse_show =
        { { "sip", "show", "inuse", NULL }, sip_show_inuse, "List all inuse/limit", show_inuse_usage };
 static struct ast_cli_entry  cli_show_registry =
@@ -8512,7 +8576,7 @@ static int sip_devicestate(void *data)
                ext = NULL;
        }
 
-       p = find_peer(host, NULL);
+       p = find_peer(host, NULL, 1);
        if (p) {
                found++;
                res = AST_DEVICE_UNAVAILABLE;
@@ -9127,6 +9191,17 @@ static int reload_config(void)
                        strncpy(default_useragent, v->value, sizeof(default_useragent)-1);
                        ast_log(LOG_DEBUG, "Setting User Agent Name to %s\n",
                                default_useragent);
+               } else if (!strcasecmp(v->name, "rtcachefriends")) {
+                       ast_set2_flag((&global_flags_page2), ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS);     
+               } else if (!strcasecmp(v->name, "rtnoupdate")) {
+                       ast_set2_flag((&global_flags_page2), ast_true(v->value), SIP_PAGE2_RTNOUPDATE); 
+               } else if (!strcasecmp(v->name, "rtautoclear")) {
+                       int i = atoi(v->value);
+                       if(i > 0)
+                               global_rtautoclear = i;
+                       else
+                               i = 0;
+                       ast_set2_flag((&global_flags_page2), i || ast_true(v->value), SIP_PAGE2_RTAUTOCLEAR);
                } else if (!strcasecmp(v->name, "usereqphone")) {
                        ast_set2_flag((&global_flags), ast_true(v->value), SIP_USEREQPHONE);    
                } else if (!strcasecmp(v->name, "relaxdtmf")) {
@@ -9689,6 +9764,7 @@ int load_module()
                ast_cli_register(&cli_show_channels);
                ast_cli_register(&cli_show_channel);
                ast_cli_register(&cli_show_history);
+               ast_cli_register(&cli_prune_realtime);
                ast_cli_register(&cli_show_peer);
                ast_cli_register(&cli_show_peers);
                ast_cli_register(&cli_show_registry);
@@ -9728,6 +9804,7 @@ int unload_module()
        ast_cli_unregister(&cli_show_channels);
        ast_cli_unregister(&cli_show_channel);
        ast_cli_unregister(&cli_show_history);
+       ast_cli_unregister(&cli_prune_realtime);
        ast_cli_unregister(&cli_show_peer);
        ast_cli_unregister(&cli_show_peers);
        ast_cli_unregister(&cli_show_registry);
index dd7f5e5..b9033fe 100755 (executable)
@@ -192,6 +192,26 @@ tos=lowdelay
 ; The default value is 'host'
 ;
 autokill=yes
+
+;
+; Cache realtime friends by adding them to the internal list
+; just like friends added from the config file only on a
+; as-needed basis.
+;
+;rtcachefriends=yes 
+;
+; do not send the update request over realtime.
+;
+;rtnoupdate=yes 
+;
+; Auto-Expire friends created on the fly on the same schedule
+; as if it had just registered when the registration expires
+; the friend will vanish from the configuration until requested
+; again.  If set to an integer, friends expire
+; within this number of seconds instead of the
+; same as the registration interval
+;
+;rtautoclear=yes 
 ;
 ; Guest sections for unauthenticated connection attempts.  Just
 ; specify an empty secret, or provide no secret section.
index 0506173..d2d02ed 100755 (executable)
@@ -157,6 +157,18 @@ srvlookup=yes                      ; Enable DNS SRV lookups on outbound calls
                                ; route = Assume NAT, don't send rport 
                                ; (work around more UNIDEN bugs)
 
+;rtcachefriends=yes ; Cache realtime friends by adding them to the internal list
+                               ; just like friends added from the config file only on a
+                                ; as-needed basis.
+;rtnoupdate=yes ; do not send the update request over realtime.
+;rtautoclear=yes ; Auto-Expire friends created on the fly on the same schedule
+                                ; as if it had just registered when the registration expires
+                                ; the friend will vanish from the configuration until requested
+                                ; again.  If set to an integer, friends expire
+                                                               ; within this number of seconds instead of the
+                                                               ; same as the registration interval
+
+
 ;-----------------------------------------------------------------------------------
 ; Users and peers have different settings available. Friends have all settings,
 ; since a friend is both a peer and a user