######## KEEPALIVE PINGING ######## #!trydef KEEPALIVE_NAT_ONLY 0 #!trydef KEEPALIVE_UDP_ONLY 0 #!trydef KEEPALIVE_TIMERS 7 #!trydef KEEPALIVE_INTERVAL 30 #!trydef KEEPALIVE_TIMEOUT 3500 #!trydef KEEPALIVE_FAILED_THRESHOLD 2 #!substdef "!KEEPALIVE_S_FROM_URI!sip:keepalive@MY_HOSTNAME!g" #!substdef "!KEEPALIVE_S_TIMERS!$def(KEEPALIVE_TIMERS)!g" kazoo.keepalive_udp_only = KEEPALIVE_UDP_ONLY descr "should we send keepalive for udp only" kazoo.keepalive_nat_only = KEEPALIVE_NAT_ONLY descr "should we send keepalive for nat phones only" modparam("rtimer", "timer", "name=keepalive_timer;interval=1;mode=KEEPALIVE_S_TIMERS;") modparam("rtimer", "exec", "timer=keepalive_timer;route=KEEPALIVE_TIMER") modparam("rtimer", "timer", "name=keepalive_db_timer;interval=250000u;mode=1;") modparam("rtimer", "exec", "timer=keepalive_db_timer;route=KEEPALIVE_DB_TIMER") modparam("mqueue","mqueue", "name=keepalive_db_queue") route[KEEPALIVE_DB_TIMER] { $var(runloop) = 1; while(mq_fetch("keepalive_db_queue") == 1 && $var(runloop) < MAX_WHILE_LOOPS) { $var(ci) = $mqk(keepalive_db_queue); xlog("L_DEBUG", "Query : $mqv(keepalive_db_queue)\n"); $var(sqlres) = sql_query("cb", "$mqv(keepalive_db_queue)"); xlog("L_DEBUG", "Query result : $var(sqlres)\n"); if($var(sqlres) < 0) { xlog("L_ERROR", "$var(ci)|log|error running query : $mqv(keepalive_db_queue)\n"); } else { $var(nrows) = $sqlrows(cb); xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows)\n"); if($var(nrows) == 0) { xlog("L_DEBUG", "$var(ci)|log|error no rows affected when running query\n"); } } $var(runloop) = $var(runloop) + 1; } } route[KEEPALIVE_CLEANUP] { $var(Query) = $_s(update location set expires = last_modified where id in(select a.id from loc a inner join (select cast(substr(contact, 1, instr(contact,";")-1) as varchar(32)) contact from keepalive where slot = $rtimer_worker AND failed > $def(KEEPALIVE_FAILED_THRESHOLD)) b on substr(a.contact, 1, instr(a.contact,";")-1) = b.contact)); sql_query("cb", "$var(Query)"); $var(Query) = $_s(DELETE FROM active_watchers where id in(select a.id from keepalive a inner join active_watchers b on a.contact=b.contact where slot = $rtimer_worker and failed > $def(KEEPALIVE_FAILED_THRESHOLD))); sql_query("cb", "$var(Query)"); $var(Query) = $_s(DELETE FROM keepalive where slot = $rtimer_worker and failed > $def(KEEPALIVE_FAILED_THRESHOLD)); sql_query("cb", "$var(Query)"); } route[KEEPALIVE_TIMER] { route(KEEPALIVE_CLEANUP); $var(Query) = $_s(UPDATE keepalive SET selected = 1 WHERE slot = $rtimer_worker AND selected = 0 AND time_sent < datetime('now', '-$def(KEEPALIVE_INTERVAL) seconds')); $var(sqlres) = sql_query("cb", "$var(Query)"); if($var(sqlres) < 0) { xlog("L_ERROR", "$rtimer_worker|log|error running query : $var(Query)\n"); } else { $var(nrows) = $sqlrows(cb); xlog("L_DEBUG", "$rtimer_worker|log|selected $var(nrows) endpoints to ping\n"); } $var(Query) = $_s(SELECT id, contact, sockinfo from keepalive WHERE slot = $rtimer_worker AND selected = 1); xlog("L_DEBUG", "$rtimer_worker|timer|SQL => $var(Query)\n"); if (sql_xquery("cb", "$var(Query)", "ra") == 1) { while($xavp(ra) != $null) { $var(loop) = 0; while($xavp(ra) != $null && $var(loop) < MAX_WHILE_LOOPS) { route(KEEPALIVE_SEND_PING); pv_unset("$xavp(ra)"); $var(loop) = $var(loop) + 1; } } } $var(Query) = $_s(UPDATE keepalive SET selected = 2 WHERE slot = $rtimer_worker AND selected = 1); $var(sqlres) = sql_query("cb", "$var(Query)"); if($var(sqlres) < 0) { xlog("L_ERROR", "$rtimer_worker|log|error running query : $var(Query)\n"); } } route[KEEPALIVE_SEND_PING] { $var(CallId) = $uuid(g); xlog("L_DEBUG", "$var(CallId)|$rtimer_worker|timer|SENDING PING FROM $xavp(ra=>local_contact) TO => $xavp(ra=>contact)\n"); $uac_req(method)="OPTIONS"; $uac_req(hdrs) = "X-TM-Local: KEEPALIVE_PING\r\nX-TM-SockInfo: " + $xavp(ra=>sockinfo) + "\r\n"; $uac_req(turi) = $xavp(ra=>contact); $uac_req(ruri) = $xavp(ra=>contact); $uac_req(furi) = $_s(KEEPALIVE_S_FROM_URI;nat_id=$xavp(ra=>id)); $uac_req(ouri) = "sip:127.0.0.1:5090;transport=tcp"; $uac_req(callid) = $var(CallId); uac_req_send(); } onreply_route[KEEPALIVE_REPLY] { xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE REPLY $(tu{nameaddr.uri})\n"); $var(Query) = $_s(UPDATE keepalive SET selected = 0, failed = 0, time_sent = datetime('now') WHERE id = $(fu{uri.param,nat_id});); xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE UPDATE SQL => '$var(Query)'\n"); mq_add("keepalive_db_queue", "$uuid(g)", "$var(Query)"); t_drop(); } failure_route[KEEPALIVE_FAULT] { xlog("L_WARNING", "$ci|keepalive|received error $T_reply_code $T_reply_reason from $(tu{nameaddr.uri})\n"); $var(Query) = $_s(UPDATE keepalive SET selected = 0, failed = failed + 1, time_sent = datetime('now') WHERE id = $(fu{uri.param,nat_id});); xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE REMOVE SQL => '$var(Query)'\n"); mq_add("keepalive_db_queue", "$uuid(g)", "$var(Query)"); t_drop(); } route[KEEPALIVE_PING] { $fs = $hdr(X-TM-SockInfo); remove_hf_re("^X-TM-SockInfo"); force_rport(); handle_ruri_alias(); record_route(); xlog("L_DEBUG", "$ci|local|sending $proto keepalive using $fs to $ru => $du => $tu\n"); t_on_reply("KEEPALIVE_REPLY"); t_on_failure("KEEPALIVE_FAULT"); t_set_fr(0, KEEPALIVE_TIMEOUT); t_relay(); } route[KEEPALIVE_ON_REGISTRATION] { if($proto == "ws" || $proto == "wss") { return; } if (isbflagset(FLB_NATB)) { if(!isbflagset(FLB_NATSIPPING)) { return; } } else { if($sel(cfg_get.kazoo.keepalive_nat_only) == 1) { return; } } $var(alias) = $(avp(AVP_RECV_PARAM){uri.host}) + "~" + $(avp(AVP_RECV_PARAM){uri.port}) + "~" + $prid; $var(contact) = $(ct{nameaddr.uri}) + ";alias=" + $var(alias); $var(local_contact) = "sip:" + $Ri + ":" + $Rp + ";transport=" + $proto; xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE ON REG $var(save_result) $proto $RAut $var(contact) $var(alias) $(ct{nameaddr.uri}) $ct $avp(AVP_RECV_PARAM) $tu $xavp(ulrcd=>ruid) , $xavp(ulrcd=>contact) , $xavp(ulrcd=>expires)\n"); $var(slot) = $(var(contact){s.corehash, KEEPALIVE_S_TIMERS}); $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, sockinfo, slot) values("$var(contact)", "$(RAut{uri.tosocket})", $var(slot))); mq_add("keepalive_db_queue", "$ci", "$var(sql)"); return; } route[KEEPALIVE_ON_SUBSCRIBE] { if(!( ($sel(cfg_get.kazoo.keepalive_udp_only) == 1 && $proto != "udp") || (!isflagset(FLT_NATS) && $sel(cfg_get.kazoo.keepalive_nat_only) == 1) || ($proto == "ws" || $proto == "wss") )) { $var(slot) = $(subs(contact){s.corehash, KEEPALIVE_S_TIMERS}); $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, sockinfo, slot) values("$subs(contact)", "$subs(sockinfo)", $var(slot))); mq_add("keepalive_db_queue", "$ci", "$var(sql)"); } }