From 7afeceb47eece55449dc2e5d3b073ebd0232e8c1 Mon Sep 17 00:00:00 2001 From: Joseph Nadiv Date: Sat, 30 Oct 2021 21:14:00 -0400 Subject: [PATCH] [mod_sofia] Randomize OPTIONS Ping interval In FS-6400, the attempt was made to randomize OPTIONS packets to be sent at a random interval. The same random interval is applied to all endpoints so this doesn't work. Furthermore, rounding within the code, as well as reseeding with srand() on each run will ultimately make the ping times converge over time. Once the times converge, they will not separate since the reseeding will cause the same random number to apply to each registration. This commmit will apply the random interval only during initial registration and update of registration. All subsequent pings will be incremented with the actual value of ping-mean-interval. (This parameter name is no longer accurate, and would be better named ping-max-interval). srand() has been moved to the start of the worker thread, and all repeat calls have been removed, so that each call of rand(), even during the same second, generates a different random number. Fixes #1132, Fixes #1133 --- src/mod/endpoints/mod_sofia/sofia.c | 3 +++ src/mod/endpoints/mod_sofia/sofia_presence.c | 1 - src/mod/endpoints/mod_sofia/sofia_reg.c | 23 ++++++++++---------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 6f73823b86..77c0b2d493 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2949,6 +2949,9 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread sofia_set_pflag_locked(profile, PFLAG_WORKER_RUNNING); + /* Seed PRNG for functions within worker thread */ + srand((unsigned)((intptr_t) switch_thread_self() + switch_micro_time_now())); + while ((mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING))) { if (tick) { diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 00cc8561d6..89324ebe82 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -3755,7 +3755,6 @@ void sofia_presence_handle_sip_i_subscribe(int status, if ((sub_max_deviation_var = profile->sip_subscription_max_deviation)) { int sub_deviation; - srand( (unsigned) ( (unsigned)(intptr_t)switch_thread_self() + switch_micro_time_now() ) ); /* random negative number between 0 and negative sub_max_deviation_var: */ sub_deviation = ( rand() % sub_max_deviation_var ) - sub_max_deviation_var; if ( (exp_delta + sub_deviation) > 45 ) { diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 9791190f5f..d9e04528a8 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -884,7 +884,6 @@ long sofia_reg_uniform_distribution(int max) int result; int range = max + 1; - srand((unsigned)((intptr_t) 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); @@ -894,8 +893,7 @@ long sofia_reg_uniform_distribution(int max) void sofia_reg_check_ping_expire(sofia_profile_t *profile, time_t now, int interval) { char *sql; - int mean = interval / 2; - long next, irand; + long next; char buf[32] = ""; int count; @@ -952,8 +950,7 @@ void sofia_reg_check_ping_expire(sofia_profile_t *profile, time_t now, int inter /* 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; + next = (long) now + interval; sql = switch_mprintf("update sip_registrations set ping_expires = %ld where hostname='%q' and profile_name='%q' and ping_expires <= %ld ", next, mod_sofia_globals.hostname, profile->name, (long) now); @@ -1765,7 +1762,6 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu (( exp_max_deviation_var = profile->sip_expires_max_deviation )) ) { if (exp_max_deviation_var > 0) { int exp_deviation; - srand( (unsigned) ( (unsigned)(intptr_t)switch_thread_self() + switch_micro_time_now() ) ); /* random number between negative exp_max_deviation_var and positive exp_max_deviation_var: */ exp_deviation = ( rand() % ( exp_max_deviation_var * 2 ) ) - exp_max_deviation_var; exptime += exp_deviation; @@ -2013,23 +2009,26 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu sql = switch_mprintf("insert into sip_registrations " "(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires," "user_agent,server_user,server_host,profile_name,hostname,network_ip,network_port,sip_username,sip_realm," - "mwi_user,mwi_host, orig_server_host, orig_hostname, sub_host, ping_status, ping_count, force_ping) " - "values ('%q','%q', '%q','%q','%q','%q', '%q', %ld, '%q', '%q', '%q', '%q', '%q', '%q', '%q','%q','%q','%q','%q','%q','%q','%q', '%q', %d, %d)", + "mwi_user,mwi_host, orig_server_host, orig_hostname, sub_host, ping_status, ping_count, ping_expires, force_ping) " + "values ('%q','%q', '%q','%q','%q','%q', '%q', %ld, '%q', '%q', '%q', '%q', '%q', '%q', '%q','%q','%q','%q','%q','%q','%q','%q', '%q', %d, %ld, %d)", call_id, to_user, reg_host, profile->presence_hosts ? profile->presence_hosts : "", contact_str, reg_desc, rpid, (long) reg_time + (long) exptime + profile->sip_expires_late_margin, agent, from_user, guess_ip4, profile->name, mod_sofia_globals.hostname, network_ip, network_port_c, username, realm, - mwi_user, mwi_host, guess_ip4, mod_sofia_globals.hostname, sub_host, "Reachable", 0, force_ping); + mwi_user, mwi_host, guess_ip4, mod_sofia_globals.hostname, sub_host, "Reachable", 0, + (long) switch_epoch_time_now(NULL) + sofia_reg_uniform_distribution(profile->iping_seconds), force_ping); } else { sql = switch_mprintf("update sip_registrations set call_id='%q'," "sub_host='%q', network_ip='%q',network_port='%q'," "presence_hosts='%q', server_host='%q', orig_server_host='%q'," "hostname='%q', orig_hostname='%q'," - "expires = %ld, force_ping=%d where sip_user='%q' and sip_username='%q' and sip_host='%q' and contact='%q'", + "expires = %ld, ping_expires=%ld, force_ping=%d " + "where sip_user='%q' and sip_username='%q' and sip_host='%q' and contact='%q'", call_id, sub_host, network_ip, network_port_c, profile->presence_hosts ? profile->presence_hosts : "", guess_ip4, guess_ip4, mod_sofia_globals.hostname, mod_sofia_globals.hostname, - (long) reg_time + (long) exptime + profile->sip_expires_late_margin, force_ping, - to_user, username, reg_host, contact_str); + (long) reg_time + (long) exptime + profile->sip_expires_late_margin, + (long) switch_epoch_time_now(NULL) + sofia_reg_uniform_distribution(profile->iping_seconds), + force_ping, to_user, username, reg_host, contact_str); } if (sql) {