--- chan_sip.orig 2013-11-18 07:20:05.000000000 -0700 +++ chan_sip.c 2013-11-16 16:05:15.000000000 -0700 @@ -737,6 +737,7 @@ static int global_timer_b; /*!< Timer B - RFC 3261 Section 17.1.1.2 */ static unsigned int global_autoframing; /*!< Turn autoframing on or off. */ static int global_qualifyfreq; /*!< Qualify frequency */ +static int global_qualifynotok; /*!< Qualify frequency when unreachable */ static int global_qualify_gap; /*!< Time between our group of peer pokes */ static int global_qualify_peers; /*!< Number of peers to poke at a given time */ @@ -4533,6 +4534,7 @@ * bugs 15156 and 15895 */ if (fc) { + if (sip_cfg.peer_rtlastms) { ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, "port", port, "regseconds", regseconds, deprecated_username ? "username" : "defaultuser", defaultuser, @@ -4541,9 +4543,22 @@ } else { ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, "port", port, "regseconds", regseconds, + deprecated_username ? "username" : "defaultuser", defaultuser, + "useragent", useragent, fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */ + } + } else { + if (sip_cfg.peer_rtlastms) { + ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, + "port", port, "regseconds", regseconds, "useragent", useragent, "lastms", str_lastms, deprecated_username ? "username" : "defaultuser", defaultuser, syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */ + } else { + ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, + "port", port, "regseconds", regseconds, + "useragent", useragent, deprecated_username ? "username" : "defaultuser", defaultuser, + syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */ + } } } @@ -13752,7 +13767,11 @@ if (!sip_cfg.ignore_regexpire) { if (peer->rt_fromcontact && sip_cfg.peer_rtupdate) { + if (!sip_cfg.peer_rtlastms) { + ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "regserver", "", "useragent", "", SENTINEL); + } else { ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "regserver", "", "useragent", "", "lastms", "0", SENTINEL); + } } else { ast_db_del("SIP/Registry", peer->name); ast_db_del("SIP/PeerMethods", peer->name); @@ -17656,6 +17675,7 @@ ast_cli(fd, " Useragent : %s\n", peer->useragent); ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact); ast_cli(fd, " Qualify Freq : %d ms\n", peer->qualifyfreq); + ast_cli(fd, " Qualify NotOK: %d ms\n", peer->qualifynotok); if (peer->chanvars) { ast_cli(fd, " Variables :\n"); for (v = peer->chanvars ; v ; v = v->next) @@ -17755,6 +17775,7 @@ astman_append(s, "SIP-Useragent: %s\r\n", peer->useragent); astman_append(s, "Reg-Contact: %s\r\n", peer->fullcontact); astman_append(s, "QualifyFreq: %d ms\r\n", peer->qualifyfreq); + astman_append(s, "QualifyNotOK: %d ms\r\n", peer->qualifynotok); astman_append(s, "Parkinglot: %s\r\n", peer->parkinglot); if (peer->chanvars) { for (v = peer->chanvars ; v ; v = v->next) { @@ -18218,6 +18239,7 @@ else ast_cli(a->fd, " SIP realtime: Enabled\n" ); ast_cli(a->fd, " Qualify Freq : %d ms\n", global_qualifyfreq); + ast_cli(a->fd, " Qualify NotOK : %d ms\n", global_qualifynotok); ast_cli(a->fd, " Q.850 Reason header: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_Q850_REASON))); ast_cli(a->fd, " Store SIP_CAUSE: %s\n", AST_CLI_YESNO(global_store_sip_cause)); ast_cli(a->fd, "\nNetwork QoS Settings:\n"); @@ -18335,6 +18357,7 @@ ast_cli(a->fd, " Realtime Regs: %s\n", AST_CLI_YESNO(realtimeregs)); ast_cli(a->fd, " Cache Friends: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS))); ast_cli(a->fd, " Update: %s\n", AST_CLI_YESNO(sip_cfg.peer_rtupdate)); + ast_cli(a->fd, " Update Lastms: %s\n", AST_CLI_YESNO(sip_cfg.peer_rtlastms)); ast_cli(a->fd, " Ignore Reg. Expire: %s\n", AST_CLI_YESNO(sip_cfg.ignore_regexpire)); ast_cli(a->fd, " Save sys. name: %s\n", AST_CLI_YESNO(sip_cfg.rtsave_sysname)); ast_cli(a->fd, " Auto Clear: %d (%s)\n", sip_cfg.rtautoclear, ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR) ? "Enabled" : "Disabled"); @@ -20955,7 +20978,7 @@ ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n", peer->name, s, pingtime, peer->maxms); ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name); - if (sip_cfg.peer_rtupdate) { + if (sip_cfg.peer_rtupdate && sip_cfg.peer_rtlastms) { ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", str_lastms, SENTINEL); } manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", @@ -20969,7 +20992,7 @@ /* Try again eventually */ AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, - is_reachable ? peer->qualifyfreq : DEFAULT_FREQ_NOTOK, + is_reachable ? peer->qualifyfreq : peer->qualifynotok, sip_poke_peer_s, peer, unref_peer(_data, "removing poke peer ref"), unref_peer(peer, "removing poke peer ref"), @@ -26385,7 +26408,7 @@ if (peer->lastms > -1) { ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Last qualify: %d\n", peer->name, peer->lastms); - if (sip_cfg.peer_rtupdate) { + if (sip_cfg.peer_rtupdate && sip_cfg.peer_rtlastms) { ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", "-1", SENTINEL); } manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, -1); @@ -26408,7 +26431,7 @@ /* Try again quickly */ AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, - DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer, + peer->qualifynotok, sip_poke_peer_s, peer, unref_peer(_data, "removing poke peer ref"), unref_peer(peer, "removing poke peer ref"), ref_peer(peer, "adding poke peer ref")); @@ -27272,6 +27295,7 @@ peer->autoframing = global_autoframing; peer->t38_maxdatagram = global_t38_maxdatagram; peer->qualifyfreq = global_qualifyfreq; + peer->qualifynotok = global_qualifynotok; if (global_callcounter) peer->call_limit=INT_MAX; ast_string_field_set(peer, vmexten, default_vmexten); @@ -27384,7 +27408,7 @@ int firstpass = 1; uint16_t port = 0; int format = 0; /* Ama flags */ - int timerb_set = 0, timert1_set = 0; + int peer_timert1_set = 0; time_t regseconds = 0; struct ast_flags peerflags[3] = {{(0)}}; struct ast_flags mask[3] = {{(0)}}; @@ -27758,17 +27782,16 @@ peer->rtpkeepalive = global_rtpkeepalive; } } else if (!strcasecmp(v->name, "timert1")) { - if ((sscanf(v->value, "%30d", &peer->timer_t1) != 1) || (peer->timer_t1 < 200) || (peer->timer_t1 < global_t1min)) { + if ((sscanf(v->value, "%30d", &peer->timer_t1) != 1) || (peer->timer_t1 < 50)) { ast_log(LOG_WARNING, "'%s' is not a valid T1 time at line %d. Using default.\n", v->value, v->lineno); - peer->timer_t1 = global_t1min; + peer->timer_t1 = global_t1; } - timert1_set = 1; + peer_timert1_set = 1; } else if (!strcasecmp(v->name, "timerb")) { - if ((sscanf(v->value, "%30d", &peer->timer_b) != 1) || (peer->timer_b < 200)) { + if ((sscanf(v->value, "%30d", &peer->timer_b) != 1) || (peer->timer_b < 3200)) { ast_log(LOG_WARNING, "'%s' is not a valid Timer B time at line %d. Using default.\n", v->value, v->lineno); peer->timer_b = global_timer_b; } - timerb_set = 1; } else if (!strcasecmp(v->name, "setvar")) { peer->chanvars = add_var(v->value, peer->chanvars); } else if (!strcasecmp(v->name, "header")) { @@ -27783,6 +27806,14 @@ ast_log(LOG_WARNING, "Invalid qualifyfreq number '%s' at line %d of %s\n", v->value, v->lineno, config); peer->qualifyfreq = global_qualifyfreq; } + } else if (!strcasecmp(v->name, "qualifynotok")) { + int i; + if (sscanf(v->value, "%30d", &i) == 1) { + peer->qualifynotok = i * 1000; + } else { + ast_log(LOG_WARNING, "Invalid qualifynotok number '%s' at line %d of %s\n", v->value, v->lineno, config); + peer->qualifynotok = global_qualifynotok; + } } else if (!strcasecmp(v->name, "maxcallbitrate")) { peer->maxcallbitrate = atoi(v->value); if (peer->maxcallbitrate < 0) { @@ -27903,20 +27934,16 @@ ast_set_cc_agent_policy(peer->cc_params, AST_CC_AGENT_NEVER); } - /* Note that Timer B is dependent upon T1 and MUST NOT be lower - * than T1 * 64, according to RFC 3261, Section 17.1.1.2 */ + /* Note that Timer B is dependent upon Timer T1 and MUST NOT be lower + * than Timer T1 * 64, according to RFC 3261, Section 17.1.1.2 */ if (peer->timer_b < peer->timer_t1 * 64) { - if (timerb_set && timert1_set) { - ast_log(LOG_WARNING, "Timer B has been set lower than recommended for peer %s (%d < 64 * Timer-T1=%d)\n", peer->name, peer->timer_b, peer->timer_t1); - } else if (timerb_set) { - if ((peer->timer_t1 = peer->timer_b / 64) < global_t1min) { - ast_log(LOG_WARNING, "Timer B has been set lower than recommended (%d < 64 * timert1=%d). (RFC 3261, 17.1.1.2)\n", peer->timer_b, peer->timer_t1); - peer->timer_t1 = global_t1min; + if (peer_timert1_set) { + ast_log(LOG_WARNING, "Timer B has been set lower than recommended (%d < 64 * timert1=%d), using 64 * timert1. (RFC 3261, 17.1.1.2)\n", peer->timer_b, peer->timer_t1); peer->timer_b = peer->timer_t1 * 64; - } - peer->timer_t1 = peer->timer_b / 64; } else { - peer->timer_b = peer->timer_t1 * 64; + ast_log(LOG_WARNING, "Timer B has been set lower than recommended (%d < 64 * timert1=%d), using 64 * timert1. (RFC 3261, 17.1.1.2)\n", peer->timer_b, peer->timer_t1); + peer->timer_t1 = global_t1; + peer->timer_b = global_timer_b; } } @@ -28131,7 +28158,7 @@ struct ast_flags config_flags = { reason == CHANNEL_MODULE_LOAD ? 0 : ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) ? 0 : CONFIG_FLAG_FILEUNCHANGED }; int auto_sip_domains = FALSE; struct ast_sockaddr old_bindaddr = bindaddr; - int registry_count = 0, peer_count = 0, timerb_set = 0, timert1_set = 0; + int registry_count = 0, peer_count = 0, global_timert1_set = 0; int subscribe_network_change = 1; time_t run_start, run_end; int bindport = 0; @@ -28299,6 +28326,7 @@ ast_set_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE); /* Default for all devices: TRUE */ ast_set_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP_YES); /* Default for all devices: Yes */ sip_cfg.peer_rtupdate = TRUE; + sip_cfg.peer_rtlastms = TRUE; global_dynamic_exclude_static = 0; /* Exclude static peers */ sip_cfg.tcp_enabled = FALSE; @@ -28343,6 +28371,7 @@ global_timer_b = 64 * DEFAULT_TIMER_T1; global_t1min = DEFAULT_T1MIN; global_qualifyfreq = DEFAULT_QUALIFYFREQ; + global_qualifynotok = DEFAULT_FREQ_NOTOK; global_t38_maxdatagram = -1; global_shrinkcallerid = 1; authlimit = DEFAULT_AUTHLIMIT; @@ -28409,20 +28438,30 @@ sip_cfg.rtsave_sysname = ast_true(v->value); } else if (!strcasecmp(v->name, "rtupdate")) { sip_cfg.peer_rtupdate = ast_true(v->value); + } else if (!strcasecmp(v->name, "rtlastms")) { + sip_cfg.peer_rtlastms = ast_true(v->value); } else if (!strcasecmp(v->name, "ignoreregexpire")) { sip_cfg.ignore_regexpire = ast_true(v->value); } else if (!strcasecmp(v->name, "timert1")) { /* Defaults to 500ms, but RFC 3261 states that it is recommended * for the value to be set higher, though a lower value is only * allowed on private networks unconnected to the Internet. */ + int tmp = atoi(v->value); + if (tmp < 50) { + global_t1 = DEFAULT_TIMER_T1; + ast_log(LOG_WARNING, "Invalid value for timert1 ('%s'). Setting to default ('%d').\n", v->value, global_t1); + } else { global_t1 = atoi(v->value); + } + global_timert1_set = 1; } else if (!strcasecmp(v->name, "timerb")) { int tmp = atoi(v->value); - if (tmp < 500) { + if (tmp < global_t1 * 64) { global_timer_b = global_t1 * 64; - ast_log(LOG_WARNING, "Invalid value for timerb ('%s'). Setting to default ('%d').\n", v->value, global_timer_b); + ast_log(LOG_WARNING, "Invalid value for timerb ('%s'). Setting to 64 * timert1 ('%d').\n", v->value, global_timer_b); + } else { + global_timer_b = atoi(v->value); } - timerb_set = 1; } else if (!strcasecmp(v->name, "t1min")) { global_t1min = atoi(v->value); } else if (!strcasecmp(v->name, "transport")) { @@ -28785,6 +28824,14 @@ ast_log(LOG_WARNING, "Invalid qualifyfreq number '%s' at line %d of %s\n", v->value, v->lineno, config); global_qualifyfreq = DEFAULT_QUALIFYFREQ; } + } else if (!strcasecmp(v->name, "qualifynotok")) { + int i; + if (sscanf(v->value, "%30d", &i) == 1) { + global_qualifynotok = i * 1000; + } else { + ast_log(LOG_WARNING, "Invalid qualifynotok number '%s' at line %d of %s\n", v->value, v->lineno, config); + global_qualifynotok = DEFAULT_FREQ_NOTOK; + } } else if (!strcasecmp(v->name, "callevents")) { sip_cfg.callevents = ast_true(v->value); } else if (!strcasecmp(v->name, "authfailureevents")) { @@ -28877,22 +28924,16 @@ network_change_event_unsubscribe(); } - if (global_t1 < global_t1min) { - ast_log(LOG_WARNING, "'t1min' (%d) cannot be greater than 't1timer' (%d). Resetting 't1timer' to the value of 't1min'\n", global_t1min, global_t1); - global_t1 = global_t1min; - } - + /* Note that Timer B is dependent upon Timer T1 and MUST NOT be lower + * than Timer T1 * 64, according to RFC 3261, Section 17.1.1.2 */ if (global_timer_b < global_t1 * 64) { - if (timerb_set && timert1_set) { - ast_log(LOG_WARNING, "Timer B has been set lower than recommended (%d < 64 * timert1=%d). (RFC 3261, 17.1.1.2)\n", global_timer_b, global_t1); - } else if (timerb_set) { - if ((global_t1 = global_timer_b / 64) < global_t1min) { - ast_log(LOG_WARNING, "Timer B has been set lower than recommended (%d < 64 * timert1=%d). (RFC 3261, 17.1.1.2)\n", global_timer_b, global_t1); - global_t1 = global_t1min; + if (global_timert1_set) { + ast_log(LOG_WARNING, "Timer B has been set lower than recommended, using 64 * timert1 (%d < 64 * timert1=%d). (RFC 3261, 17.1.1.2)\n", global_timer_b, global_t1); global_timer_b = global_t1 * 64; - } } else { - global_timer_b = global_t1 * 64; + ast_log(LOG_WARNING, "Timer B has been set lower than recommended, using defaults for timert1 and timerb (%d < 64 * timert1=%d). (RFC 3261, 17.1.1.2)\n", global_timer_b, global_t1); + global_t1 = DEFAULT_TIMER_T1; + global_timer_b = 64 * DEFAULT_TIMER_T1; } } if (!sip_cfg.allow_external_domains && AST_LIST_EMPTY(&domain_list)) { @@ -30454,6 +30495,7 @@ MEMBER(sip_peer, lastms, AST_DATA_MILLISECONDS) \ MEMBER(sip_peer, maxms, AST_DATA_MILLISECONDS) \ MEMBER(sip_peer, qualifyfreq, AST_DATA_MILLISECONDS) \ + MEMBER(sip_peer, qualifynotok, AST_DATA_MILLISECONDS) \ MEMBER(sip_peer, timer_t1, AST_DATA_MILLISECONDS) \ MEMBER(sip_peer, timer_b, AST_DATA_MILLISECONDS)