]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-6400 Improve sip ping generation by distributing them across an interval
authorMatteo Brancaleoni <mbrancaleoni@voismart.it>
Mon, 22 Sep 2014 08:44:53 +0000 (10:44 +0200)
committerMatteo Brancaleoni <mbrancaleoni@voismart.it>
Tue, 14 Oct 2014 12:24:21 +0000 (14:24 +0200)
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_glue.c
src/mod/endpoints/mod_sofia/sofia_reg.c

index f4e361318c273664279dfe38342b3e2683a7065b..c15cbdc14d150acac4ad8ddd9a76f8d6ffe815f4 100644 (file)
@@ -43,6 +43,8 @@
 #define SQL_CACHE_TIMEOUT 300
 #define DEFAULT_NONCE_TTL 60
 #define IREG_SECONDS 30
+#define IPING_SECONDS 30
+#define IPING_FREQUENCY 1
 #define GATEWAY_SECONDS 1
 #define SOFIA_QUEUE_SIZE 50000
 #define HAVE_APR
@@ -720,6 +722,8 @@ struct sofia_profile {
        uint32_t sip_expires_late_margin;
        uint32_t sip_subscription_max_deviation;
        int ireg_seconds;
+       int iping_seconds;
+       int iping_freq;
        sofia_paid_type_t paid_type;
        uint32_t rtp_digit_delay;
        switch_queue_t *event_queue;
@@ -976,6 +980,7 @@ void sofia_glue_actually_execute_sql_trans(sofia_profile_t *profile, char *sql,
 void sofia_glue_execute_sql_now(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic);
 void sofia_glue_execute_sql_soon(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic);
 void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot);
+void sofia_reg_check_ping_expire(sofia_profile_t *profile, time_t now, int interval);
 void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now);
 void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now);
 void sofia_reg_unregister(sofia_profile_t *profile);
index 3c92207ebe8046db995b94bef136f6ef14d938da..054b656db6418e2d5358cc274684c0f4912971f6 100644 (file)
@@ -2574,6 +2574,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread
 {
        sofia_profile_t *profile = (sofia_profile_t *) obj;
        uint32_t ireg_loops = profile->ireg_seconds;                                    /* Number of loop iterations done when we haven't checked for registrations */
+       uint32_t iping_loops = profile->iping_freq;                                     /* Number of loop iterations done when we haven't checked for ping expires */
        uint32_t gateway_loops = GATEWAY_SECONDS;                       /* Number of loop iterations done when we haven't checked for gateways */
 
        sofia_set_pflag_locked(profile, PFLAG_WORKER_RUNNING);
@@ -2618,6 +2619,12 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread
                                sofia_reg_check_expire(profile, now, 0);
                                ireg_loops = 0;
                        }
+       
+                       if(++iping_loops >= (uint32_t)profile->iping_freq) {
+                               time_t now = switch_epoch_time_now(NULL);
+                               sofia_reg_check_ping_expire(profile, now, profile->iping_seconds);
+                               iping_loops = 0;
+                       }
 
                        if (++gateway_loops >= GATEWAY_SECONDS) {
                                sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
@@ -4099,6 +4106,8 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
                                        profile->mndlb |= SM_NDLB_ALLOW_NONDUP_SDP;
                                        profile->te = 101;
                                        profile->ireg_seconds = IREG_SECONDS;
+                                       profile->iping_seconds = IPING_SECONDS;
+                                       profile->iping_freq = IPING_FREQUENCY;
                                        profile->paid_type = PAID_DEFAULT;
                                        profile->bind_attempts = 2;
                                        profile->bind_attempt_interval = 5;
@@ -4229,6 +4238,16 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
                                                if (profile->ireg_seconds < 0) {
                                                        profile->ireg_seconds = IREG_SECONDS;
                                                }
+                                       } else if (!strcasecmp(var, "ping-mean-interval")) {
+                                               profile->iping_seconds = atoi(val);
+                                               if (profile->iping_seconds < 0) {
+                                                       profile->iping_seconds = IPING_SECONDS;
+                                               }
+                                       } else if (!strcasecmp(var, "ping-thread-frequency")) {
+                                               profile->iping_freq = atoi(val);
+                                               if (profile->iping_freq < 0) {
+                                                       profile->iping_freq = IPING_FREQUENCY;
+                                               }
                                        } else if (!strcasecmp(var, "user-agent-string")) {
                                                profile->user_agent = switch_core_strdup(profile->pool, val);
                                        } else if (!strcasecmp(var, "auto-restart")) {
index 0773e45b5091500008e30a55a2dc24b59c2d4685..3ed3e42e1497b87d64854f913b05ac513bea38dc 100644 (file)
@@ -1993,6 +1993,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
                "   ping_count       INTEGER,\n"
                "   rpid             VARCHAR(255),\n"
                "   expires          BIGINT,\n"
+               "   ping_expires     INTEGER not null default 0,\n"
                "   user_agent       VARCHAR(255),\n"
                "   server_user      VARCHAR(255),\n"
                "   server_host      VARCHAR(255),\n"
@@ -2121,6 +2122,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
                "create index sr_presence_hosts on sip_registrations (presence_hosts)",
                "create index sr_contact on sip_registrations (contact)",
                "create index sr_expires on sip_registrations (expires)",
+               "create index sr_ping_expires on sip_registrations (ping_expires)",
                "create index sr_hostname on sip_registrations (hostname)",
                "create index sr_status on sip_registrations (status)",
                "create index sr_ping_status on sip_registrations (ping_status)",
@@ -2205,6 +2207,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
 
        switch_cache_db_test_reactive(dbh, "select ping_count from sip_registrations", NULL, "alter table sip_registrations add column ping_count INTEGER default 0");
        switch_cache_db_test_reactive(dbh, "select ping_status from sip_registrations", NULL, "alter table sip_registrations add column ping_status VARCHAR(255) default \"Reachable\"");
+       switch_cache_db_test_reactive(dbh, "select ping_expires from sip_registrations", NULL, "alter table sip_registrations add column ping_expires INTEGER not null default 0");
        
        test2 = switch_mprintf("%s;%s", test_sql, test_sql);
                        
index d4177195d11f42e622775bd1f29c5840cd538082..108aaf54d16398ad3f4ad547e987bc5318df3524 100644 (file)
@@ -846,21 +846,45 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
 
        sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 
+}
+
+long sofia_reg_uniform_distribution(int max)
+{
+/* 
+ * Generate a random number following a uniform distribution between 0 and max
+ */
+       int result;
+       int range = max + 1;
+
+       srand((unsigned) switch_thread_self() + switch_micro_time_now());
+       result = (int)((double)rand() / (((double)RAND_MAX + (double)1) / range));
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9, "Generated random %ld, max is %d\n", (long) result, max);
+       return (long) result;
+}
+
+void sofia_reg_check_ping_expire(sofia_profile_t *profile, time_t now, int interval)
+{
+       char *sql;
+       int mean = interval / 2;
+       long next, irand;
 
        if (now) {
                if (sofia_test_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING)) {
                        sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,"
                                                        "expires,user_agent,server_user,server_host,profile_name"
  " from sip_registrations where hostname='%s' and " 
- "profile_name='%s' and orig_hostname='%s'", mod_sofia_globals.hostname, profile->name, mod_sofia_globals.hostname); 
+ "profile_name='%s' and orig_hostname='%s' and "
+ "ping_expires > 0 and ping_expires <= %ld", mod_sofia_globals.hostname, profile->name, mod_sofia_globals.hostname, (long) now); 
                        
                        sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_nat_callback, profile);
                        switch_safe_free(sql);
                } else if (sofia_test_pflag(profile, PFLAG_UDP_NAT_OPTIONS_PING)) {
-                       sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,"
-                                                       "expires,user_agent,server_user,server_host,profile_name"
-                                                       " from sip_registrations where status like '%%UDP-NAT%%' "
- "and hostname='%s' and profile_name='%s'", mod_sofia_globals.hostname, profile->name); 
+                       sql = switch_mprintf(   " select call_id,sip_user,sip_host,contact,status,rpid, "
+                                               " expires,user_agent,server_user,server_host,profile_name "
+                                               " from sip_registrations where status like '%%UDP-NAT%%' "
+                                               " and hostname='%s' and profile_name='%s' and ping_expires > 0 and ping_expires <= %ld ",
+                                               mod_sofia_globals.hostname, profile->name, (long) now); 
                        
                        sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_nat_callback, profile);
                        switch_safe_free(sql);
@@ -869,11 +893,37 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
                                                        "expires,user_agent,server_user,server_host,profile_name"
                                                        " from sip_registrations where (status like '%%NAT%%' "
  "or contact like '%%fs_nat=yes%%') and hostname='%s' " 
- "and profile_name='%s' and orig_hostname='%s'", mod_sofia_globals.hostname, profile->name, mod_sofia_globals.hostname); 
+ "and profile_name='%s' and orig_hostname='%s' and "
+ "ping_expires > 0 and ping_expires <= %ld", mod_sofia_globals.hostname, profile->name, mod_sofia_globals.hostname, (long) now); 
                        
                        sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_nat_callback, profile);
                        switch_safe_free(sql);
                }
+
+               if (sofia_test_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING) ||
+                       sofia_test_pflag(profile, PFLAG_UDP_NAT_OPTIONS_PING) || 
+                       sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) {
+                       char buf[32] = "";
+                       int count;
+
+                       sql = switch_mprintf("select count(*) from sip_registrations where hostname='%q' and profile_name='%q' and ping_expires <= %ld",
+                                               mod_sofia_globals.hostname, profile->name, (long) now);
+
+                       sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf));
+                       switch_safe_free(sql);
+                       count = atoi(buf);
+
+                       /* only update if needed */
+                       if (count) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9, "Updating ping expires for profile %s\n", profile->name);
+                               irand = mean + sofia_reg_uniform_distribution(interval);
+                               next = (long) now + irand;
+       
+                               sql = switch_mprintf(" update sip_registrations set ping_expires = %ld where ping_expires <= %ld ",
+                                                       next, (long) now);
+                               sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+                       }
+               }
        }
 
 }