diff --git a/kamailio/accounting-role.cfg b/kamailio/accounting-role.cfg
index 7c58cb5..13b866d 100644
--- a/kamailio/accounting-role.cfg
+++ b/kamailio/accounting-role.cfg
@@ -1,8 +1,7 @@
####### Flags #######
-flags
- FLAG_ACC: 8,
- FLAG_ACCMISSED: 9,
- FLAG_ACCFAILED: 10;
+#!trydef FLAG_ACC 13
+#!trydef FLAG_ACCMISSED 14
+#!trydef FLAG_ACCFAILED 15
######## Accounting module ########
loadmodule "acc.so"
diff --git a/kamailio/acl-role.cfg b/kamailio/acl-role.cfg
index 664298d..f4fc1df 100644
--- a/kamailio/acl-role.cfg
+++ b/kamailio/acl-role.cfg
@@ -265,3 +265,9 @@ event_route[kazoo:consumer-event-acl-acl-flush]
}
}
+
+route[ACL_BINDINGS]
+{
+ $var(payload) = $_s({"name": "acl-role", "exchange" : "frontier_acl" , "type" : "topic", "queue" : "FRONTIERACL-FLUSH-MY_HOSTNAME", "routing" : "flush" });
+ kazoo_subscribe("$var(payload)");
+}
\ No newline at end of file
diff --git a/kamailio/antiflood-role.cfg b/kamailio/antiflood-role.cfg
index 342a555..3a98318 100644
--- a/kamailio/antiflood-role.cfg
+++ b/kamailio/antiflood-role.cfg
@@ -4,9 +4,17 @@
#!trydef ANTIFLOOD_RATE_EXPIRE 4
#!trydef ANTIFLOOD_FAILED_AUTH_WINDOW 300
#!trydef ANTIFLOOD_FAILED_AUTH_DENSITY 4
+#!trydef ANTIFLOOD_FAILED_AUTH_USE_PORT 1
+#!trydef ANTIFLOOD_FAILED_AUTH_ACTION 2
+#!trydef ANTIFLOOD_RATE_LIMIT_ENABLED 1
+#!trydef ANTIFLOOD_AUTH_LIMIT_ENABLED 1
+#!trydef ANTIFLOOD_RATE_DROP 1
+#!trydef ANTIFLOOD_CACHE_PERIOD 300
+
+#!substdef "!ANTIFLOOD_SUBST_CACHE_PERIOD!$def(ANTIFLOOD_CACHE_PERIOD)!g"
######## Flood Prevention Hash Tables ########
-modparam("htable", "htable", "antiflood=>size=16;autoexpire=ANTIFLOOD_CACHE_PERIOD;initval=0")
+modparam("htable", "htable", "antiflood=>size=16;autoexpire=ANTIFLOOD_SUBST_CACHE_PERIOD;initval=0")
######## Flood Prevention Module ########
loadmodule "pike.so"
@@ -14,6 +22,21 @@ modparam("pike", "sampling_time_unit", ANTIFLOOD_RATE_WINDOW)
modparam("pike", "reqs_density_per_unit", ANTIFLOOD_RATE_DENSITY)
modparam("pike", "remove_latency", ANTIFLOOD_RATE_EXPIRE)
+kazoo.antiflood_failed_auth_use_port = ANTIFLOOD_FAILED_AUTH_USE_PORT descr "should we keep track of ip and port for auth failures"
+kazoo.antiflood_failed_auth_action = ANTIFLOOD_FAILED_AUTH_ACTION descr "0 - log, 1 - drop, 2 - reply with 403"
+kazoo.antiflood_rate_limit_enabled = ANTIFLOOD_RATE_LIMIT_ENABLED descr "antiflood rate limit enabled"
+kazoo.antiflood_auth_limit_enabled = ANTIFLOOD_AUTH_LIMIT_ENABLED descr "antiflood auth limit enabled"
+kazoo.antiflood_rate_drop = ANTIFLOOD_RATE_DROP descr "should we drop on rate limit"
+
+route[ANTIFLOOD_LIMIT]
+{
+ if($sel(cfg_get.kazoo.antiflood_rate_limit_enabled) == 1) {
+ route(ANTIFLOOD_RATE_LIMIT);
+ }
+ if($sel(cfg_get.kazoo.antiflood_auth_limit_enabled) == 1) {
+ route(ANTIFLOOD_AUTH_LIMIT);
+ }
+}
route[ANTIFLOOD_RATE_LIMIT]
{
@@ -25,13 +48,16 @@ route[ANTIFLOOD_RATE_LIMIT]
# use pike to control the rates
if (!pike_check_req()) {
- xlog("L_WARN", "$ci|end|dropping request from $fu due to rate of requests with source $si:$sp\n");
- drop();
- exit;
+ if($sel(cfg_get.kazoo.antiflood_rate_drop) == 1) {
+ xlog("L_WARN", "$ci|end|dropping request from $fu due to rate of requests with source $si:$sp\n");
+ drop();
+ } else {
+ xlog("L_WARN", "$ci|allowed|request from $fu exceeded rate of requests with source $si:$sp\n");
+ }
}
}
-route[ANITFLOOD_AUTH_LIMIT]
+route[ANTIFLOOD_AUTH_LIMIT]
{
if (has_totag()
|| isflagset(FLAG_TRUSTED_SOURCE)
@@ -39,21 +65,38 @@ route[ANITFLOOD_AUTH_LIMIT]
return(1);
}
- if ($Au != $null &&
- $sht(antiflood=>$Au::$si::count) >= ANTIFLOOD_FAILED_AUTH_DENSITY
+ $var(auth_key) = "";
+ if($sel(cfg_get.kazoo.antiflood_failed_auth_use_port) == 1) {
+ $var(auth_key) = $_s("$Au::$si::$sp");
+ } else {
+ $var(auth_key) = $_s("$Au::$si");
+ }
+ if ($Au != $null &&
+ $sht(antiflood=>$var(auth_key)::count) >= ANTIFLOOD_FAILED_AUTH_DENSITY
) {
- xlog("L_NOTICE", "$ci|end|request at authorization failure limit for $Au $si:$sp\n");
- $shtex(antiflood=>$Au::$si::count) = ANTIFLOOD_FAILED_AUTH_WINDOW;
- $sht(antiflood=>$Au::$si::last) = $Ts;
- append_to_reply("Retry-After: 3600\r\n");
- send_reply("500", "Retry Later");
- exit;
+ $shtex(antiflood=>$var(auth_key)::count) = ANTIFLOOD_FAILED_AUTH_WINDOW;
+ $sht(antiflood=>$var(auth_key)::last) = $Ts;
+ if($sel(cfg_get.kazoo.antiflood_failed_auth_action) == 1) {
+ xlog("L_WARNING", "$ci|end|dropping request authorization failure limit $def(ANTIFLOOD_FAILED_AUTH_DENSITY) for $Au $si:$sp\n");
+ drop();
+ } else if($sel(cfg_get.kazoo.antiflood_failed_auth_action) == 2) {
+ xlog("L_NOTICE", "$ci|end|authorization failure limit $def(ANTIFLOOD_FAILED_AUTH_DENSITY) for $Au $si:$sp\n");
+ append_to_reply("Retry-After: 3600\r\n");
+ send_reply("403", "Forbidden");
+ exit;
+ } else {
+ xlog("L_NOTICE", "$ci|log|authorization failure limit $def(ANTIFLOOD_FAILED_AUTH_DENSITY) for $Au $si:$sp\n");
+ }
}
}
route[ANTIFLOOD_SUCCESSFUL_AUTH]
{
- sht_rm_name_re("antiflood=>$(Au{re.subst,/\\./\\\\./g})::$(si{re.subst,/\\./\\\\./g})::.*");
+ if($sel(cfg_get.kazoo.antiflood_failed_auth_use_port) == 1) {
+ sht_rm_name_re("antiflood=>$(Au{re.subst,/\\./\\\\./g})::$(si{re.subst,/\\./\\\\./g})::$sp::.*");
+ } else {
+ sht_rm_name_re("antiflood=>$(Au{re.subst,/\\./\\\\./g})::$(si{re.subst,/\\./\\\\./g})::.*");
+ }
}
route[ANTIFLOOD_RESET_AUTH]
@@ -68,23 +111,30 @@ route[ANITFLOOD_FAILED_AUTH]
return;
}
- $var(count) = $shtinc(antiflood=>$Au::$si::count);
- $sht(antiflood=>$Au::$si::last) = $Ts;
+ $var(auth_key) = "";
+ if($sel(cfg_get.kazoo.antiflood_failed_auth_use_port) == 1) {
+ $var(auth_key) = $_s("$Au::$si::$sp");
+ } else {
+ $var(auth_key) = $_s("$Au::$si");
+ }
+
+ $var(count) = $shtinc(antiflood=>$var(auth_key)::count);
+ $sht(antiflood=>$var(auth_key)::last) = $Ts;
xlog("L_INFO", "$ci|log|$var(count) errounous authorization response for $Au $si:$sp\n");
- if ($var(count) >= ANTIFLOOD_FAILED_AUTH_DENSITY) {
+ if ($var(count) >= ANTIFLOOD_FAILED_AUTH_DENSITY) {
$var(exp) = $Ts - ANTIFLOOD_FAILED_AUTH_WINDOW;
- if($sht(antiflood=>$Au::$si::last) > $var(exp)){
- xlog("L_NOTICE", "$ci|end|request at authorization failure limit for $Au $si:$sp\n");
+ if($sht(antiflood=>$var(auth_key)::last) > $var(exp)) {
+ xlog("L_NOTICE", "$ci|end|request at authorization failure limit $def(ANTIFLOOD_FAILED_AUTH_DENSITY) for $Au $si:$sp\n");
append_to_reply("Retry-After: 3600\r\n");
- send_reply("500", "Retry Later");
+ send_reply("403", "Forbidden");
exit;
}
- }
+ }
}
-event_route[htable:expired:antiflood]
+event_route[htable:expired:antiflood]
{
xlog("L_NOTICE", "antiflood expired record $shtrecord(key) => $shtrecord(value)\n");
}
diff --git a/kamailio/auth.cfg b/kamailio/auth.cfg
new file mode 100644
index 0000000..aca5bec
--- /dev/null
+++ b/kamailio/auth.cfg
@@ -0,0 +1,105 @@
+
+
+route[AUTH]
+{
+ if (!is_method("INVITE|MESSAGE|REFER")) {
+ return;
+ }
+
+ #!ifdef DISPATCHER_ROLE
+ if (!isflagset(FLAG_INTERNALLY_SOURCED)) {
+ route(SETUP_AUTH_HEADERS);
+ }
+ #!endif
+}
+
+route[AUTH_HEADERS]
+{
+ remove_hf_re("^X-");
+
+ xavp_params_implode("hf", "$var(outx)");
+ $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/});
+ $var(c) = $(var(out){param.count});
+ xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n");
+ while($var(c) > 0) {
+ $var(idx) = $var(c) - 1;
+ xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n");
+ append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n");
+ $var(c) = $var(c) - 1;
+ }
+
+}
+
+route[SETUP_AUTH_HEADERS]
+{
+
+ $xavp(hf=>X-AUTH-IP) = $si;
+ $xavp(hf[0]=>X-AUTH-PORT) = $sp;
+
+ #!ifdef REGISTRAR_ROLE
+ #!ifdef WITH_AUTH_TOKEN
+ route(AUTH_TOKEN);
+ #!else
+ route(AUTH_CCVS);
+ #!endif
+ #!endif
+
+}
+
+#!ifdef REGISTRAR_ROLE
+
+route[AUTH_TOKEN]
+{
+ $xavp(regcfg=>match_received) = $su;
+ if (registered("location","$fu", 2, 1) == 1) {
+ if($(xavp(ulattrs=>token){s.len}) > 0) {
+ $xavp(hf[0]=>X-AUTH-Token) = $xavp(ulattrs=>token);
+ } else {
+ if($(xavp(ulattrs=>Authorizing-ID){s.len}) > 0 && $(xavp(ulattrs=>Account-ID){s.len})) {
+ $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}));
+ }
+ }
+ }
+}
+
+route[AUTH_CCVS]
+{
+ $xavp(regcfg=>match_received) = $su;
+ if (registered("location","$fu", 2, 1) != 1) return;
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Account-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Authorizing-Type) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0 && $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0)
+ $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}));
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Authorizing-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Username}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Username) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Username});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Realm});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Account-Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Account-Name) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.escape.param});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Presence-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Owner-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID});
+
+ if($(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID}{s.len}) > 0)
+ $xavp(hf[0]=>X-ecallmgr_Hotdesk-Current-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID});
+
+}
+
+#!endif
diff --git a/kamailio/authorization-role.cfg b/kamailio/authorization-role.cfg
new file mode 100644
index 0000000..5b55be2
--- /dev/null
+++ b/kamailio/authorization-role.cfg
@@ -0,0 +1,23 @@
+## to be enhanced
+
+route[AUTHORIZATION_CHECK]
+{
+ if (!is_method("MESSAGE|NOTIFY|SUBSCRIBE|PUBLISH"))
+ return;
+
+ if(has_totag())
+ return;
+
+ if (isflagset(FLAG_INTERNALLY_SOURCED))
+ return;
+
+ if (isflagset(FLAG_TRUSTED_SOURCE))
+ return;
+
+ $xavp(regcfg=>match_received) = $su;
+ if(!(registered("location", "$fu", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1)) {
+ xlog("L_INFO", "$ci|log|not authorized $fu from $si:$sp\n");
+ send_reply("503", "Not Registered");
+ exit;
+ }
+}
diff --git a/kamailio/blocker-role.cfg b/kamailio/blocker-role.cfg
new file mode 100644
index 0000000..8da3adf
--- /dev/null
+++ b/kamailio/blocker-role.cfg
@@ -0,0 +1,39 @@
+######## BLOCK BY IP[PORT] ########
+
+#!trydef KZ_BLOCK_ENABLE 1
+#!trydef KZ_BLOCK_LOG_LEVEL 1
+#!trydef KZ_BLOCK_LOG_BUFFER 0
+#!trydef KZ_BLOCK_DRY_RUN 0
+
+#!ifdef KZ_BLOCK_COLD_CACHE
+#!substdef "!BLOCK_S_WARM_CACHE!!g"
+#!else
+#!substdef "!BLOCK_S_WARM_CACHE!dbtable=block_cache;dbmode=1;!g"
+#!endif
+
+modparam("htable", "htable", "block=>size=8;BLOCK_S_WARM_CACHE")
+modparam("statistics","variable", "block:blocked_requests")
+
+kazoo.block_enable = KZ_BLOCK_ENABLE descr "enable block processing"
+kazoo.block_log_level = KZ_BLOCK_LOG_LEVEL descr "block log level"
+kazoo.block_log_buffer = KZ_BLOCK_LOG_BUFFER descr "log the received buffer"
+kazoo.block_dry_run = KZ_BLOCK_DRY_RUN descr "log but keep processing"
+
+## global param to enable route
+received_route_mode=1
+
+event_route[core:msg-received]
+{
+ if($sel(cfg_get.kazoo.block_enable) == 1) {
+ if($sht(block=>$rcv(srcip)) || $sht(block=>$rcv(srcip)::$rcv(srcport))) {
+ if($sel(cfg_get.kazoo.block_log_buffer) == 1) {
+ xlog("$(sel(cfg_get.kazoo.block_log_level){s.int})", "|block|request from [$rcv(srcip):$rcv(srcport)] to [$rcv(rcvip):$rcv(rcvport)] was blocked => [$rcv(buf)]\n");
+ } else {
+ xlog("$(sel(cfg_get.kazoo.block_log_level){s.int})", "|block|request from [$rcv(srcip):$rcv(srcport)] to [$rcv(rcvip):$rcv(rcvport)] was blocked\n");
+ }
+ if($sel(cfg_get.kazoo.block_dry_run) == 0) {
+ drop;
+ }
+ }
+ }
+}
diff --git a/kamailio/db_kazoo.cfg b/kamailio/db_kazoo.cfg
new file mode 100644
index 0000000..4989a32
--- /dev/null
+++ b/kamailio/db_kazoo.cfg
@@ -0,0 +1,14 @@
+#### db_kazoo module ###
+
+#!trydef KZ_DB_HOOK_TRACE 1
+#!trydef KZ_DB_TRACE 0
+#!trydef KZ_DB_TRACE_LOG_LEVEL 3
+#!trydef KZ_DB_TRACE_FILTER 110
+
+loadmodule "db_kazoo.so"
+modparam("db_kazoo", "trace_hook", KZ_DB_HOOK_TRACE)
+modparam("db_kazoo", "trace_enable", KZ_DB_TRACE)
+modparam("db_kazoo", "trace_log_level", KZ_DB_TRACE_LOG_LEVEL)
+modparam("db_kazoo", "trace_filter", KZ_DB_TRACE_FILTER)
+
+include_file "db_queries_kazoo.cfg"
diff --git a/kamailio/db_mysql.cfg b/kamailio/db_mysql.cfg
new file mode 100644
index 0000000..9000b57
--- /dev/null
+++ b/kamailio/db_mysql.cfg
@@ -0,0 +1,4 @@
+#### db_mysql module ###
+loadmodule "db_mysql.so"
+
+include_file "db_queries_mysql.cfg"
diff --git a/kamailio/db_postgres.cfg b/kamailio/db_postgres.cfg
new file mode 100644
index 0000000..51dbd44
--- /dev/null
+++ b/kamailio/db_postgres.cfg
@@ -0,0 +1,4 @@
+#### db_postgres module ###
+loadmodule "db_postgres.so"
+
+include_file "db_queries_postgres.cfg"
diff --git a/kamailio/db_queries_kazoo.cfg b/kamailio/db_queries_kazoo.cfg
index b7e542d..f3de127 100644
--- a/kamailio/db_queries_kazoo.cfg
+++ b/kamailio/db_queries_kazoo.cfg
@@ -1,15 +1,27 @@
####### Database queries ########
-#!substdef "!KZQ_CHECK_MEDIA_SERVER_INSERT!insert into dispatcher (setid, destination) select \$var(SetId), \"\$var(MediaUrl)\" where not exists(select * from dispatcher where destination = \"\$var(MediaUrl)\")!g"
-#!substdef "!KZQ_COUNT_ALL_SUBSCRIBERS!select a.event, count(distinct watcher_username || \"@\" || watcher_domain) count_unique, count(*) count from event_list a, active_watchers b where b.event = a.event group by a.event!g"
+#!substdef "!KZQ_CHECK_MEDIA_SERVER_INSERT!insert into dispatcher (setid, destination, flags, attrs, description) select \$var(SetId), \"\$var(MediaUrl)\", \$var(flags), \"\$var(attrs)\", \"added by nodes role\" where not exists(select * from dispatcher where destination = \"\$var(MediaUrl)\")!g"
+#!substdef "!KZQ_COUNT_ALL_SUBSCRIBERS!select a.event, count(distinct watcher_uri) count_unique, count(*) count from event_list a left outer join active_watchers b on a.event = b.event group by a.event!g"
+
#!substdef "!KZQ_COUNT_PRESENTITIES!select event, (select count(*) from presentity b where username = \"\$(var(payload){kz.json,From}{uri.user})\" and domain = \"\$(var(payload){kz.json,From}{uri.domain})\" and b.event = a.event) count from event_list a!g"
-#!substdef "!KZQ_COUNT_SUBSCRIBERS!select event, (select count(*) from active_watchers b where presentity_uri = \"\$var(presentity)\" and b.event = a.event) count from event_list a!g"
+#!substdef "!KZQ_COUNT_SUBSCRIBERS!select event, (select count(*) from active_watchers b where presentity_uri = \"\$var(presentity)\" and b.event = a.event) count from event_list a union all select \"self\", count(distinct callid) from presentities where presentity_uri = \"\$var(presentity)\" and callid <> \"\$var(callid)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g"
+
#!substdef "!KZQ_EVENT_PRESENCE_RESET_DELETE!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\" and username = \"\$(kzE{kz.json,Username})\"!g"
#!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE1!delete from active_watchers where callid = \"\$ci\"!g"
-#!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE2!delete from active_watchers where watcher_username=\"\$fU\" and presentity_uri=\"\$var(presentity_uri)\" and to_user=\"\$tU\" and watcher_domain=\"\$fd\" and event=\"\$hdr(Event)\"!g"
-#!substdef "!KZQ_RESET_ACCOUNT_DELETE!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\"!g"
-#!substdef "!KZQ_RESET_ACCOUNT_UPDATE!update active_watchers set expires = \$TS where watcher_domain=\"\$(kzE{kz.json,Realm})\"!g"
-#!substdef "!KZQ_RESET_PUBLISHER_UPDATE!update active_watchers set expires = \$TS where id in (select b.id from presentity a inner join active_watchers b on a.username = b.to_user and a.domain = b.to_domain and a.event = b.event where a.sender = \"\$var(MediaUrl)\")!g"
-#!substdef "!KZQ_PRESENCE_SEARCH_DETAIL!select * from active_watchers_log where presentity_uri = \"\$var(presentity_uri)\"!g"
-#!substdef "!KZQ_PRESENCE_SEARCH_SUMMARY!select * from active_watchers where watcher_domain = \"\$var(Domain)\"!g"
+#!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE2!delete from active_watchers where presentity_uri=\"\$var(presentity_uri)\" and event=\"\$hdr(Event)\" and watcher_username=\"\$fU\" and to_user=\"\$tU\" and watcher_domain=\"\$fd\"!g"
+
+#!substdef "!KZQ_PRESENCE_SEARCH_SUMMARY!select * from active_watchers where to_domain = \"\$var(Domain)\"!g"
+#!substdef "!KZQ_PRESENCE_SEARCH_DETAIL!select a.*, b.time, b.result, b.sent_msg, b.received_msg from active_watchers a left outer join active_watchers_log b on a.presentity_uri = b.presentity_uri and a.event = b.event and a.callid = b.callid where a.presentity_uri = \"\$var(presentity_uri)\" !g"
+
#!substdef "!KZQ_HAS_PRESENTITY!select count(*) as count from presentity where username = \"\$subs(to_user)\" and domain = \"\$subs(to_domain)\" and event = \"\$subs(event)\"!g"
+#!substdef "!KZQ_REPLACE_WATCHERS_LOG!REPLACE INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES (\"\$subs(uri)\", \"\$subs(watcher_username)\", \"\$subs(watcher_domain)\", \"\$subs(event)\",\"\$subs(callid)\",\"\$subs(to_user)\",\"\$subs(to_domain)\", '\$(subs(user_agent){s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})', \$TS, \$notify_reply(\$rs), '\$(mb{s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})', '\$(notify_reply(\$mb){s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})')!g"
+
+# # #!substdef "!KZQ_RESET_PUBLISHER_UPDATE!update active_watchers set expires = \$TS where id in (select b.id from presentity a inner join active_watchers b on a.username = b.to_user and a.domain = b.to_domain and a.event = b.event where a.sender = \"\$var(MediaUrl)\")!g"
+#!substdef "!KZQ_RESET_PUBLISHER_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where sender = \"\$var(MediaUrl)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g"
#!substdef "!KZQ_PRESENCE_RESET!delete from presentity where sender = \"\$var(MediaUrl)\"!g"
+
+# # #!substdef "!KZQ_RESET_ACCOUNT_UPDATE!update active_watchers set expires = \$TS where watcher_domain=\"\$(kzE{kz.json,Realm})\"!g"
+#!substdef "!KZQ_RESET_ACCOUNT_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where domain=\"\$(kzE{kz.json,Realm})\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g"
+#!substdef "!KZQ_RESET_ACCOUNT_RESET!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\"!g"
+
+#!substdef "!KZQ_RESET_PUBLISHER_ZONE_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join wdispatcher c on a.sender = c.destination inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where zone = \"\$var(Zone)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g"
+#!substdef "!KZQ_PRESENCE_ZONE_RESET!delete from presentity where id in(select a.id from presentities a join wdispatcher c on a.sender = c.destination where zone = \"\$var(Zone)\")!g"
diff --git a/kamailio/db_scripts/check-kazoodb-sql.sh b/kamailio/db_scripts/check-kazoodb-sql.sh
new file mode 100755
index 0000000..4ff700a
--- /dev/null
+++ b/kamailio/db_scripts/check-kazoodb-sql.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+TEMP_DB_LOCATION=/tmp/db
+TEMP_DB=${TEMP_DB_LOCATION}/kazoo.db
+
+rm -rf ${TEMP_DB_LOCATION}
+. $(dirname $0)/kazoodb-sql.sh --source-only
+
+file=$(sql_db_prepare)
+sql_setup $file ${TEMP_DB_LOCATION}
+
+DB_VERSION=`KazooDB -db ${TEMP_DB} "select sum(table_version) from version;"`
+
+DB_CURRENT_DB=${DB_LOCATION:-/etc/kazoo/kamailio}/kazoo.db
+DB_CURRENT_VERSION=`KazooDB -db ${DB_CURRENT_DB} "select sum(table_version) from version;"`
+
+
+if [[ $DB_CURRENT_VERSION -ne $DB_VERSION ]]; then
+ echo "db required version is ${DB_VERSION}, existing version is ${DB_CURRENT_VERSION}, applying diff"
+ KazooDB-diff --schema ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB}
+ KazooDB-diff --primarykey --table version ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB}
+ KazooDB-diff --primarykey --table event_list ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB}
+fi
+
+
+for VIEW in `ls ${DB_SCRIPT_DIR}/vw_*.sql`; do
+ filename=$(basename -- "$VIEW")
+ filename="${filename%.*}"
+ viewname=${filename#*_}
+ v1=$(KazooDB -db ${DB_CURRENT_DB} "select sql from sqlite_master where type='view' and name='$viewname'" 2> /dev/null | tr -d ' ' | md5sum | cut -d ' ' -f1)
+ v2=$(cat $VIEW | tr -d ' ' | md5sum | cut -d ' ' -f1)
+ if [[ "$v1" != "$v2" ]]; then
+ echo "rebuilding view $viewname"
+ KazooDB -db ${DB_CURRENT_DB} "drop view if exists $viewname;"
+ KazooDB -db ${DB_CURRENT_DB} < $VIEW
+ fi
+done
+
+if [ -f ${DB_SCRIPT_DIR}/db_extra_check.sql ]; then
+ . ${DB_SCRIPT_DIR}/db_extra_check.sql --source-only
+ do_db_extra_check;
+fi
+
+for INIT in `ls ${DB_SCRIPT_DIR}/db_init_*.sql`; do
+ KazooDB -db ${DB_CURRENT_DB} < $INIT
+done
diff --git a/kamailio/db_scripts/create-kazoodb-sql.sh b/kamailio/db_scripts/create-kazoodb-sql.sh
index 0663a0e..b720415 100755
--- a/kamailio/db_scripts/create-kazoodb-sql.sh
+++ b/kamailio/db_scripts/create-kazoodb-sql.sh
@@ -1,104 +1,9 @@
#!/bin/sh -e
-#####################################################################################
-##
-## If you want prepare SQL file for PostgreSQL or MySQL server, then need to execute
-## DB_ENGINE=postgres ./create-kazoodb-sql.sh
-##
-#####################################################################################
-KAMAILIO_SHARE_DIR=${KAMAILIO_SHARE_DIR:-/usr/share/kamailio}
-DB_ENGINE=${DB_ENGINE:-db_kazoo}
-RESULTED_SQL=${RESULTED_SQL:-/tmp/kamailio_initdb.sql}
+. $(dirname $0)/kazoodb-sql.sh --source-only
-. $(dirname $0)/$DB_ENGINE-specific --source-only
-
-sql_filelist() {
-cat << EOF
-acc-create.sql
-lcr-create.sql
-domain-create.sql
-group-create.sql
-permissions-create.sql
-registrar-create.sql
-usrloc-create.sql
-msilo-create.sql
-alias_db-create.sql
-uri_db-create.sql
-speeddial-create.sql
-avpops-create.sql
-auth_db-create.sql
-pdt-create.sql
-dialog-create.sql
-dispatcher-create.sql
-dialplan-create.sql
-topos-create.sql
-presence-create.sql
-rls-create.sql
-imc-create.sql
-cpl-create.sql
-siptrace-create.sql
-domainpolicy-create.sql
-carrierroute-create.sql
-userblacklist-create.sql
-htable-create.sql
-purple-create.sql
-uac-create.sql
-pipelimit-create.sql
-mtree-create.sql
-sca-create.sql
-mohqueue-create.sql
-rtpproxy-create.sql
-uid_auth_db-create.sql
-uid_avp_db-create.sql
-uid_domain-create.sql
-uid_gflags-create.sql
-uid_uri_db-create.sql
-EOF
-}
-
-sql_all_header() {
-cat << EOF
-CREATE TABLE version (
- table_name VARCHAR(32) NOT NULL,
- table_version INTEGER DEFAULT 0 NOT NULL,
- CONSTRAINT version_table_name_idx UNIQUE (table_name)
-);
-INSERT INTO version VALUES('version',1);
-
-EOF
-}
-
-sql_all_extra_tables() {
-cat << EOF
-
-CREATE TABLE event_list ( event varchar(25) PRIMARY KEY NOT NULL);
-INSERT INTO event_list VALUES('dialog');
-INSERT INTO event_list VALUES('presence');
-INSERT INTO event_list VALUES('message-summary');
-INSERT INTO version VALUES('event_list',1);
-
-EOF
-}
-
-sql_all_footer() {
-cat << EOF
-COMMIT;
-EOF
-}
-
-echo "Creating kamailio database init file in '$RESULTED_SQL'"
-
-sql_db_pre_setup > $RESULTED_SQL
-sql_all_header >> $RESULTED_SQL
-sql_header >> $RESULTED_SQL
-for i in $(sql_filelist); do
- cat $KAMAILIO_SHARE_DIR/$DB_ENGINE/$i >> $RESULTED_SQL
-done
-sql_all_extra_tables >> $RESULTED_SQL
-sql_extra_tables >> $RESULTED_SQL
-sql_footer >> $RESULTED_SQL
-sql_all_footer >> $RESULTED_SQL
-
-sql_setup $RESULTED_SQL
+file=$(sql_db_prepare)
+echo "setting up kazoo db from init script $file"
+sql_setup $file
exit 0
diff --git a/kamailio/db_scripts/db_extra_check.sql b/kamailio/db_scripts/db_extra_check.sql
new file mode 100644
index 0000000..88210bd
--- /dev/null
+++ b/kamailio/db_scripts/db_extra_check.sql
@@ -0,0 +1,34 @@
+
+do_db_extra_check() {
+
+# location
+if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then
+ KazooDB -db ${DB_CURRENT_DB} "delete from location where socket not like 'udp:%';"
+fi
+
+##KazooDB -db ${DB_CURRENT_DB} "delete from location where expires > 0 and datetime(expires) < datetime('now', '-30 seconds');"
+KazooDB -db ${DB_CURRENT_DB} "delete from location_attrs where not exists(select id from location where ruid = location_attrs.ruid);"
+
+## presence
+if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then
+ KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers where socket_info not like 'udp:%';"
+fi
+KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers where expires > 0 and datetime(expires, 'unixepoch') < datetime('now', '-10 seconds');"
+KazooDB -db ${DB_CURRENT_DB} "delete from presentity where expires > 0 AND datetime(expires, 'unixepoch') < datetime('now', '-10 seconds');"
+KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities where state in('terminated','available'));"
+KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers_log where id in(select id from active_watchers_log a where not exists(select callid from active_watchers b where b.callid = a.callid and b.watcher_username = a.watcher_username and b.watcher_domain = a.watcher_domain));"
+KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities a where not exists(select * from active_watchers where presentity_uri = a.presentity_uri));"
+
+## notify watchers of pending calls
+## 'create temp table as' because it will be dropped as soon as we ended the session
+KazooDB -db ${DB_CURRENT_DB} "drop table if exists tmp_probe;"
+KazooDB -db ${DB_CURRENT_DB} "create table tmp_probe as select distinct a.event, a.presentity_uri, cast(2 as integer) action from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where state in('early', 'confirmed', 'onthephone', 'busy');"
+KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities where state in('early', 'confirmed', 'onthephone', 'busy'));"
+
+## keepalive
+if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then
+ KazooDB -db ${DB_CURRENT_DB} "delete from keepalive where sockinfo NOT LIKE 'udp%';"
+fi
+KazooDB -db ${DB_CURRENT_DB} "update keepalive set selected = 0, time_sent = datetime('now') where selected < 3;"
+
+}
diff --git a/kamailio/db_scripts/db_init_watcher_triggers.sql b/kamailio/db_scripts/db_init_watcher_triggers.sql
new file mode 100644
index 0000000..8e5a202
--- /dev/null
+++ b/kamailio/db_scripts/db_init_watcher_triggers.sql
@@ -0,0 +1,14 @@
+CREATE TRIGGER if not exists active_watchers_watcher_uri_insert
+AFTER INSERT ON active_watchers
+FOR EACH ROW
+BEGIN
+ UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id;
+END;
+
+CREATE TRIGGER if not exists active_watchers_watcher_uri_update
+AFTER UPDATE ON active_watchers
+FOR EACH ROW
+WHEN OLD.watcher_username <> NEW.watcher_username OR OLD.watcher_domain <> NEW.watcher_domain
+BEGIN
+ UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id;
+END;
diff --git a/kamailio/db_scripts/db_kazoo-specific b/kamailio/db_scripts/db_kazoo-specific
index 014fd78..2f87516 100644
--- a/kamailio/db_scripts/db_kazoo-specific
+++ b/kamailio/db_scripts/db_kazoo-specific
@@ -6,15 +6,16 @@ cat << EOF
PRAGMA foreign_keys=OFF;
PRAGMA wal=on;
PRAGMA journal_mode=WAL;
+PRAGMA wal_autocheckpoint=25;
BEGIN TRANSACTION;
EOF
}
sql_setup() {
- DB_KAZOO_LOCATION=${DB_KAZOO_LOCATION:-/etc/kazoo/kamailio/db}
- mkdir -p ${DB_KAZOO_LOCATION}
- KazooDB -db ${DB_KAZOO_LOCATION}/kazoo.db < $1
+ DB_KAZOO_LOCATION=${2:-${DB_KAZOO_LOCATION:-/etc/kazoo/kamailio/db}}
+ mkdir -p ${DB_KAZOO_LOCATION}
+ KazooDB -db ${DB_KAZOO_LOCATION}/kazoo.db < $1 > /dev/null
}
sql_header() {
@@ -40,6 +41,108 @@ CREATE TABLE active_watchers_log (
user_agent VARCHAR(255) DEFAULT '' COLLATE NOCASE,
CONSTRAINT active_watchers_active_watchers_log_idx UNIQUE (presentity_uri, watcher_username, watcher_domain, event)
);
+INSERT INTO version (table_name, table_version) values ('active_watchers_log','1');
+
+CREATE TABLE keepalive (
+ id INTEGER PRIMARY KEY NOT NULL,
+ contact VARCHAR(2048) NOT NULL COLLATE NOCASE,
+ received VARCHAR(32) NOT NULL COLLATE NOCASE,
+ sockinfo VARCHAR(128) NOT NULL COLLATE NOCASE,
+ time_inserted timestamp DEFAULT CURRENT_TIMESTAMP,
+ time_sent timestamp DEFAULT CURRENT_TIMESTAMP,
+ slot INTEGER NOT NULL,
+ selected INTEGER DEFAULT 0,
+ failed INTEGER DEFAULT 0,
+ CONSTRAINT keepalive_idx UNIQUE (contact),
+ CONSTRAINT keepalive_idx_2 UNIQUE (slot, failed, contact)
+ );
+
+CREATE INDEX keepalive_idx_3 ON keepalive (slot, selected, time_sent);
+CREATE INDEX keepalive_idx_4 ON keepalive (received, selected);
+
+INSERT INTO version (table_name, table_version) values ('keepalive','4');
+
+ALTER TABLE active_watchers ADD COLUMN watcher_uri varchar(64) NOT NULL DEFAULT "sip:no_watcher@no_domain";
+
+CREATE TRIGGER active_watchers_watcher_uri_insert
+AFTER INSERT ON active_watchers
+FOR EACH ROW
+BEGIN
+ UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id;
+END;
+
+CREATE TRIGGER active_watchers_watcher_uri_update
+AFTER UPDATE ON active_watchers
+FOR EACH ROW
+WHEN OLD.watcher_username <> NEW.watcher_username OR OLD.watcher_domain <> NEW.watcher_domain
+BEGIN
+ UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id;
+END;
+
+CREATE UNIQUE INDEX active_watchers_contact ON active_watchers (contact, id);
+CREATE INDEX active_watchers_event_watcher_uri ON active_watchers (event, watcher_uri);
+
+
+CREATE INDEX location_attrs_ruid ON location_attrs (ruid);
+CREATE UNIQUE INDEX location_ruid ON location (ruid);
+
+create table auth_cache as select * from htable;
+INSERT INTO version (table_name, table_version) select 'auth_cache', table_version from version where table_name = 'htable';
+
+create table block_cache as select * from htable;
+INSERT INTO version (table_name, table_version) select 'block_cache', table_version from version where table_name = 'htable';
+
+
+ create view presentities as select id, cast(printf("sip:%s@%s",username,domain) as varchar(64)) presentity_uri ,
+ username, domain, event, cast(substr(etag, instr(etag,"@")+1) as varchar(64)) callid,
+ datetime(received_time, 'unixepoch') as received,
+ datetime(expires, 'unixepoch') as expire_date,
+ expires, cast(sender as varchar(30)) sender,
+ lower(cast( case when event = "dialog"
+ then substr(body, instr(BODY,"")+7, instr(body,"") - instr(body,"") - 7)
+ when event = "presence"
+ then case when instr(body,"") == 0
+ then replace(substr(body, instr(body,"")+6, instr(body,"") - instr(body,"") - 6), " ", "")
+ else replace(substr(body, instr(body,"")+9, instr(body,"") - instr(body,"") - 9), " ", "")
+ end
+ when event = "message-summary"
+ then case when instr(body,"Messages-Waiting: yes") = 0
+ then "Waiting"
+ else "Not-Waiting"
+ end
+ end as varchar(12))) state
+ from presentity;
+
+ create view wdispatcher as select *,
+ cast(substr(attrs, instr(attrs, "zone=")+5, instr(attrs, ";profile")-instr(attrs, "zone=")-5) as varchar(20)) zone,
+ cast(substr(attrs, instr(attrs, "idx=")+4, instr(attrs, ";node")-instr(attrs, "idx=")-4) as integer) idx,
+ cast(substr(attrs, instr(attrs, "node=")+5) as varchar(50)) node
+ from dispatcher;
+
+ create unique index if not exists idx_dispatcher_destination on dispatcher(destination);
+
+
+CREATE VIEW w_keepalive_contact as
+SELECT id, slot, selected, failed, case when instr(contact,";") > 0
+ then substr(contact, 1, instr(contact,";")-1)
+ else contact
+ end as contact
+from keepalive;
+
+CREATE VIEW w_location_contact as
+SELECT id, ruid, case when instr(contact,";") > 0
+ then substr(contact, 1, instr(contact,";")-1)
+ else contact
+ end as contact
+from location;
+
+CREATE VIEW w_watchers_contact as
+select id, case when instr(contact,";") > 0
+ then substr(contact, 1, instr(contact,";")-1)
+ else contact
+ end as contact
+from active_watchers;
+
EOF
}
diff --git a/kamailio/db_scripts/kazoodb-sql.sh b/kamailio/db_scripts/kazoodb-sql.sh
new file mode 100755
index 0000000..6351266
--- /dev/null
+++ b/kamailio/db_scripts/kazoodb-sql.sh
@@ -0,0 +1,56 @@
+#!/bin/sh -e
+
+KAMAILIO_SHARE_DIR=${KAMAILIO_SHARE_DIR:-/usr/share/kamailio}
+DB_ENGINE=${DB_ENGINE:-db_kazoo}
+RESULTED_SQL=${RESULTED_SQL:-/tmp/kamailio_initdb.sql}
+
+. $(dirname $0)/$DB_ENGINE-specific --source-only
+
+sql_filelist() {
+ echo `ls -A1 ${KAMAILIO_SHARE_DIR}/${DB_ENGINE}/*.sql | grep -v standard | tr '\n' '\0' | xargs -0 -n 1 basename | sort`
+}
+
+sql_all_header() {
+cat << EOF
+CREATE TABLE version (
+ table_name VARCHAR(32) NOT NULL,
+ table_version INTEGER DEFAULT 0 NOT NULL,
+ PRIMARY KEY(table_name)
+);
+INSERT INTO version VALUES('version',1);
+
+EOF
+}
+
+sql_all_extra_tables() {
+cat << EOF
+
+CREATE TABLE event_list ( event varchar(25) PRIMARY KEY NOT NULL);
+INSERT INTO event_list VALUES('dialog');
+INSERT INTO event_list VALUES('presence');
+INSERT INTO event_list VALUES('message-summary');
+INSERT INTO version VALUES('event_list',1);
+
+EOF
+}
+
+sql_all_footer() {
+cat << EOF
+COMMIT;
+EOF
+}
+
+sql_db_prepare() {
+ sql_db_pre_setup > $RESULTED_SQL
+ sql_all_header >> $RESULTED_SQL
+ sql_header >> $RESULTED_SQL
+ for i in $(sql_filelist); do
+ cat $KAMAILIO_SHARE_DIR/$DB_ENGINE/$i >> $RESULTED_SQL
+ done
+ sql_all_extra_tables >> $RESULTED_SQL
+ sql_extra_tables >> $RESULTED_SQL
+ sql_footer >> $RESULTED_SQL
+ sql_all_footer >> $RESULTED_SQL
+
+ echo "$RESULTED_SQL"
+}
diff --git a/kamailio/db_scripts/vw_presentities.sql b/kamailio/db_scripts/vw_presentities.sql
new file mode 100644
index 0000000..4c95a38
--- /dev/null
+++ b/kamailio/db_scripts/vw_presentities.sql
@@ -0,0 +1,20 @@
+CREATE VIEW presentities as
+select id, cast(printf("sip:%s@%s",username,domain) as varchar(64)) presentity_uri ,
+ username, domain, event, cast(substr(etag, instr(etag,"@")+1) as varchar(64)) callid,
+ datetime(received_time, 'unixepoch') as received,
+ datetime(expires, 'unixepoch') as expire_date,
+ expires, cast(sender as varchar(30)) sender,
+ lower(cast( case when event = "dialog"
+ then substr(body, instr(BODY,"")+7, instr(body,"") - instr(body,"") - 7)
+ when event = "presence"
+ then case when instr(body,"") == 0
+ then replace(substr(body, instr(body,"")+6, instr(body,"") - instr(body,"") - 6), " ", "")
+ else replace(substr(body, instr(body,"")+9, instr(body,"") - instr(body,"") - 9), " ", "")
+ end
+ when event = "message-summary"
+ then case when instr(body,"Messages-Waiting: yes") = 0
+ then "Waiting"
+ else "Not-Waiting"
+ end
+ end as varchar(12))) state
+ from presentity
diff --git a/kamailio/db_scripts/vw_w_keepalive_contact.sql b/kamailio/db_scripts/vw_w_keepalive_contact.sql
new file mode 100644
index 0000000..1639650
--- /dev/null
+++ b/kamailio/db_scripts/vw_w_keepalive_contact.sql
@@ -0,0 +1,6 @@
+CREATE VIEW w_keepalive_contact as
+ select id, slot, selected, failed, case when instr(contact,";") > 0
+ then substr(contact, 1, instr(contact,";")-1)
+ else contact
+ end as contact
+ from keepalive
diff --git a/kamailio/db_scripts/vw_w_location_contact.sql b/kamailio/db_scripts/vw_w_location_contact.sql
new file mode 100644
index 0000000..6914519
--- /dev/null
+++ b/kamailio/db_scripts/vw_w_location_contact.sql
@@ -0,0 +1,6 @@
+CREATE VIEW w_location_contact as
+ select id, ruid, case when instr(contact,";") > 0
+ then substr(contact, 1, instr(contact,";")-1)
+ else contact
+ end as contact
+ from location
diff --git a/kamailio/db_scripts/vw_w_watchers_contact.sql b/kamailio/db_scripts/vw_w_watchers_contact.sql
new file mode 100644
index 0000000..96d0186
--- /dev/null
+++ b/kamailio/db_scripts/vw_w_watchers_contact.sql
@@ -0,0 +1,6 @@
+CREATE VIEW w_watchers_contact as
+ select id, case when instr(contact,";") > 0
+ then substr(contact, 1, instr(contact,";")-1)
+ else contact
+ end as contact
+ from active_watchers
diff --git a/kamailio/db_scripts/vw_wdispatcher.sql b/kamailio/db_scripts/vw_wdispatcher.sql
new file mode 100644
index 0000000..1643b92
--- /dev/null
+++ b/kamailio/db_scripts/vw_wdispatcher.sql
@@ -0,0 +1,6 @@
+CREATE VIEW wdispatcher as
+ select *,
+ cast(substr(attrs, instr(attrs, "zone=")+5, instr(attrs, ";profile")-instr(attrs, "zone=")-5) as varchar(20)) zone,
+ cast(substr(attrs, instr(attrs, "idx=")+4, instr(attrs, ";node")-instr(attrs, "idx=")-4) as integer) idx,
+ cast(substr(attrs, instr(attrs, "node=")+5) as varchar(50)) node
+ from dispatcher
diff --git a/kamailio/default.cfg b/kamailio/default.cfg
index 31eb2a7..67faef0 100644
--- a/kamailio/default.cfg
+++ b/kamailio/default.cfg
@@ -1,15 +1,19 @@
## NOTE: DO NOT CHANGE THIS FILE, EDIT local.cfg ##
####### Flags #######
-flags
- FLAG_INTERNALLY_SOURCED: 1,
- FLAG_ASSOCIATE_SERVER: 2,
- FLAG_SKIP_NAT_CORRECTION: 3,
- FLAG_ASSOCIATE_USER: 4,
- FLAG_TRUSTED_SOURCE: 5,
- FLAG_SESSION_PROGRESS: 6,
- FLAG_IS_REPLY: 7,
- FLAG_SIP_TRACE: 8;
+#!trydef FLAG_INTERNALLY_SOURCED 1
+#!trydef FLAG_ASSOCIATE_SERVER 2
+#!trydef FLAG_SKIP_NAT_CORRECTION 3
+#!trydef FLAG_ASSOCIATE_USER 4
+#!trydef FLAG_TRUSTED_SOURCE 5
+#!trydef FLAG_SESSION_PROGRESS 6
+#!trydef FLAG_IS_REPLY 7
+#!trydef FLAG_SIP_TRACE 8
+#!trydef FLT_AOR 9
+#!trydef FLT_T38 10
+#!trydef FLT_NATS 11
+#!trydef FLAG_LOCAL_REQUEST 12
+#!trydef FLAG_LOCAL_ROUTE 17
####### Global Parameters #########
fork = yes
@@ -22,15 +26,17 @@ mlock_pages = yes
phone2tel = 1
max_while_loops = MAX_WHILE_LOOPS
-pv_buffer_size=65536
+pv_buffer_size = PV_BUFFER_SIZE
+pv_buffer_slots = PV_BUFFER_SLOTS
+
mem_join=1
####### Logging Parameters #########
debug = KAZOO_LOG_LEVEL
memdbg = 10
-memlog = L_INFO
+memlog = L_BUG
corelog = L_ERR
-mem_summary = 12
+mem_summary = 0
log_stderror = no
log_facility = LOG_LOCAL0
log_name="kamailio"
@@ -44,22 +50,22 @@ tos = IPTOS_LOWDELAY
####### TCP Parameters #########
tcp_children = TCP_CHILDREN
disable_tcp = no
-tcp_max_connections = 4096
-tcp_connection_lifetime = 3605
+tcp_max_connections = TCP_MAX_CONNECTIONS
+tcp_connection_lifetime = TCP_CONNECTION_LIFETIME
tcp_accept_aliases = no
tcp_async = yes
-tcp_connect_timeout = 10
+tcp_connect_timeout = TCP_CONNECTION_TIMEOUT
tcp_conn_wq_max = 65536
tcp_crlf_ping = yes
tcp_delayed_ack = yes
tcp_fd_cache = yes
-tcp_keepalive = yes
-tcp_keepcnt = 3
-tcp_keepidle = 30
-tcp_keepintvl = 10
+tcp_keepalive = TCP_KEEP_ALIVE
+tcp_keepcnt = TCP_KEEP_COUNT
+tcp_keepidle = TCP_KEEP_IDLE
+tcp_keepintvl = TCP_KEEP_INTERVAL
tcp_linger2 = 30
tcp_rd_buf_size = 80000
-tcp_send_timeout = 10
+tcp_send_timeout = TCP_SEND_TIMEOUT
tcp_wq_blk_size = 2100
tcp_wq_max = 10485760
@@ -88,6 +94,9 @@ dns_srv_lb = off
####### SCTP Parameters #########
disable_sctp = yes
+####### multi homed #########
+mhomed=KZ_MULTI_HOMED
+
######## Kamailio mqueue module ########
loadmodule "mqueue.so"
@@ -100,14 +109,16 @@ loadmodule "stun.so"
######## Kamailio path module ########
loadmodule "path.so"
-######## Kamailio ipops module ########
-loadmodule "ipops.so"
-
######## Kamailio control connector module ########
loadmodule "ctl.so"
modparam("ctl", "binrpc_buffer_size", 4096)
loadmodule "cfg_rpc.so"
+
+######## Kamailio config utils module ########
loadmodule "cfgutils.so"
+modparam("cfgutils", "lock_set_size", 4)
+
+######## Kamailio corex module ########
loadmodule "corex.so"
######## Kamailio uuid module ########
@@ -124,6 +135,10 @@ modparam("tm", "auto_inv_100_reason", "Attempting to connect your call")
modparam("tm", "cancel_b_method", 2)
modparam("tm", "ruri_matching", 0)
modparam("tm", "failure_reply_mode", 3)
+modparam("tm", "failure_exec_mode", 1)
+modparam("tm", "reparse_on_dns_failover", 0)
+
+
# modparam("tm", "fr_timer", 30000)
# modparam("tm", "fr_inv_timer", 120000)
@@ -132,8 +147,9 @@ loadmodule "sl.so"
######## Record-Route and Route module ########
loadmodule "rr.so"
-modparam("rr", "enable_full_lr", 1)
-modparam("rr", "enable_double_rr", 1)
+modparam("rr", "enable_full_lr", RR_FULL_LR)
+modparam("rr", "enable_double_rr", RR_DOUBLE_RR)
+modparam("rr", "force_send_socket", RR_FORCE_SOCKET)
######## Max-Forward processor module ########
loadmodule "maxfwd.so"
@@ -142,23 +158,25 @@ modparam("maxfwd", "max_limit", 50)
######## SIP utilities [requires sl] ########
loadmodule "siputils.so"
-######## SIP message formatting sanity checks [requires sl] ########
-loadmodule "sanity.so"
-modparam("sanity", "default_checks", 1511)
-modparam("sanity", "uri_checks", 7)
-modparam("sanity", "autodrop", 0)
-
######## Text operations module ########
loadmodule "textops.so"
loadmodule "textopsx.so"
+######## sdp operations module ########
+loadmodule "sdpops.so"
+
######## Generic Hash Table container in shared memory ########
loadmodule "htable.so"
modparam("htable", "htable", "associations=>size=16;autoexpire=7200")
modparam("htable", "htable", "redirects=>size=16;autoexpire=5")
+modparam("htable", "db_url", "KAZOO_DB_URL")
+
+####### RTIMER module ##########
+loadmodule "rtimer.so"
-######## Pseudo-Variables module ########
-loadmodule "pv.so"
+####### evrexec module ##########
+loadmodule "evrexec.so"
+modparam("evrexec", "exec", "name=evrexec:DEFERRED_INIT;wait=20000000;workers=1;")
######## Advanced logger module ########
loadmodule "xlog.so"
@@ -181,54 +199,25 @@ loadmodule "sqlops.so"
modparam("sqlops","sqlcon", "cb=>KAZOO_DB_URL")
modparam("sqlops","sqlcon", "exec=>KAZOO_DB_URL")
-####### DATABASE module ##########
-loadmodule "db_KAMAILIO_DBMS.so"
-
-####### Kazoo Integration module ##########
-loadmodule "kazoo.so"
-modparam("kazoo", "pua_mode", MY_AMQP_PUA_MODE)
-modparam("kazoo", "amqp_primary_zone", "MY_AMQP_ZONE")
-modparam("kazoo", "amqp_query_timeout_avp", "$avp(kz_timeout)")
-modparam("kazoo", "node_hostname", "MY_HOSTNAME")
-modparam("kazoo", "amqp_heartbeats", MY_AMQP_HEARTBEATS)
-modparam("kazoo", "amqp_max_channels", MY_AMQP_MAX_CHANNELS)
-modparam("kazoo", "amqp_consumer_processes", MY_AMQP_CONSUMER_PROCESSES)
-modparam("kazoo", "amqp_consumer_workers", MY_AMQP_CONSUMER_WORKERS)
-## amqp connections
-modparam("kazoo", "amqp_connection", "MY_AMQP_URL")
-#!ifdef MY_AMQP_SECONDARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_SECONDARY_URL")
-#!endif
-#!ifdef MY_AMQP_TERTIARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_TERTIARY_URL")
-#!endif
-#!ifdef MY_AMQP_QUATERNARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_QUATERNARY_URL")
-#!endif
-#!ifdef MY_AMQP_QUINARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_QUINARY_URL")
-#!endif
-#!ifdef MY_AMQP_SENARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_SENARY_URL")
-#!endif
-#!ifdef MY_AMQP_SEPTENARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_SEPTENARY_URL")
-#!endif
-#!ifdef MY_AMQP_OCTONARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_OCTONARY_URL")
-#!endif
-#!ifdef MY_AMQP_NONARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_NONARY_URL")
-#!endif
-#!ifdef MY_AMQP_DENARY_URL
-modparam("kazoo", "amqp_connection", "MY_AMQP_DENARY_URL")
-#!endif
+####### DEBUG ######
+loadmodule "debugger.so"
+modparam("debugger", "mod_hash_size", 5)
+modparam("debugger", "mod_level_mode", 1)
+modparam("debugger", "mod_level", "core=1")
+####### STATISTICS ######
+loadmodule "statistics.so"
+
+####### DATABASE module ##########
+include_file "db_KAMAILIO_DBMS.cfg"
###### kazoo bindings ######
include_file "kazoo-bindings.cfg"
####### Role Configurations ##########
+#!ifdef AUTHORIZATION_ROLE
+include_file "authorization-role.cfg"
+#!endif
#!ifdef DISPATCHER_ROLE
include_file "dispatcher-role.cfg"
#!endif
@@ -277,18 +266,27 @@ include_file "nodes-role.cfg"
#!ifdef SIP_TRACE_ROLE
include_file "sip_trace-role.cfg"
#!endif
+#!ifdef KEEPALIVE_ROLE
+include_file "keepalive-role.cfg"
+#!endif
+#!ifdef BLOCKER_ROLE
+include_file "blocker-role.cfg"
+#!endif
+
+## sanity ##
+include_file "sanity.cfg"
+## auth ##
+include_file "auth.cfg"
####### Permissions module ##########
loadmodule "permissions.so"
modparam("permissions", "db_url", "KAZOO_DB_URL")
modparam("permissions", "db_mode", 1)
-
-####### DEBUG ######
-loadmodule "debugger.so"
-modparam("debugger", "mod_hash_size", 5)
-modparam("debugger", "mod_level_mode", 1)
+###### local route ######
+tcp_children = 5
+listen=tcp:127.0.0.1:5090
####### SDPOPS ######
loadmodule "sdpops.so"
@@ -296,21 +294,14 @@ loadmodule "sdpops.so"
####### Routing Logic ########
route
{
- route(SANITY_CHECK);
-
- route(CHECK_RETRANS);
+ route(LOCAL_REQUEST);
- # log the basic info regarding this call
- xlog("L_INFO", "$ci|start|received $pr request $rm $ou\n");
- xlog("L_INFO", "$ci|log|source $si:$sp -> $Ri:$Rp\n");
- xlog("L_INFO", "$ci|log|from $fu\n");
- xlog("L_INFO", "$ci|log|to $tu\n");
+ route(SANITY_CHECK);
- route(CLASSIFY_SOURCE);
+ route(CHECK_RETRANS);
#!ifdef ANTIFLOOD_ROLE
- route(ANTIFLOOD_RATE_LIMIT);
- route(ANITFLOOD_AUTH_LIMIT);
+ route(ANTIFLOOD_LIMIT);
#!endif
#!ifdef TRAFFIC_FILTER_ROLE
@@ -325,12 +316,20 @@ route
route(DOS_PREVENTION);
#!endif
- #!ifdef WEBSOCKETS_ROLE
- route(HANDLE_WEBSOCKETS);
+ route(LOG_REQUEST);
+
+ route(CLASSIFY_SOURCE);
+
+ #!ifdef NAT_TRAVERSAL_ROLE
+ route(NAT_DETECT);
#!endif
route(HANDLE_OPTIONS);
+ #!ifdef SIP_TRACE_ROLE
+ route(SIP_TRACE);
+ #!endif
+
route(HANDLE_NOTIFY);
#!ifdef AUTHORIZATION_ROLE
@@ -348,6 +347,8 @@ route
route(HANDLE_REGISTER);
#!endif
+ route(HANDLE_REFER);
+
route(HANDLE_IN_DIALOG_REQUESTS);
route(PREPARE_INITIAL_REQUESTS);
@@ -362,13 +363,28 @@ route
}
#!endif
- #!ifdef DISPATCHER_ROLE
- if (!isflagset(FLAG_INTERNALLY_SOURCED)) {
- route(DISPATCHER_FIND_ROUTES);
+ route(AUTH);
+
+ route(SETUP);
+
+}
+
+#!trydef KZ_LOG_REQUEST_OPTIONS 0
+kazoo.log_request_options = KZ_LOG_REQUEST_OPTIONS descr "log OPTIONS requests, default is 0 for preserving log size"
+
+route[LOG_REQUEST]
+{
+ if($sel(cfg_get.kazoo.log_request_options) == 0 && is_method("OPTIONS")) {
+ $var(log_request_level) = L_DBG;
+ } else {
+ $var(log_request_level) = L_INFO;
}
- #!endif
- route(RELAY);
+ # log the basic info regarding this call
+ xlog("$var(log_request_level)", "$ci|start|received $pr request $rm $ou\n");
+ xlog("$var(log_request_level)", "$ci|log|source $si:$sp -> $RAi:$RAp\n");
+ xlog("$var(log_request_level)", "$ci|log|from $fu\n");
+ xlog("$var(log_request_level)", "$ci|log|to $tu\n");
}
route[CHECK_RETRANS]
@@ -383,121 +399,94 @@ route[CHECK_RETRANS]
}
}
-route[SANITY_CHECK]
-{
- ## CVE-2018-14767
- if($(hdr(To)[1]) != $null) {
- xlog("second To header not null - dropping message");
- drop;
- }
-
- if (!sanity_check()) {
- xlog("L_WARN", "$ci|end|message from $si:$sp is insane\n");
- exit;
- }
-
- if (!mf_process_maxfwd_header("10")) {
- xlog("L_WARN", "$ci|end|too much hops, not enough barley from $si:$sp\n");
- send_reply("483", "Too Many Hops");
- exit;
- }
-
- if ($ua == "friendly-scanner" ||
- $ua == "sundayddr" ||
- $ua == "pplsip" ||
- $ua =~ "NiceGuy" ||
- $ua =~ "PortSIP" ||
- $ua =~ "sipcli" ) {
- xlog("L_WARN", "$ci|end|dropping message with user-agent $ua from $si:$sp\n");
- exit;
- }
-
- if(sdp_get_line_startswith("$avp(sanity_sline)", "s=")) {
- if ($avp(sanity_sline) == "s=portsip.com") {
- xlog("L_WARN", "$ci|end|dropping message with '$avp(sanity_sline)' string in SDP\n");
- exit;
- }
- }
-}
-
route[CLASSIFY_SOURCE]
{
#!ifdef DISPATCHER_ROLE
route(DISPATCHER_CLASSIFY_SOURCE);
#!endif
- if (isflagset(FLAG_INTERNALLY_SOURCED) || allow_source_address(TRUSTED_ADR_GROUP) || is_myself($si)) {
- xlog("L_INFO", "$ci|log|request from trusted IP\n");
+ if (allow_source_address(TRUSTED_ADR_GROUP)) {
+ xlog("$var(log_request_level)", "$ci|log|request from trusted IP\n");
setflag(FLAG_TRUSTED_SOURCE);
}
+
+ if (isflagset(FLAG_INTERNALLY_SOURCED) || is_myself($si)) {
+ setflag(FLAG_TRUSTED_SOURCE);
+ }
+
}
route[HANDLE_OPTIONS]
{
- if (is_method("OPTIONS")) {
- if (isflagset(FLAG_INTERNALLY_SOURCED)) {
- route(INTERNAL_TO_EXTERNAL_RELAY);
- } else {
- #!ifdef TRAFFIC_FILTER_ROLE
- if (!isflagset(FLAG_TRUSTED_SOURCE)) {
- route(FILTER_REQUEST_DOMAIN);
- }
- #!endif
-
- #!ifdef NAT_TRAVERSAL_ROLE
- route(NAT_TEST_AND_CORRECT);
- #!endif
+ if (!is_method("OPTIONS")) {
+ return;
+ }
- sl_send_reply("200", "Rawr!!");
+ if (isflagset(FLAG_INTERNALLY_SOURCED)) {
+ route(INTERNAL_TO_EXTERNAL_RELAY);
+ } else {
+ #!ifdef TRAFFIC_FILTER_ROLE
+ if (!isflagset(FLAG_TRUSTED_SOURCE)) {
+ route(FILTER_REQUEST_DOMAIN);
}
- exit;
+ #!endif
+
+ sl_send_reply("200", "Rawr!!");
+
+ #!ifdef KEEPALIVE_ROLE
+ route(KEEPALIVE_ON_OPTIONS);
+ #!endif
}
+ exit;
}
route[HANDLE_NOTIFY]
{
- if (has_totag())
- return;
+ if (!is_method("NOTIFY")) return;
- if (is_method("NOTIFY")) {
- if (isflagset(FLAG_INTERNALLY_SOURCED)) {
- if (loose_route()) {
- xlog("L_INFO", "$ci|log|Able to loose-route. Cool beans!\n");
- }
+ if (has_totag()) return;
- #!ifdef REGISTRAR_ROLE
- if (registered("location")) {
- lookup("location");
- xlog("L_INFO", "$ci|log|routing to $ruid\n");
- }
- #!endif
+ if (isflagset(FLAG_INTERNALLY_SOURCED)) {
+ if (loose_route()) {
+ xlog("L_INFO", "$ci|log|Able to loose-route. Cool beans!\n");
+ }
- route(INTERNAL_TO_EXTERNAL_RELAY);
- } else {
- #!ifdef TRAFFIC_FILTER_ROLE
- if (!isflagset(FLAG_TRUSTED_SOURCE)) {
- route(FILTER_REQUEST_DOMAIN);
- }
- #!endif
+ #!ifdef REGISTRAR_ROLE
+ if (registered("location")) {
+ lookup("location");
+ xlog("L_INFO", "$ci|log|routing to $ruid\n");
+ }
+ #!endif
- #!ifdef WEBSOCKETS_ROLE
- route(NAT_WEBSOCKETS_CORRECT);
- #!endif
+ ## verify we're not routing to ourselves
+ if(is_myself($du)) {
+ xlog("L_INFO", "$ci|log|notify from internal to invalid destination $ruid\n");
+ sl_send_reply("200", "Rawr!!");
+ exit;
+ }
- #!ifdef NAT_TRAVERSAL_ROLE
- route(NAT_TEST_AND_CORRECT);
- #!endif
+ route(INTERNAL_TO_EXTERNAL_RELAY);
+ } else {
+ #!ifdef TRAFFIC_FILTER_ROLE
+ if (!isflagset(FLAG_TRUSTED_SOURCE)) {
+ route(FILTER_REQUEST_DOMAIN);
+ }
+ #!endif
- if($hdr(Event) == "keep-alive") {
- xlog("L_INFO", "$ci|stop|replying to keep alive\n");
- sl_send_reply("405", "Stay Alive / Method Not Allowed");
- } else {
- xlog("L_INFO", "$ci|stop|consuming event $hdr(Event)\n");
- sl_send_reply("200", "Rawr!!");
- }
+ if($hdr(Event) == "keep-alive") {
+ xlog("L_INFO", "$ci|stop|replying to keep alive\n");
+ sl_send_reply("405", "Stay Alive / Method Not Allowed");
+ } else {
+ xlog("L_INFO", "$ci|stop|consuming event $hdr(Event)\n");
+ sl_send_reply("200", "Rawr!!");
}
- exit;
+
+ #!ifdef KEEPALIVE_ROLE
+ route(KEEPALIVE_ON_NOTIFY);
+ #!endif
+
}
+ exit;
}
route[HANDLE_MESSAGE]
@@ -518,7 +507,7 @@ route[HANDLE_MESSAGE]
exit();
#!endif
} else {
- xlog("L_WARN", "$ci|end|MESSAGE $(hdr(Content-Type))\n");
+ xlog("L_WARN", "$ci|end|MESSAGE $hdr(Content-Type)\n");
if( $hdr(Content-Type) == "application/im-iscomposing+xml" ) {
xlog("L_WARN", "$ci|end|dropping MESSAGE application/im-iscomposing+xml\n");
sl_send_reply("200", "OK");
@@ -542,54 +531,86 @@ route[HANDLE_MESSAGE]
#!endif
}
+route[HANDLE_REFER]
+{
+ if (!is_method("REFER")) {
+ return;
+ }
+
+ if(is_present_hf("Referred-By")) {
+ $var(referred_by) = $hdr(Referred-By);
+ } else {
+ $var(referred_by) = $_s(;created=true);
+ }
+ $xavp(regcfg=>match_received) = $su;
+ if(registered("location", "$rz:$Au", 2, 1) == 1) {
+ $var(referred_by) = $_s($var(referred_by);endpoint_id=$(xavp(ulattrs=>token){re.subst,/(.*)@(.*)/\1/});account_id=$(xavp(ulattrs=>token){re.subst,/(.*)@(.*)/\2/}));
+ }
+
+ remove_hf_re("^Referred-By");
+ append_hf("Referred-By: $var(referred_by)\r\n");
+
+}
route[HANDLE_IN_DIALOG_REQUESTS]
{
- if (has_totag()) {
- if (is_method("INVITE")) {
- setflag(FLAG_SESSION_PROGRESS);
- record_route();
+ if (!has_totag()) return;
+
+ if (is_method("INVITE")) {
+ setflag(FLAG_SESSION_PROGRESS);
+ }
+
+ if (loose_route()) {
+
+ #!ifdef NAT_TRAVERSAL_ROLE
+ if(!isdsturiset()) {
+ handle_ruri_alias();
}
- if (loose_route()) {
+ if ( is_method("ACK") ) {
+ # ACK is forwarded statelessly
+ route(NAT_MANAGE);
+ }
+ #!endif
- #!ifdef ACCOUNTING_ROLE
- if (is_method("BYE")) {
- setflag(FLAG_ACC);
- setflag(FLAG_ACCFAILED);
- }
- #!endif
+ #!ifdef ACCOUNTING_ROLE
+ if (is_method("BYE")) {
+ setflag(FLAG_ACC);
+ setflag(FLAG_ACCFAILED);
+ }
+ #!endif
- #!ifdef NAT_TRAVERSAL_ROLE
- if(!isdsturiset()) {
- handle_ruri_alias();
- }
- #!endif
-
- xlog("L_INFO", "$ci|log|loose_route in-dialog message\n");
- # Called on in-dialog requests
- # If the request in an Invite for on hold from external to internal,
- # associate the contact with the media server
- # if Invite for on hold, we need to associate the contact URI with the next hop
- if (is_method("INVITE") && !isflagset(FLAG_INTERNALLY_SOURCED) && is_audio_on_hold()) {
- setflag(FLAG_ASSOCIATE_USER);
- }
- if ( is_method("NOTIFY") ) {
- # Add Record-Route for in-dialog NOTIFY as per RFC 6665.
- record_route();
- }
- route(RELAY);
- } else if (isflagset(FLAG_INTERNALLY_SOURCED)) {
- xlog("L_INFO", "$ci|log|relay internally sourced in-dialog message without loose_route\n");
- route(RELAY);
- } else if (t_check_trans()) {
- xlog("L_INFO", "$ci|log|allow message for a known transaction\n");
- route(RELAY);
- } else {
- xlog("L_INFO", "$ci|log|message had a to-tag but can't be loose routed\n");
- sl_send_reply("481", "Call Leg/Transaction Does Not Exist");
+ xlog("L_INFO", "$ci|log|loose_route in-dialog message\n");
+ # Called on in-dialog requests
+ # If the request in an Invite for on hold from external to internal,
+ # associate the contact with the media server
+ # if Invite for on hold, we need to associate the contact URI with the next hop
+ if (is_method("INVITE") && !isflagset(FLAG_INTERNALLY_SOURCED) && is_audio_on_hold()) {
+ setflag(FLAG_ASSOCIATE_USER);
}
- exit();
+
+ # If the request in an Invite for t38 from internal,
+ # mark the request with FLT_T38
+ if (is_method("INVITE") && isflagset(FLAG_INTERNALLY_SOURCED) && sdp_with_media("image")) {
+ xlog("L_DEBUG", "$ci|log|T38 RE-INVITE\n");
+ setflag(FLT_T38);
+ }
+
+ if ( is_method("NOTIFY") ) {
+ # Add Record-Route for in-dialog NOTIFY as per RFC 6665.
+ record_route();
+ }
+ route(RELAY);
+ } else if (isflagset(FLAG_INTERNALLY_SOURCED)) {
+ xlog("L_INFO", "$ci|log|relay internally sourced in-dialog message without loose_route\n");
+ route(RELAY);
+ } else if (t_check_trans()) {
+ xlog("L_INFO", "$ci|log|allow message for a known transaction\n");
+ route(RELAY);
+ } else {
+ xlog("L_INFO", "$ci|log|message had a to-tag but can't be loose routed\n");
+ sl_send_reply("481", "Call Leg/Transaction Does Not Exist");
}
+ exit();
}
route[PREPARE_INITIAL_REQUESTS]
@@ -638,11 +659,49 @@ route[PREPARE_INITIAL_REQUESTS]
record_route();
}
-route[RELAY]
+route[SETUP]
{
- #!ifdef SIP_TRACE_ROLE
- route(SEND_SIP_TRACE);
+ #!ifdef DISPATCHER_ROLE
+ if (!isflagset(FLAG_INTERNALLY_SOURCED)) {
+ route(DISPATCHER_FIND_ROUTES);
+ }
#!endif
+
+ #!ifdef REGISTRAR_ROLE
+ if (isflagset(FLAG_INTERNALLY_SOURCED)) {
+ route(ROUTE_TO_AOR);
+ }
+ #!endif
+
+ route(RELAY);
+}
+
+route[BRANCH_HEADERS]
+{
+ if (!isflagset(FLAG_INTERNALLY_SOURCED)) {
+ route(AUTH_HEADERS);
+ } else {
+ remove_hf_re("^X-");
+ }
+
+}
+
+# Manage outgoing branches
+branch_route[MANAGE_BRANCH] {
+ xlog("L_DEBUG", "$ci|branch|new branch [$T_branch_idx] to $ru => $du\n");
+ #!ifdef NAT_TRAVERSAL_ROLE
+ route(NAT_MANAGE);
+ #!endif
+
+ route(BRANCH_HEADERS);
+
+}
+
+route[RELAY]
+{
+ if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
+ if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
+ }
if (isflagset(FLAG_INTERNALLY_SOURCED)) {
route(INTERNAL_TO_EXTERNAL_RELAY);
@@ -666,30 +725,6 @@ route[INTERNAL_TO_EXTERNAL_RELAY]
}
#!endif
- #!ifdef REGISTRAR_ROLE
- if ($hdr(X-KAZOO-AOR) != $null) {
- xlog("L_INFO", "$ci|log|using AOR $hdr(X-KAZOO-AOR)\n");
- if ($hdr(X-KAZOO-INVITE-FORMAT) == "contact") {
- if(lookup("location", "$hdr(X-KAZOO-AOR)") > 0){
- xlog("L_INFO", "$ci|end|routing to contact $ru\n");
- } else {
- xlog("L_INFO", "$ci|end|lookup for AOR $hdr(X-KAZOO-AOR) failed\n");
- sl_send_reply("410", "Not registered");
- exit;
- }
- } else if (reg_fetch_contacts("location", "$hdr(X-KAZOO-AOR)", "callee")) {
- $du = $(ulc(callee=>received));
- $fs = $(ulc(callee=>socket));
- xlog("L_INFO", "$ci|log|routing $hdr(X-KAZOO-AOR) to $du via $fs\n");
- } else {
- xlog("L_INFO", "$ci|end|user is not registered\n");
- sl_send_reply("410", "Not registered");
- exit;
- }
- }
- #!endif
-
- remove_hf_re("^X-.*");
t_on_reply("EXTERNAL_REPLY");
@@ -707,21 +742,6 @@ route[EXTERNAL_TO_INTERNAL_RELAY]
}
#!endif
- #!ifdef NAT_TRAVERSAL_ROLE
- if (!isflagset(FLAG_INTERNALLY_SOURCED)) {
- route(NAT_TEST_AND_CORRECT);
- }
- #!endif
-
- remove_hf_re("^X-.*");
-
- append_hf("X-AUTH-IP: $si\r\n");
- append_hf("X-AUTH-PORT: $sp\r\n");
-
- #!ifdef REGISTRAR_ROLE
- route(ADD_AUTHORIZATION_HEADERS);
- #!endif
-
t_on_reply("INTERNAL_REPLY");
t_on_failure("INTERNAL_FAULT");
@@ -732,14 +752,12 @@ route[EXTERNAL_TO_INTERNAL_RELAY]
onreply_route[EXTERNAL_REPLY]
{
- xlog("L_INFO", "$ci|log|external reply $T_reply_code\n");
-
- #!ifdef WEBSOCKETS_ROLE
- route(NAT_WEBSOCKETS_CORRECT);
- #!endif
+ xlog("L_INFO", "$ci|log|external reply $T_reply_code $T_reply_reason\n");
#!ifdef NAT_TRAVERSAL_ROLE
- route(NAT_TEST_AND_CORRECT);
+ if(status=~"[12][0-9][0-9]") {
+ route(NAT_MANAGE);
+ }
#!endif
#!ifdef ACL_ROLE
@@ -751,7 +769,7 @@ onreply_route[EXTERNAL_REPLY]
setflag(FLAG_IS_REPLY);
route(DOS_PREVENTION);
#!endif
-
+
#!ifdef MESSAGE_ROLE
if (is_method("MESSAGE")) {
route(MESSAGE_REPLY);
@@ -762,11 +780,15 @@ onreply_route[EXTERNAL_REPLY]
onreply_route[INTERNAL_REPLY]
{
# this route handles replies that are comming from our media server
- xlog("L_INFO", "$ci|start|received internal reply $T_reply_code $rr\n");
- xlog("L_INFO", "$ci|log|source $si:$sp\n");
+ if ($rs < 300) {
+ xlog("L_INFO", "$ci|log|internal reply $T_reply_code $T_reply_reason\n");
+ xlog("L_DEBUG", "$ci|log|source $si:$sp\n");
+ }
- #!ifdef WEBSOCKETS_ROLE
- route(NAT_WEBSOCKETS_CORRECT);
+ #!ifdef NAT_TRAVERSAL_ROLE
+ if(status=~"[12][0-9][0-9]") {
+ route(NAT_MANAGE);
+ }
#!endif
#!ifdef ACL_ROLE
@@ -797,7 +819,6 @@ onreply_route[INTERNAL_REPLY]
xlog("L_INFO", "$ci|pass|$T_req($si):$T_req($sp)\n");
}
- $var(reply_reason) = $rr;
}
failure_route[INTERNAL_FAULT]
@@ -834,32 +855,34 @@ failure_route[INTERNAL_FAULT]
# change 6xx to 4xx
if (t_check_status("6[0-9][0-9]") && !t_check_status("600|603|604|606")) {
$var(new_code) = "4" + $(T_reply_code{s.substr,1,0});
- xlog("L_INFO", "$ci|log|sending 6XX reply as $var(new_code) $var(reply_reason)\n");
- t_reply("$(var(new_code){s.int})", "$var(reply_reason)");
+ xlog("L_INFO", "$ci|failure|sending $T_reply_code reply as $var(new_code) $T_reply_reason\n");
+ t_reply("$(var(new_code){s.int})", "$T_reply_reason");
# if the failure case was something that we should recover
# from then try to find a new media server
- } else if ($var(reply_reason) =~ "call barred") {
- xlog("L_INFO", "$ci|log|failure route ignoring call barred\n");
+ } else if ($T_reply_reason =~ "call barred") {
+ xlog("L_INFO", "$ci|failure|ignoring call barred\n");
} else if (isflagset(FLAG_SESSION_PROGRESS)) {
- xlog("L_INFO", "$ci|log|failure route ignoring failure after session progress\n");
- } else if (t_check_status("403") && $var(reply_reason)=="Forbidden") {
- xlog("L_WARNING", "$ci|log|failure route ignoring. Failed auth from IP $si\n");
- } else if (t_check_status("(401)|(407)|(486)|(403)")) {
- xlog("L_INFO", "$ci|log|failure route ignoring auth reply $T_reply_code $var(reply_reason)\n");
+ xlog("L_INFO", "$ci|failure|ignoring failure after session progress\n");
+ } else if (t_check_status("403") && $T_reply_reason=="Forbidden") {
+ xlog("L_WARNING", "$ci|failure|Failed auth from IP $si\n");
+ } else if (t_check_status("(401)|(407)|(486)")) {
+ xlog("L_INFO", "$ci|failure|auth reply $T_reply_code $T_reply_reason\n");
} else if (t_check_status("402")) {
- xlog("L_INFO", "$ci|log|failure route overriding reply code 402 with 486\n");
+ xlog("L_INFO", "$ci|failure|overriding reply code 402 with 486\n");
send_reply("486", "Insufficient Funds");
} else if (t_check_status("(4[0-9][0-9])|(5[0-9][0-9])")) {
- xlog("L_INFO", "$ci|start|received failure reply $T_reply_code $rr\n");
+ xlog("L_INFO", "$ci|failure|internal reply $T_reply_code $T_reply_reason\n");
#!ifdef DISPATCHER_ROLE
route(DISPATCHER_NEXT_ROUTE);
#!endif
send_reply("486", "Unable to Comply");
+
} else {
- xlog("L_INFO", "$ci|log|failure route ignoring reply $T_reply_code $rr\n");
+ xlog("L_INFO", "$ci|failure|internal reply $T_reply_code $T_reply_reason\n");
+ send_reply("$T_reply_code", "$T_reply_reason");
}
xlog("L_INFO", "$ci|pass|$si:$sp\n");
}
@@ -891,53 +914,94 @@ onsend_route {
$sht(associations=>$var(user_source))= "sip:" + $sndto(ip) + ":" + $sndto(port);
}
- xlog("L_INFO", "$ci|pass|$sndfrom(ip):$sndfrom(port) -> $sndto(ip):$sndto(port)\n");
+ #!ifdef SIP_TRACE_ROLE
+ if (is_method("ACK") && isflagset(FLAG_SIP_TRACE)) {
+ sip_trace();
+ }
+ #!endif
+
+ if(!isflagset(FLAG_LOCAL_ROUTE)) {
+ xlog("L_INFO", "$ci|pass|$sndfrom(ip):$sndfrom(port) -> $sndto(ip):$sndto(port)\n");
+ }
}
-#!ifdef REGISTRAR_ROLE
-route[ADD_AUTHORIZATION_HEADERS]
+route[ROUTE_TO_AOR]
{
- if (!is_method("INVITE|MESSAGE|REFER")) {
+ if ($hdr(X-KAZOO-AOR) == $null) {
return;
}
- $xavp(regcfg=>match_received) = $su;
- if (registered("location","$fu", 2, 1) == 1) {
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0)
- append_hf("X-ecallmgr_Account-ID: $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0)
- append_hf("X-ecallmgr_Authorizing-Type: $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}{s.len}) > 0)
- append_hf("X-ecallmgr_Authorizing-ID: $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Username}{s.len}) > 0)
- append_hf("X-ecallmgr_Username: $(xavp(ulattrs=>custom_channel_vars){kz.json,Username})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}{s.len}) > 0)
- append_hf("X-ecallmgr_Realm: $(xavp(ulattrs=>custom_channel_vars){kz.json,Realm})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}{s.len}) > 0)
- append_hf("X-ecallmgr_Account-Realm: $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.len}) > 0)
- append_hf("X-ecallmgr_Account-Name: $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}{s.len}) > 0)
- append_hf("X-ecallmgr_Presence-ID: $(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID})\r\n");
-
- if($(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}{s.len}) > 0)
- append_hf("X-ecallmgr_Owner-ID: $(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID})\r\n");
- }
+ xlog("L_INFO", "$ci|log|using AOR $hdr(X-KAZOO-AOR)\n");
+ if ($hdr(X-KAZOO-INVITE-FORMAT) == "contact") {
+ if(lookup("location", "$hdr(X-KAZOO-AOR)") > 0){
+ xlog("L_INFO", "$ci|end|routing to contact $ru\n");
+ handle_ruri_alias();
+ } else {
+ xlog("L_INFO", "$ci|end|lookup for AOR $hdr(X-KAZOO-AOR) failed\n");
+ sl_send_reply("410", "Not registered");
+ exit;
+ }
+ } else if (reg_fetch_contacts("location", "$hdr(X-KAZOO-AOR)", "callee")) {
+ $du = $(ulc(callee=>received));
+ $fs = $(ulc(callee=>socket));
+ xlog("L_INFO", "$ci|log|routing $hdr(X-KAZOO-AOR) to $du via $fs\n");
+
+ } else {
+ xlog("L_INFO", "$ci|end|user is not registered\n");
+ sl_send_reply("410", "Not registered");
+ exit;
+ }
}
-#!endif
-#!ifdef PRESENCE_NOTIFY_INIT
event_route[tm:local-request]
{
- route(PRESENCE_LOCAL_NOTIFY);
+ setflag(FLAG_LOCAL_REQUEST);
+ xlog("L_DEBUG", "$ci|local|start $pr request $rm $ou\n");
+ xlog("L_DEBUG", "$ci|local|source $si:$sp -> $dd:$dp\n");
+ xlog("L_DEBUG", "$ci|local|from $fu\n");
+ xlog("L_DEBUG", "$ci|local|to $tu\n");
+
+ #!ifdef SIP_TRACE_ROLE
+ route(SIP_TRACE);
+ #!endif
+
+ #!ifdef PRESENCE_ROLE
+ route(PRESENCE_LOCAL_REQUEST);
+ #!endif
+
}
-#!endif
+
+event_route[evrexec:DEFERRED_INIT]
+{
+ xlog("L_INFO", "processing deferred init\n");
+
+ #!ifdef PRESENCE_ROLE
+ route(PRESENCE_DEFERRED_INIT);
+ #!endif
+
+ #!import_file "custom-init.cfg"
+
+}
+
+route[LOCAL_REQUEST]
+{
+ if(src_ip != myself || $hdr(X-TM-Local) == $null) {
+ return;
+ }
+
+ xlog("L_DEBUG", "internal route $hdr(X-TM-Local)\n");
+
+ setflag(FLAG_LOCAL_ROUTE);
+
+ #!ifdef SIP_TRACE_ROLE
+ route(SIP_TRACE);
+ #!endif
+
+ $var(LocalRoute) = $hdr(X-TM-Local);
+ remove_hf_re("^X-TM-Local");
+ route_if_exists("$var(LocalRoute)");
+ exit;
+}
+
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
diff --git a/kamailio/defs-amqp.cfg b/kamailio/defs-amqp.cfg
new file mode 100644
index 0000000..fa116c9
--- /dev/null
+++ b/kamailio/defs-amqp.cfg
@@ -0,0 +1,88 @@
+## NOTE: DO NOT CHANGE THIS FILE, EDIT local.cfg ##
+
+
+####### amqp defs ########
+#!ifndef AMQP_DEFAULTS_INCLUDED
+#!define AMQP_DEFAULTS_INCLUDED
+
+#!trydef MY_AMQP_MAX_CHANNELS 25
+#!trydef MY_AMQP_CONSUMER_PROCESSES 4
+#!trydef MY_AMQP_CONSUMER_WORKERS 16
+#!trydef MY_AMQP_HEARTBEATS 5
+
+#!ifndef MY_AMQP_ZONE
+#!substdef "!MY_AMQP_ZONE!local!g"
+#!endif
+
+#!ifdef PRESENCE_ROLE
+#!trydef MY_AMQP_PUA_MODE 1
+#!else
+#!trydef MY_AMQP_PUA_MODE 0
+#!endif
+
+#!ifndef MY_AMQP_URL
+#!ifdef AMQP_URL1
+#!substdef "!MY_AMQP_URL!$def(AMQP_URL1)!g"
+#!else
+#!substdef "!MY_AMQP_URL!amqp://guest:guest@127.0.0.1:5672!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_SECONDARY_URL
+#!ifdef AMQP_URL2
+#!substdef "!MY_AMQP_SECONDARY_URL!$def(AMQP_URL2)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_TERTIARY_URL
+#!ifdef AMQP_URL3
+#!substdef "!MY_AMQP_TERTIARY_URL!$def(AMQP_URL3)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_QUATERNARY_URL
+#!ifdef AMQP_URL4
+#!substdef "!MY_AMQP_QUATERNARY_URL!$def(AMQP_URL4)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_QUINARY_URL
+#!ifdef AMQP_URL5
+#!substdef "!MY_AMQP_QUINARY_URL!$def(AMQP_URL5)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_SENARY_URL
+#!ifdef AMQP_URL6
+#!substdef "!MY_AMQP_SENARY_URL!$def(AMQP_URL6)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_SEPTENARY_URL
+#!ifdef AMQP_URL7
+#!substdef "!MY_AMQP_SEPTENARY_URL!$def(AMQP_URL7)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_OCTONARY_URL
+#!ifdef AMQP_URL8
+#!substdef "!MY_AMQP_OCTONARY_URL!$def(AMQP_URL8)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_NONARY_URL
+#!ifdef AMQP_URL9
+#!substdef "!MY_AMQP_NONARY_URL!$def(AMQP_URL9)!g"
+#!endif
+#!endif
+
+#!ifndef MY_AMQP_DENARY_URL
+#!ifdef AMQP_URL10
+#!substdef "!MY_AMQP_DENARY_URL!$def(AMQP_URL10)!g"
+#!endif
+#!endif
+
+
+#!endif
+
+# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
diff --git a/kamailio/defs.cfg b/kamailio/defs.cfg
index 2cb4cc7..753828b 100644
--- a/kamailio/defs.cfg
+++ b/kamailio/defs.cfg
@@ -2,125 +2,69 @@
####### defs ########
+#!ifndef DEFAULTS_INCLUDED
+#!define DEFAULTS_INCLUDED
-#!ifndef KAZOO_LOG_LEVEL
-#!define KAZOO_LOG_LEVEL L_INFO
+#!ifndef MY_HOSTNAME
+#!substdef "!MY_HOSTNAME!$HN(f)!g"
#!endif
-#!ifndef KAMAILIO_DBMS
-#!substdef "!KAMAILIO_DBMS!kazoo!g"
-#!endif
-
-#!ifndef KAZOO_DATA_DIR
-#!substdef "!KAZOO_DATA_DIR!/etc/kazoo/kamailio/db!g"
-#!endif
-
-#!ifndef KAZOO_DB_URL
-#!substdef "!KAZOO_DB_URL!kazoo:///KAZOO_DATA_DIR/kazoo.db!g"
-#!endif
-
-#!ifndef MAX_WHILE_LOOPS
-#!substdef "!MAX_WHILE_LOOPS!500!g"
-#!endif
-
-#!ifndef CHILDREN
-#!define CHILDREN 25
-#!endif
-
-#!ifndef TCP_CHILDREN
-#!define TCP_CHILDREN 25
+#!ifndef MY_IP_ADDRESS
+#!ifdef MY_LOCAL_IP
+#!substdef "!MY_IP_ADDRESS!$def(MY_LOCAL_IP)!g"
+#!else
+#!substdef "!MY_IP_ADDRESS!$HN(i)!g"
#!endif
-
-#!ifndef OPENBTS_AUTH_SECRET
-#!substdef "!OPENBTS_AUTH_SECRET!b3a54fa8317c7d9cb1d89d8970947b30eda273124d97fc3a079ccc98ecc2569b!g"
#!endif
-#!ifndef KZ_USE_DISPATCHER_LIST
-#!trydef KZ_USE_DISPATCHER_TABLE
+#!ifndef WEBSOCKET_NO_ORIGIN_RESTRICTION
+#!ifndef MY_WEBSOCKET_DOMAIN
+#!substdef "!MY_WEBSOCKET_DOMAIN!$HN(d)!g"
#!endif
-
-#!ifndef ANTIFLOOD_CACHE_PERIOD
-#!substdef "!ANTIFLOOD_CACHE_PERIOD!600!g"
#!endif
-#!ifndef MY_AMQP_MAX_CHANNELS
-#!define MY_AMQP_MAX_CHANNELS 25
-#!endif
+#!trydef KAZOO_LOG_LEVEL L_INFO
-#!ifndef MY_AMQP_CONSUMER_PROCESSES
-#!define MY_AMQP_CONSUMER_PROCESSES 4
-#!endif
+#!trydef PV_BUFFER_SIZE 16384
+#!trydef PV_BUFFER_SLOTS 30
-#!ifndef MY_AMQP_CONSUMER_WORKERS
-#!define MY_AMQP_CONSUMER_WORKERS 16
-#!endif
+#!trydef KZ_DB_MODULE kazoo
+#!substdef "!KAMAILIO_DBMS!$def(KZ_DB_MODULE)!g"
-#!ifndef MY_AMQP_HEARTBEATS
-#!define MY_AMQP_HEARTBEATS 5
+#!ifndef KAZOO_DATA_DIR
+#!substdef "!KAZOO_DATA_DIR!/etc/kazoo/kamailio/db!g"
#!endif
-#!ifndef BLF_USE_SINGLE_DIALOG
-#!define BLF_USE_SINGLE_DIALOG 1
+#!ifndef KAZOO_DB_URL
+#!substdef "!KAZOO_DB_URL!kazoo:///KAZOO_DATA_DIR/kazoo.db!g"
#!endif
-#!ifndef MY_AMQP_ZONE
-#!substdef "!MY_AMQP_ZONE!local!g"
+#!ifndef MAX_WHILE_LOOPS
+#!substdef "!MAX_WHILE_LOOPS!500!g"
#!endif
-#!ifndef DISPATCHER_ADD_SERVERS
-#!define DISPATCHER_ADD_SERVERS 1
-#!endif
+#### tcp parameters ##
+#!trydef CHILDREN 25
+#!trydef TCP_CHILDREN 25
-#!ifndef PRESENCE_RESET_BLF_DEFER_UPDATE
-#!define PRESENCE_RESET_BLF_DEFER_UPDATE 0
-#!endif
+#!trydef TCP_MAX_CONNECTIONS 4096
+#!trydef TCP_CONNECTION_LIFETIME 60
+#!trydef TCP_CONNECTION_TIMEOUT 5
+#!trydef TCP_KEEP_ALIVE yes
+#!trydef TCP_KEEP_COUNT 3
+#!trydef TCP_KEEP_IDLE 30
+#!trydef TCP_KEEP_INTERVAL 5
+#!trydef TCP_SEND_TIMEOUT 3
-#!ifndef MY_AMQP_PUA_MODE
-#!ifdef PRESENCE_ROLE
-#!define MY_AMQP_PUA_MODE 1
-#!else
-#!define MY_AMQP_PUA_MODE 0
-#!endif
-#!endif
+#!include_file "defs-amqp.cfg"
#!ifndef MEDIA_SERVERS_HASH_SIZE
#!substdef "!MEDIA_SERVERS_HASH_SIZE!256!g"
#!endif
-#!ifndef KZ_PRESENCE_AMQP_PUBLISH
-#!define KZ_PRESENCE_AMQP_PUBLISH 0
-#!endif
-
-#!ifndef KZ_PRESENCE_REQUEST_RESUBSCRIBE_PROBE
-#!define KZ_PRESENCE_REQUEST_RESUBSCRIBE_PROBE 0
-#!endif
-
-#!ifndef KZ_PRESENCE_REQUEST_PROBE
-#!define KZ_PRESENCE_REQUEST_PROBE 1
-#!endif
-
-#!ifndef NAT_UAC_TEST_LEVEL
-#!substdef "!NAT_UAC_TEST_LEVEL!3!g"
-#!endif
-
-#################################
-## Defs related to SIP_TRACE_ROLE
-##
-#!ifdef SIP_TRACE_ROLE
-#!trydef KZ_TRACE 0
-#!trydef KZ_TRACE_INTERNAL 1
-#!trydef KZ_TRACE_EXTERNAL 1
-#!trydef KZ_TRACE_INTERNAL_INCOMING 1
-#!trydef KZ_TRACE_INTERNAL_OUTGOING 1
-#!trydef KZ_TRACE_EXTERNAL_INCOMING 1
-#!trydef KZ_TRACE_EXTERNAL_OUTGOING 1
-#!ifndef SIP_TRACE_URI
-#!substdef "!SIP_TRACE_URI!sip:127.0.0.1:9060!g"
-#!endif
-#!ifndef HEP_CAPTURE_ID
-#!substdef "!HEP_CAPTURE_ID!1!g"
-#!endif
-#!endif
+#!trydef RR_FULL_LR 1
+#!trydef RR_DOUBLE_RR 1
+#!trydef RR_FORCE_SOCKET 1
#!ifndef KZ_DISABLE_WEBSOCKETS_REGISTRAR_PORT
#!trydef KZ_WEBSOCKETS_REGISTRAR_PORT 7000
@@ -130,7 +74,9 @@
#!trydef KZ_TLS_REGISTRAR_PORT 7000
#!endif
-#!trydef KZ_FAST_PICKUP_COOKIES 1
-#!trydef KZ_FAST_PICKUP_REALTIME 1
+#!trydef KZ_MULTI_HOMED 0
+
+
+#!endif
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
diff --git a/kamailio/dispatcher-role.cfg b/kamailio/dispatcher-role.cfg
index 24b26cc..46bd6b4 100644
--- a/kamailio/dispatcher-role.cfg
+++ b/kamailio/dispatcher-role.cfg
@@ -1,7 +1,31 @@
######## Generic Hash Table container in shared memory ########
modparam("htable", "htable", "failover=>size=16;autoexpire=120")
+#!trydef KZ_DISPATCHER_PROBE_MODE 1
+#!trydef DISPATCHER_ADD_SERVERS 1
+#!trydef DISPATCHER_ADD_SECONDARY_IP 1
+#!trydef DISPATCHER_SECONDARY_IP_GROUP 3
+#!trydef DISPATCHER_ALG 0
+#!trydef KZ_DISPATCHER_ADD_FLAGS 10
+#!trydef KZ_DISPATCHER_PRIMARY_GROUP 1
+#!trydef KZ_DISPATCHER_SECONDARY_GROUP 2
+#!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3
+#!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51
+#!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52
+#!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53
+#!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54
+#!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10
+#!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11
+#!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20
+#!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21
+
kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr"
+kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr"
+kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr"
+
+kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use"
+kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group"
+kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group"
####### Dispatcher module ########
loadmodule "dispatcher.so"
@@ -18,7 +42,7 @@ modparam("dispatcher", "setid_pvname", "$var(setid)")
modparam("dispatcher", "ds_ping_method", "OPTIONS")
modparam("dispatcher", "ds_ping_interval", 10)
modparam("dispatcher", "ds_probing_threshold", 3)
-modparam("dispatcher", "ds_probing_mode", 1)
+modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE)
modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200")
modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME")
@@ -31,25 +55,34 @@ modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME")
## 10 - Presence servers (if not locally handled)
## 20 - Registrar servers (if not locally handled)
+
+modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;")
+modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD")
+
####### Dispatcher Logic ########
route[DISPATCHER_CLASSIFY_SOURCE]
{
#!import_file "dispatcher-network-classify.cfg"
-
+
if (is_myself("$ou")) {
- xlog("L_INFO", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n");
+ xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n");
} else if (
- ds_is_from_list(1, 3) ||
- ds_is_from_list(2, 3) ||
- ds_is_from_list(3, 3) ||
- ds_is_from_list(10, 3) ||
- ds_is_from_list(20, 3)
+ ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, 3) ||
+ ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, 3)
) {
- xlog("L_INFO", "$ci|log|originated from internal sources\n");
-
+ xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n");
setflag(FLAG_INTERNALLY_SOURCED);
} else {
- xlog("L_INFO", "$ci|log|originated from external sources\n");
+ xlog("$var(log_request_level)", "$ci|log|originated from external sources\n");
}
}
@@ -62,34 +95,36 @@ route[DISPATCHER_FIND_ROUTES]
return;
}
- $var(ds_primary_group) = 1;
- $var(ds_backup_group) = 2;
-
+ $var(ds_primary_group) = $sel(cfg_get.kazoo.dispatcher_primary_group);
+ $var(ds_backup_group) = $sel(cfg_get.kazoo.dispatcher_secondary_group);
+
#!ifndef PRESENCE_ROLE
if (is_method("SUBSCRIBE")) {
- $var(ds_primary_group) = 10;
- $var(ds_backup_group) = 11;
+ $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP;
+ $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP;
+ add_path();
}
#!endif
#!ifndef REGISTRAR_ROLE
if (is_method("REGISTER")) {
- $var(ds_primary_group) = 20;
- $var(ds_backup_group) = 21;
+ $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP;
+ $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP;
+ add_path();
}
#!endif
- #!ifdef FAST_PICKUP_ROLE
- route(FAST_PICKUP_ATTEMPT);
+ #!ifdef PRESENCE_ROLE
+ route(PRESENCE_FAST_PICKUP_ATTEMPT);
#!endif
#!import_file "dispatcher-network-find.cfg"
$var(ds_group) = $var(ds_primary_group);
- if (!ds_select_dst("$var(ds_primary_group)", "0") || $(avp(ds_dst)[0]) == $null) {
+ if (!ds_select_dst("$var(ds_primary_group)", "$sel(cfg_get.kazoo.dispatcher_algorithm)") || $(avp(ds_dst)[0]) == $null) {
# we selected from primary group, try again in backup group
- if (!ds_select_dst("$var(ds_backup_group)", "0") || $(avp(ds_dst)[0]) == $null) {
+ if (!ds_select_dst("$var(ds_backup_group)", "$sel(cfg_get.kazoo.dispatcher_algorithm)") || $(avp(ds_dst)[0]) == $null) {
xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n");
sl_send_reply("480", "All servers busy");
exit;
@@ -111,7 +146,7 @@ route[DISPATCHER_FIND_ROUTES]
$var(prefered_route) = $sht(associations=>$var(user_source));
xlog("L_INFO", "$ci|log|found association for contact uri $var(user_source)\n");
if (!route(DISPATCHER_REORDER_ROUTES)) {
- $sht(associations=>$var(association)) = $null;
+ $sht(associations=>$var(user_source)) = $null;
}
}
}
@@ -198,12 +233,8 @@ route[DISPATCHER_NEXT_ROUTE]
# reset the final reply timer
$avp(final_reply_timer) = 3;
- t_on_reply("INTERNAL_REPLY");
-
- t_on_failure("INTERNAL_FAULT");
-
# relay the request to the new media server
- route(EXTERNAL_TO_INTERNAL_RELAY);
+ route(RELAY);
exit();
}
@@ -211,28 +242,57 @@ route[DISPATCHER_NEXT_ROUTE]
event_route[dispatcher:dst-down]
{
- xlog("L_ERR", "Destination down: $ru\n");
+ xlog("L_WARNING", "Destination down: $ru\n");
}
event_route[dispatcher:dst-up]
{
- xlog("L_WARNING", "Destination up: $ru\n");
+ xlog("L_NOTICE", "Destination up: $ru\n");
}
route[DISPATCHER_CHECK_MEDIA_SERVER]
{
- if(@cfg_get.kazoo.dispatcher_auto_add == 1) {
+ $var(check_media_server_ret) = 0;
+ if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) {
$var(SetId) = 1;
if($var(Zone) != "MY_AMQP_ZONE") {
$var(SetId) = 2;
}
+ $var(flags) = KZ_DISPATCHER_ADD_FLAGS;
+ $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);idx=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName));
+ #!import_file "dispatcher-custom-media-check.cfg"
sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT");
if($sqlrows(exec) > 0) {
- xlog("L_WARNING", "reloading dispatcher table\n");
- ds_reload();
+ $shv(dispatcher_reload) = 1;
+ $var(check_media_server_ret) = 1;
+ }
+
+ if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) {
+ if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) {
+ $var(MediaUrlBack) = $var(MediaUrl);
+ $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port}));
+ $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group);
+ sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT");
+ if($sqlrows(exec) > 0) {
+ $shv(dispatcher_reload) = 1;
+ $var(check_media_server_ret) = 1;
+ }
+ $var(MediaUrl) = $var(MediaUrlBack);
+ }
}
+
}
+ return $var(check_media_server_ret);
+}
+
+route[DISPATCHER_RELOAD]
+{
+ if($shv(dispatcher_reload) == 1) {
+ xlog("L_NOTICE", "reloading dispatcher table\n");
+ ds_reload();
+ };
+ $shv(dispatcher_reload) = 0;
}
route[DISPATCHER_STATUS]
diff --git a/kamailio/kamailio.cfg b/kamailio/kamailio.cfg
index 2528128..e515b9b 100644
--- a/kamailio/kamailio.cfg
+++ b/kamailio/kamailio.cfg
@@ -10,6 +10,7 @@
#!define L_NOTICE 1
#!define L_INFO 2
#!define L_DBG 3
+#!define L_DEBUG 4
#!define AVP_RECV_PARAM "recv_param"
#!define AVP_LOG_LEVEL "log_level"
@@ -23,15 +24,26 @@
#!define FLB_UAC_REDIRECT 3
#!define TRUSTED_ADR_GROUP 1
+################
+# Kamailio modules to help substdef setup
+# these need to go before local.cfg
+# so they can be used
+#
+# ipops - ip , domain, hostname
+# pv - $def(existing definition)
+#
+#
+################
+loadmodule "ipops.so"
+loadmodule "pv.so"
+
+
####### Local Configuration ########
include_file "local.cfg"
####### defaults not configured in local ########
include_file "defs.cfg"
-####### DBMS query selection ########
-include_file "db_queries_KAMAILIO_DBMS.cfg"
-
####### Default Configuration ######
include_file "default.cfg"
diff --git a/kamailio/kazoo-bindings.cfg b/kamailio/kazoo-bindings.cfg
index c4c520f..d63bcf7 100644
--- a/kamailio/kazoo-bindings.cfg
+++ b/kamailio/kazoo-bindings.cfg
@@ -1,21 +1,49 @@
######## kazoo bindings ########
-### use this simple form of binding a listener
-### kazoo_subscribe("dialoginfo", "direct", "BLF-QUEUE-MY_HOSTNAME", "BLF-MY_HOSTNAME");
-###
-### or unleash the power of rabbit to kazoo-blf
-###
-### 'no_ack' : 1 => needs ack,
-### 'wait_for_consumer_ack'
-### : 1 => when it receives, it processses on the AMQP Worker ad after that it confirms
-### : 0 => when it receives, it acks then processes in the AMQP Worker
-### only works if no_ack : 0
-###
-### Rabbit Policy for ha-mode
-### pattern : ^BLF
-### definition : ha-mode: all
###
###
+####### Kazoo Integration module ##########
+loadmodule "kazoo.so"
+modparam("kazoo", "pua_mode", MY_AMQP_PUA_MODE)
+modparam("kazoo", "amqp_primary_zone", "MY_AMQP_ZONE")
+modparam("kazoo", "amqp_query_timeout_avp", "$avp(kz_timeout)")
+modparam("kazoo", "node_hostname", "MY_HOSTNAME")
+modparam("kazoo", "amqp_heartbeats", MY_AMQP_HEARTBEATS)
+modparam("kazoo", "amqp_max_channels", MY_AMQP_MAX_CHANNELS)
+modparam("kazoo", "amqp_consumer_processes", MY_AMQP_CONSUMER_PROCESSES)
+modparam("kazoo", "amqp_consumer_workers", MY_AMQP_CONSUMER_WORKERS)
+## amqp connections
+#!ifdef MY_AMQP_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_URL")
+#!endif
+#!ifdef MY_AMQP_SECONDARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_SECONDARY_URL")
+#!endif
+#!ifdef MY_AMQP_TERTIARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_TERTIARY_URL")
+#!endif
+#!ifdef MY_AMQP_QUATERNARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_QUATERNARY_URL")
+#!endif
+#!ifdef MY_AMQP_QUINARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_QUINARY_URL")
+#!endif
+#!ifdef MY_AMQP_SENARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_SENARY_URL")
+#!endif
+#!ifdef MY_AMQP_SEPTENARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_SEPTENARY_URL")
+#!endif
+#!ifdef MY_AMQP_OCTONARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_OCTONARY_URL")
+#!endif
+#!ifdef MY_AMQP_NONARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_NONARY_URL")
+#!endif
+#!ifdef MY_AMQP_DENARY_URL
+modparam("kazoo", "amqp_connection", "MY_AMQP_DENARY_URL")
+#!endif
+
event_route[kazoo:mod-init]
{
@@ -36,8 +64,7 @@ event_route[kazoo:mod-init]
#!endif
#!ifdef ACL_ROLE
- $var(payload) = "{ 'exchange' : 'frontier_acl' , 'type' : 'topic', 'queue' : 'FRONTIERACL-FLUSH-MY_HOSTNAME', 'routing' : 'flush' }";
- kazoo_subscribe("$var(payload)");
+ route(ACL_BINDINGS);
#!endif
#!import_file "kazoo-custom-bindings.cfg"
@@ -46,17 +73,81 @@ event_route[kazoo:mod-init]
event_route[kazoo:consumer-event]
{
- xlog("L_INFO","unhandled AMQP event, payload: $kzE\n");
+ xlog("L_DEBUG","unhandled AMQP event, payload: $kzE\n");
}
event_route[kazoo:consumer-event-connection-open]
{
- xlog("L_INFO","connection to $(kzE{kz.json,host}) opened\n");
+ xlog("L_DEBUG","connection to $(kzE{kz.json,host}) opened\n");
+}
+
+event_route[kazoo:consumer-event-connection-error]
+{
+ xlog("L_ERR","amqp|error|$(kzE{kz.json,zone})|$(kzE{kz.json,name})|$(kzE{kz.json,message})\n");
+}
+
+event_route[kazoo:consumer-event-connection-message]
+{
+ xlog("L_DEBUG","amqp|msg|$(kzE{kz.json,zone})|$(kzE{kz.json,name})|$(kzE{kz.json,message})\n");
}
event_route[kazoo:consumer-event-connection-closed]
{
- xlog("L_INFO","connection to $(kzE{kz.json,host}) closed\n");
+ xlog("L_DEBUG","amqp|closed|$(kzE{kz.json,zone})|$(kzE{kz.json,name})|connection to $(kzE{kz.json,host}) closed\n");
+}
+
+event_route[kazoo:consumer-event-connection-zone-available]
+{
+ xlog("L_DEBUG","amqp zone $(kzE{kz.json,zone}) is available\n");
+}
+
+event_route[kazoo:consumer-event-connection-zone-unavailable]
+{
+ xlog("L_DEBUG","amqp zone $(kzE{kz.json,zone}) is unavailable\n");
+}
+
+event_route[kazoo:consumer-event-connection-available]
+{
+ xlog("L_DEBUG","amqp zone $(kzE{kz.json,zone}) is available\n");
+}
+
+event_route[kazoo:consumer-event-connection-unavailable]
+{
+ xlog("L_DEBUG","amqp zone $(kzE{kz.json,zone}) is unavailable\n");
+}
+
+event_route[kazoo:consumer-event-connection-zone-listener-available]
+{
+ xlog("L_DEBUG","amqp zone $(kzE{kz.json,zone}) is available\n");
+}
+
+event_route[kazoo:consumer-event-connection-zone-listener-unavailable]
+{
+ xlog("L_DEBUG","amqp zone $(kzE{kz.json,zone}) is unavailable\n");
+}
+
+event_route[kazoo:consumer-event-connection-listener-zone-available]
+{
+ xlog("L_NOTICE","amqp|connection|$(kzE{kz.json,zone})|$(kzE{kz.json,name})|listener available\n");
+}
+
+event_route[kazoo:consumer-event-connection-listener-zone-unavailable]
+{
+ xlog("L_WARN","amqp|connection|$(kzE{kz.json,zone})|$(kzE{kz.json,name})|listener unavailable\n");
+
+ #!ifdef PRESENCE_ROLE
+ route(PRESENCE_ZONE_UNAVAILABLE);
+ #!endif
+}
+
+event_route[kazoo:consumer-event-connection-listener-available]
+{
+ xlog("L_DEBUG","amqp|connection|$(kzE{kz.json,zone})|$(kzE{kz.json,name})|listener available\n");
+}
+
+event_route[kazoo:consumer-event-connection-listener-unavailable]
+{
+ xlog("L_DEBUG","amqp zone $(kzE{kz.json,zone}) is unavailable\n");
}
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
diff --git a/kamailio/keepalive-role.cfg b/kamailio/keepalive-role.cfg
new file mode 100644
index 0000000..b7d28e1
--- /dev/null
+++ b/kamailio/keepalive-role.cfg
@@ -0,0 +1,343 @@
+######## KEEPALIVE PINGING ########
+
+#!trydef KEEPALIVE_ENABLED 1
+#!trydef KEEPALIVE_NAT_ONLY 0
+#!trydef KEEPALIVE_UDP_ONLY 0
+#!trydef KEEPALIVE_TIMERS 4
+#!trydef KEEPALIVE_INTERVAL 60
+#!trydef KEEPALIVE_TIMEOUT 5000
+#!trydef KEEPALIVE_FAILED_THRESHOLD 2
+#!trydef KEEPALIVE_EXPIRE_SUBSCRIPTIONS 1
+#!trydef KEEPALIVE_EXPIRE_REGISTRATIONS 1
+#!trydef KEEPALIVE_FAILED_ACTION 1
+#!trydef KEEPALIVE_FAILED_LOG_LEVEL 0
+#!trydef KEEPALIVE_EXPIRED_SUBSCRIPTION_ACTION 1
+#!trydef KEEPALIVE_EXPIRED_REGISTRATION_ACTION 1
+#!trydef KEEPALIVE_ON_SUBSCRIPTION_ACTION 1
+#!trydef KEEPALIVE_ON_REGISTRATION_ACTION 1
+
+#!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"
+kazoo.keepalive_timeout = KEEPALIVE_TIMEOUT descr "timeout in ms for keepalive transaction"
+kazoo.keepalive_failed_threshold = KEEPALIVE_FAILED_THRESHOLD descr "how many times can a device fail to respond to OPTIONS"
+kazoo.keepalive_expire_subscriptions = KEEPALIVE_EXPIRE_SUBSCRIPTIONS descr "expires subscriptions that do not respond to OPTIONS"
+kazoo.keepalive_expire_registrations = KEEPALIVE_EXPIRE_REGISTRATIONS descr "expires registrations that do not respond to OPTIONS"
+kazoo.keepalive_failed_log_level = KEEPALIVE_FAILED_LOG_LEVEL descr "loglevel for keepalive failed reply"
+kazoo.keepalive_failed_action = KEEPALIVE_FAILED_ACTION descr "action for devices that exceed the threshold. 1 = disable, 2 = delete"
+kazoo.keepalive_interval = KEEPALIVE_INTERVAL descr "interval in seconds between attempts to send OPTIONS to device"
+kazoo.keepalive_expired_registration_action = KEEPALIVE_EXPIRED_REGISTRATION_ACTION descr "action when registrar expires a registration, 1 = delete , 2 = disable, 0 = none"
+kazoo.keepalive_expired_subscription_action = KEEPALIVE_EXPIRED_SUBSCRIPTION_ACTION descr "action when presence expires a subscription, 1 = delete , 2 = disable, 0 = none"
+kazoo.keepalive_on_registration_action = KEEPALIVE_ON_REGISTRATION_ACTION descr "action on registration, 1 = insert in keepalive , 0 = none"
+kazoo.keepalive_on_subscription_action = KEEPALIVE_ON_SUBSCRIPTION_ACTION descr "action on subscription, 1 = insert in keepalive , 0 = none"
+kazoo.keepalive_enable = KEEPALIVE_ENABLED descr "enable keepalive, 1 = on , 0 = off"
+
+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=1;mode=1;")
+modparam("rtimer", "exec", "timer=keepalive_db_timer;route=KEEPALIVE_DB_TIMER")
+
+##modparam("rtimer", "timer", "name=keepalive_cleanup;interval=5;mode=1;")
+##modparam("rtimer", "exec", "timer=keepalive_cleanup;route=KEEPALIVE_CLEANUP")
+
+modparam("mqueue","mqueue", "name=keepalive_db_queue")
+
+modparam("statistics","variable", "keepalive:success")
+modparam("statistics","variable", "keepalive:failure")
+modparam("statistics","variable", "keepalive:db:success")
+modparam("statistics","variable", "keepalive:db:failure")
+modparam("statistics","variable", "keepalive:client_options")
+modparam("statistics","variable", "keepalive:client_notify")
+modparam("statistics","variable", "keepalive:disabled")
+modparam("statistics","variable", "keepalive:removed")
+modparam("statistics","variable", "keepalive:expired_registrations")
+modparam("statistics","variable", "keepalive:expired_subscriptions")
+
+modparam("statistics","variable", "keepalive:from_registration")
+modparam("statistics","variable", "keepalive:from_subscription")
+
+modparam("statistics","variable", "keepalive:removed_from_registration")
+modparam("statistics","variable", "keepalive:removed_from_subscription")
+
+modparam("statistics","variable", "keepalive:disabled_from_expired_registration")
+modparam("statistics","variable", "keepalive:removed_from_expired_registration")
+
+modparam("statistics","variable", "keepalive:disabled_from_expired_subscription")
+modparam("statistics","variable", "keepalive:removed_from_expired_subscription")
+
+modparam("htable", "htable", "keepalive=>size=32;")
+
+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 : $var(ci) => $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(stat_update) = $_s(+$sqlrows(cb));
+ update_stat("$var(ci)", "$var(stat_update)");
+
+ $var(nrows) = $sqlrows(cb);
+ xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows) => $var(stat_update)\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]
+{
+ if($sel(cfg_get.kazoo.keepalive_enable) == 0) return;
+
+ $var(Query) = $_s(UPDATE keepalive SET SELECTED = 9 WHERE slot = $var(slot) AND selected = 0 and failed > $sel(cfg_get.kazoo.keepalive_failed_threshold));
+# $var(Query) = $_s(UPDATE keepalive SET SELECTED = 9 where selected < 3 and failed > $sel(cfg_get.kazoo.keepalive_failed_threshold));
+ sql_query("cb", "$var(Query)");
+
+ if($sqlrows(cb) > 0) {
+
+ if($sel(cfg_get.kazoo.keepalive_expire_registrations) == 1) {
+ if($def(REGISTRAR_DB_MODE) == 3) {
+ $var(Query) = $_s(update location set expires = last_modified where id in(select b.id from w_keepalive_contact a inner join w_location_contact b on a.contact = b.contact where selected = 9));
+ sql_query("cb", "$var(Query)");
+ $var(stat_update) = $_s(+$sqlrows(cb));
+ update_stat("keepalive:expired_registrations", "$var(stat_update)");
+ } else {
+ $var(Query) = $_s(update location set expires = last_modified where id in(select b.id from w_keepalive_contact a inner join w_location_contact b on a.contact = b.contact where selected = 9));
+ sql_query("cb", "$var(Query)");
+ $var(stat_update) = $_s(+$sqlrows(cb));
+ update_stat("keepalive:expired_registrations", "$var(stat_update)");
+ }
+ }
+
+ if($sel(cfg_get.kazoo.keepalive_expire_subscriptions) == 1) {
+ $var(Query) = $_s(DELETE FROM active_watchers where id in(select b.id from w_keepalive_contact a inner join w_watchers_contact b on a.contact = b.contact where selected = 9));
+ sql_query("cb", "$var(Query)");
+ $var(stat_update) = $_s(+$sqlrows(cb));
+ update_stat("keepalive:expired_subscriptions", "$var(stat_update)");
+ }
+
+ if($sel(cfg_get.kazoo.keepalive_failed_action) == 2) {
+ ## disable
+ $var(Query) = $_s(UPDATE keepalive SET SELECTED = 10 where selected = 9);
+ $var(stat) = "keepalive:disabled";
+ } else if($sel(cfg_get.kazoo.keepalive_failed_action) == 1) {
+ ## delete - will be recreated on registration/subscription with same contact
+ $var(Query) = $_s(DELETE FROM keepalive where selected = 9);
+ $var(stat) = "keepalive:removed";
+ }
+ sql_query("cb", "$var(Query)");
+ $var(stat_update) = $_s(+$sqlrows(cb));
+ update_stat("$var(stat)", "$var(stat_update)");
+ }
+}
+
+route[KEEPALIVE_TIMER]
+{
+ if($sel(cfg_get.kazoo.keepalive_enable) == 0) return;
+
+ $var(base_slot) = $rtimer_worker * $sel(cfg_get.kazoo.keepalive_interval);
+ $var(slot) = $var(base_slot) + $var(tick);
+ $var(Query) = $_s(UPDATE keepalive SET selected = 1 WHERE slot = $var(slot) AND selected = 0 AND time_sent < datetime('now', '-$sel(cfg_get.kazoo.keepalive_interval) seconds'));
+## xlog("L_NOTICE", "SQLTIMER ($var(base_slot) + $var(tick))> $var(Query)\n");
+ $var(sqlres) = sql_query("cb", "$var(Query)");
+ if($var(sqlres) < 0) {
+ xlog("L_ERROR", "$rtimer_worker|$var(tick)|log|error running query : $var(Query)\n");
+ } else {
+ $var(nrows) = $sqlrows(cb);
+ xlog("L_DEBUG", "$rtimer_worker|$var(tick)|log|selected $var(nrows) endpoints to ping\n");
+ }
+
+ route(KEEPALIVE_CLEANUP);
+
+ $var(Query) = $_s(SELECT id, contact, sockinfo from keepalive WHERE slot = $var(slot) AND selected = 1);
+ xlog("L_DEBUG", "$rtimer_worker|$var(tick)|timer|SQL => $var(Query)\n");
+ $var(result) =sql_xquery("cb", "$var(Query)", "ra");
+
+ if($var(result) == 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 = $var(slot) AND selected = 1);
+ $var(sqlres) = sql_query("cb", "$var(Query)");
+ if($var(sqlres) < 0) {
+ xlog("L_ERROR", "$rtimer_worker|$var(tick)|log|error running query : $var(Query)\n");
+ }
+
+ $var(tick) = $var(tick) + 1;
+ if($var(tick) > $sel(cfg_get.kazoo.keepalive_interval)) {
+ $var(tick) = 0;
+ }
+
+}
+
+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}) AND SELECTED = 2);
+ xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE UPDATE SQL => '$var(Query)'\n");
+ mq_add("keepalive_db_queue", "keepalive:db:success", "$var(Query)");
+ update_stat("keepalive:success", "+1");
+ resetflag(FLAG_SIP_TRACE);
+}
+
+failure_route[KEEPALIVE_FAULT]
+{
+ xlog("$(sel(cfg_get.kazoo.keepalive_failed_log_level){s.int})", "$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}) AND SELECTED = 2);
+ xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE REMOVE SQL => '$var(Query)'\n");
+ mq_add("keepalive_db_queue", "keepalive:db:failure", "$var(Query)");
+ update_stat("keepalive:failure", "+1");
+ resetflag(FLAG_SIP_TRACE);
+}
+
+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, $sel(cfg_get.kazoo.keepalive_timeout));
+
+ t_relay();
+}
+
+route[KEEPALIVE_ON_REGISTRATION]
+{
+ if($sel(cfg_get.kazoo.keepalive_enable) == 0) return;
+
+ if($sel(cfg_get.kazoo.keepalive_on_registration_action) == 0) {
+ return;
+ }
+
+ if($proto == "ws" || $proto == "wss") {
+ return;
+ }
+
+ if($sht(keepalive=>$si~$sp~$prid) != $null) {
+ 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");
+
+ if($var(save_result) == 3) {
+ $var(sql) = $_s(DELETE FROM keepalive WHERE contact = "$var(contact)");
+ $var(stat) = "keepalive:removed_from_registration";
+ } else {
+ $var(max_slots) = $sel(cfg_get.kazoo.keepalive_interval) * KEEPALIVE_S_TIMERS;
+ $var(slot) = $(var(contact){s.corehash, $var(max_slots)});
+ $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, received, sockinfo, slot) values("$var(contact)", "$var(alias)", "$(RAut{uri.tosocket})", $var(slot)));
+ $var(stat) = "keepalive:from_registration";
+ }
+ mq_add("keepalive_db_queue", "$var(stat)", "$var(sql)");
+
+ return;
+}
+
+route[KEEPALIVE_ON_SUBSCRIBE]
+{
+ if($sel(cfg_get.kazoo.keepalive_enable) == 0) return;
+
+ if($sel(cfg_get.kazoo.keepalive_on_subscription_action) == 0) {
+ return;
+ }
+
+ if($sht(keepalive=>$si~$sp~$prid) != $null) {
+ return;
+ }
+
+ $var(max_slots) = $sel(cfg_get.kazoo.keepalive_interval) * KEEPALIVE_S_TIMERS;
+ $var(slot) = $(subs(contact){s.corehash, $var(max_slots)});
+ $var(alias) = $(subs(contact){uri.param,alias});
+ $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, received, sockinfo, slot) values("$subs(contact)", "$var(alias)", "$subs(sockinfo)", $var(slot)));
+ mq_add("keepalive_db_queue", "keepalive:from_subscription", "$var(sql)");
+
+}
+
+route[KEEPALIVE_ON_EXPIRED_REGISTRATION]
+{
+ if($sel(cfg_get.kazoo.keepalive_enable) == 0) return;
+
+ if($sel(cfg_get.kazoo.keepalive_expired_registration_action) == 2) {
+ ## disable
+ $var(Query) = $_s(UPDATE keepalive SET SELECTED = 10 where selected < 3 and contact like "$ulc(exp=>addr)%");
+ mq_add("keepalive_db_queue", "keepalive:disabled_from_expired_registration", "$var(Query)");
+ } else if($sel(cfg_get.kazoo.keepalive_expired_registration_action) == 1) {
+ ## delete - will be recreated on registration with same contact
+ $var(Query) = $_s(DELETE FROM keepalive where selected < 3 and contact like "$ulc(exp=>addr)%");
+ mq_add("keepalive_db_queue", "keepalive:removed_from_expired_registration", "$var(Query)");
+ }
+
+}
+
+route[KEEPALIVE_ON_OPTIONS]
+{
+ if($sel(cfg_get.kazoo.keepalive_enable) == 0) return;
+
+ if($shtinc(keepalive=>$si~$sp~$prid) == 1) {
+ $var(Query) = $_s(UPDATE keepalive set selected = 3 where received = "$si~$sp~$prid" and selected <> 3 );
+ mq_add("keepalive_db_queue", "keepalive:client_options", "$var(Query)");
+ }
+
+}
+
+route[KEEPALIVE_ON_NOTIFY]
+{
+ if($sel(cfg_get.kazoo.keepalive_enable) == 0) return;
+
+ if($shtinc(keepalive=>$si~$sp~$prid) == 1) {
+ $var(Query) = $_s(UPDATE keepalive set selected = 4 where received = "$si~$sp~$prid" and selected <> 4 );
+ mq_add("keepalive_db_queue", "keepalive:client_notify", "$var(Query)");
+ }
+
+}
diff --git a/kamailio/local.cfg b/kamailio/local.cfg
index 36b0363..5cb844d 100644
--- a/kamailio/local.cfg
+++ b/kamailio/local.cfg
@@ -8,8 +8,6 @@
#!trydef PRESENCE_ROLE
#!trydef RESPONDER_ROLE
#!trydef NODES_ROLE
-#!trydef FAST_PICKUP_ROLE
-#!trydef PRESENCE_QUERY_ROLE
## Disabled Roles - remove all but the last '#' to enable
# # #!trydef TRAFFIC_FILTER_ROLE
@@ -27,26 +25,38 @@
################################################################################
## SERVER INFORMATION
################################################################################
-## CHANGE "kamailio.2600hz.com" TO YOUR SERVERS HOSTNAME
-#!substdef "!MY_HOSTNAME!kamailio.2600hz.com!g"
+## UNCOMMENT & CHANGE "kamailio.2600hz.com" TO YOUR SERVERS HOSTNAME
+# # #!substdef "!MY_HOSTNAME!kamailio.2600hz.com!g"
-## CHANGE "127.0.0.1" TO YOUR SERVERS IP ADDRESS
+## UNCOMMENT & CHANGE "127.0.0.1" TO YOUR SERVERS IP ADDRESS
## Usually your public IP. If you need
## to listen on addtional ports or IPs
## add them in "BINDINGS" at the bottom.
-#!substdef "!MY_IP_ADDRESS!0.0.0.0!g"
+# # #!substdef "!MY_IP_ADDRESS!127.0.0.1!g"
## CHANGE "kazoo://guest:guest@127.0.0.1:5672" TO THE AMQP URL
## This should be the primary RabbitMQ server
## in the zone that this server will service.
-#!substdef "!MY_AMQP_URL!kazoo://guest:guest@127.0.0.1:5672!g"
+# # #!substdef "!MY_AMQP_URL!amqp://guest:guest@127.0.0.1:5672!g"
-## This parameter is only required if you are using websockets
+################################################################################
+## WEBSOCKETS
+################################################################################
+##
+## These parameters are only required if you are using websockets
+##
+## MY_WEBSOCKET_DOMAIN
## This value must be present in the HTTP
## Origin header on a new websocket request
-## or it will be rejected. If you remove
-## it completely the validation will be disabled.
-#!substdef "!MY_WEBSOCKET_DOMAIN!2600hz.com!g"
+## or it will be rejected. default value is
+## domain of this server.
+## #!substdef "!MY_WEBSOCKET_DOMAIN!2600hz.com!g"
+##
+## WEBSOCKET_NO_ORIGIN_RESTRICTION
+## if defined, it will disable the origin validation.
+##
+## #!trydef WEBSOCKET_NO_ORIGIN_RESTRICTION
+##
################################################################################
## DATABASE
@@ -75,13 +85,14 @@
## BINDINGS
################################################################################
## This parameter is OPTIONAL.
+## when set to 1,
## It will try to locate outbound interface
## on multihomed host. By default forward
## requests use the incoming socket disregarding
## the destination location. When enabled Kamailio
## will select a socket that can reach the
## destination. This reduces performance.
-mhomed=0
+##!define KZ_MULTI_HOMED 1
################################################################################
## KZ_DISABLE_REGISTRAR_PORTS
@@ -106,23 +117,16 @@ mhomed=0
##!define KZ_UDP_REGISTRAR_PORT 7000
##!define KZ_TCP_REGISTRAR_PORT 7000
-################################################################################
-## NAT
-################################################################################
-## These parameters are OPTIONAL.
-## It allows overriding the nat_uac_test with a different value than "3"
-## (default) as it is proven that it fixes the issue reported here:
-## https://lists.kamailio.org/pipermail/sr-users/2016-August/094211.html
-# # #!substdef "!NAT_UAC_TEST_LEVEL!1!g"
-
################################################################################
## SIP traffic mirroring to SIP_TRACE server
################################################################################
## This parameter is OPTIONAL.
## If you have installed SIP_TRACE server (Homer as example),
## then you can mirror INVITE and MESSAGE here
-# # #!substdef "!SIP_TRACE_URI!sip:127.0.0.1:9060!g"
-# # #!substdef "!HEP_CAPTURE_ID!1!g"
+# # #!define SIP_TRACE_URI "sip:127.0.0.1:9060"
+# # #!define HEP_CAPTURE_ID 1
+
+include_file "defs.cfg"
## YOU SHOULD NOT HAVE TO CHANGE THESE!
## By setting MY_IP_ADDRESS above these will resolve
diff --git a/kamailio/message-role.cfg b/kamailio/message-role.cfg
index a0fa312..1122a1e 100644
--- a/kamailio/message-role.cfg
+++ b/kamailio/message-role.cfg
@@ -40,7 +40,7 @@ route[MESSAGE_REPLY]
}
$var(Payload) = '{ "Event-Category" : "message", "Event-Name" : "delivery", "Call-ID" : "$(sht(msg=>$ci){kz.json,Call-ID})", "Message-ID" : "$(sht(msg=>$ci){kz.json,Message-ID})" , "Delivery-Result-Code" : "sip:$T_reply_code", "Msg-ID" : "$(sht(msg=>$ci){kz.json,Msg-ID})" , "Status" : "$var(Result)"}';
-
+
$var(RoutingKey) = $(sht(msg=>$ci){kz.json,Server-ID});
$var(exchange) = "targeted";
if($var(RoutingKey) == "") {
@@ -54,7 +54,7 @@ route[MESSAGE_REPLY]
route[MESSAGE_BINDINGS]
{
$var(key) = "kamailio@MY_HOSTNAME";
- $var(payload) = "{ 'exchange' : 'sms' , 'type' : 'topic', 'queue' : 'MSG-QUEUE-MY_HOSTNAME', 'routing' : 'message.route." + $(var(key){kz.encode}) + ".*', 'no_ack' : 0 }";
+ $var(payload) = $_s({"name": "sms", "exchange": "sms", "type": "topic", "queue": "MSG-QUEUE-MY_HOSTNAME", "routing": "message.route.$(var(key){kz.encode}).*", "no_ack": 0 });
kazoo_subscribe("$var(payload)");
}
diff --git a/kamailio/nat-traversal-role.cfg b/kamailio/nat-traversal-role.cfg
index 7166446..6d62690 100644
--- a/kamailio/nat-traversal-role.cfg
+++ b/kamailio/nat-traversal-role.cfg
@@ -1,45 +1,116 @@
######## NAT Traversal module - signaling functions ########
#!ifndef NATHELPER_LOADED
loadmodule "nathelper.so"
+#!trydef NATHELPER_LOADED
#!endif
modparam("nathelper", "received_avp", "$avp(AVP_RECV_PARAM)")
-modparam("nathelper", "sipping_from", "sip:sipcheck@MY_HOSTNAME")
+modparam("nathelper", "sipping_from", "sip:registrar@MY_HOSTNAME")
+
+#!ifdef WEBSOCKETS_ROLE
+#!trydef KZ_NAT_DETECT 83
+#!else
+#!trydef KZ_NAT_DETECT 19
+#!endif
+
+#!trydef KZ_NAT_FIX_SDP_REQUEST 1
+#!trydef KZ_NAT_FIX_SDP_REPLY 1
+#!trydef KZ_NAT_SDP_TEST 8
+#!trydef KZ_NAT_SDP_FIX 10
+
+
+kazoo.nat_fix_sdp_request = KZ_NAT_FIX_SDP_REQUEST descr "performs request sdp replacement of private addresses"
+kazoo.nat_fix_sdp_reply = KZ_NAT_FIX_SDP_REPLY descr "performs reply sdp replacement of private addresses"
####### NAT Traversal Logic ########
-route[NAT_TEST_AND_CORRECT]
+route[NAT_SDP]
+{
+ if( has_body("application/sdp")) {
+ if( nat_uac_test(KZ_NAT_SDP_TEST)) {
+ xlog("L_DEBUG", "$ci|log|applying sdp nat fix\n");
+ $var(ret) = fix_nated_sdp(KZ_NAT_SDP_FIX);
+ xlog("L_DEBUG", "$ci|log|result of applying sdp nat fix is $var(ret)\n");
+ } else if( is_method("INVITE") && !isflagset(FLAG_INTERNALLY_SOURCED) && is_audio_on_hold()) {
+ xlog("L_DEBUG", "$ci|log|applying sdp nat fix for held channel\n");
+ $var(ret) = fix_nated_sdp(KZ_NAT_SDP_FIX);
+ xlog("L_DEBUG", "$ci|log|result of applying sdp nat fix for held channel is $var(ret)\n");
+ }
+ }
+}
+
+route[NAT_DETECT]
+{
+
+ if($sel(cfg_get.kazoo.nat_fix_sdp_request) == 1) {
+ route(NAT_SDP);
+ }
+
+ if ($Rp == "5080") {
+ setflag(FLAG_SKIP_NAT_CORRECTION);
+ xlog("L_DEBUG", "$ci|log|skipping nat correction on PORT 5080\n");
+ } else {
+ if (is_present_hf("Record-Route")) {
+ $var(i) = 0;
+ $var(rr_count) = $rr_count;
+ while($var(i) < $var(rr_count)) {
+ $var(rr_base) = $(hdr(Record-Route)[$var(i)]);
+ $var(rr_idx) = 0;
+ $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,});
+ while($var(rr) != $null && $var(rr) != "") {
+ $var(i) = $var(i) + 1;
+ if (!is_myself("$(var(rr){nameaddr.uri})")) {
+ setflag(FLAG_SKIP_NAT_CORRECTION);
+ xlog("L_DEBUG", "$ci|log|skipping nat correction on record-route $(var(rr){nameaddr.uri})\n");
+ }
+ $var(rr_idx) = $var(rr_idx) + 1;
+ $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,});
+ }
+ }
+ }
+ }
+
+ if (isflagset(FLAG_SKIP_NAT_CORRECTION)) {
+ xlog("L_DEBUG", "$ci|log|skipping nat detection\n");
+ return;
+ }
+
+ force_rport();
+
+ if(nat_uac_test(KZ_NAT_DETECT)) {
+ xlog("L_DEBUG", "$ci|log|detected nat request\n");
+ setflag(FLT_NATS);
+ if (!is_method("REGISTER")) {
+ if(is_first_hop()) set_contact_alias();
+ }
+ }
+
+}
+
+route[NAT_MANAGE]
{
- if (is_present_hf("Record-Route")) {
- $var(i) = 0;
- $var(rr_count) = $rr_count;
- while($var(i) < $var(rr_count)) {
- $var(rr_base) = $(hdr(Record-Route)[$var(i)]);
- $var(rr_idx) = 0;
- $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,});
- while($var(rr) != $null && $var(rr) != "") {
- $var(i) = $var(i) + 1;
- if (!is_myself("$(var(rr){nameaddr.uri})")) {
- setflag(FLAG_SKIP_NAT_CORRECTION);
- }
- $var(rr_idx) = $var(rr_idx) + 1;
- $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,});
- }
- }
- } else if ($Rp == "5080") {
- setflag(FLAG_SKIP_NAT_CORRECTION);
- }
-
- if (isflagset(FLAG_SKIP_NAT_CORRECTION)) {
- return();
- }
-
- if (nat_uac_test("NAT_UAC_TEST_LEVEL")) {
- force_rport();
- fix_nated_contact();
- }
-
- if (has_body("application/sdp") && nat_uac_test("8")) {
- fix_nated_sdp("10");
- }
+ if( is_reply() && $sel(cfg_get.kazoo.nat_fix_sdp_reply) == 1) {
+ route(NAT_SDP);
+ }
+
+ if ( is_request() && isflagset(FLAG_INTERNALLY_SOURCED)) {
+ setbflag(FLB_NATB);
+ }
+
+ if ( is_request() && has_totag() ) {
+ setbflag(FLB_NATB);
+ }
+
+ if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))) {
+ return;
+ }
+
+ if (is_reply()) {
+ if(isflagset(FLT_NATS) || isbflagset(FLB_NATB)) {
+ if(is_first_hop()) {
+ set_contact_alias();
+ }
+ }
+ }
+
}
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
diff --git a/kamailio/nodes-role.cfg b/kamailio/nodes-role.cfg
index c3df110..cb985a2 100644
--- a/kamailio/nodes-role.cfg
+++ b/kamailio/nodes-role.cfg
@@ -1,21 +1,11 @@
######## Nodes role - pushes info to kazoo ########
-#!ifndef NODES_EXPIRE
-#!define NODES_EXPIRE 10
-#!endif
-
-#!ifndef NODES_FUDGE_FACTOR
-#!define NODES_FUDGE_FACTOR 10
-#!endif
+#!trydef NODES_EXPIRE 10
+#!trydef NODES_FUDGE_EXPIRE 45
modparam("htable", "htable", "nodes=>size=8;initval=0;autoexpire=60");
modparam("htable", "htable", "media=>size=8;initval=0;autoexpire=60");
-####### RTIMER module ##########
-#!ifndef RTIMER_LOADED
-loadmodule "rtimer.so"
-#!trydef RTIMER_LOADED
-#!endif
modparam("rtimer", "timer", "name=ta;interval=2;mode=2;")
modparam("rtimer", "timer", "name=retry;interval=5;mode=2;")
modparam("rtimer", "timer", "name=pub;interval=10;mode=1;")
@@ -61,24 +51,24 @@ route(LISTENER_STATUS);
#!endif
$var(Roles) = $_s("Roles" : {"Proxy" : $var(listeners) $var(Dispatcher) $var(Presence) $var(Registrar)});
- $var(Payload) = '{"Event-Category" : "nodes", "Event-Name" : "advertise", "Expires" : 15000, "Used-Memory" : $(stat(real_used_size){s.int}), "Startup" : $Tb, "WhApps" : {"kamailio" : {"Startup" : $Tb }}, $var(Roles)}';
+ $var(Payload) = $_s({"Event-Category" : "nodes", "Event-Name" : "advertise", "Expires" : 15000, "Used-Memory" : $(stat(real_used_size){s.int}), "Startup" : $Tb, "WhApps" : {"kamailio" : {"Startup" : $Tb }}, $var(Roles)});
kazoo_publish("nodes", "", $var(Payload));
}
event_route[kazoo:consumer-event-nodes-advertise]
{
- $var(count) = $shtinc(nodes=>$(kzE{kz.json,Node})::count);
+ $var(count) = $shtinc(nodes=>$(kzE{kz.json,Node})::count);
if($var(count) == 0) {
- xlog("L_WARNING", "$(kzE{kz.json,Msg-ID})|nodes|heartbeat for reconnected node $(kzE{kz.json,Node})\n");
+ xlog("L_NOTICE", "$(kzE{kz.json,Msg-ID})|nodes|heartbeat for reconnected node $(kzE{kz.json,Node})\n");
$var(count) = $shtinc(nodes=>$(kzE{kz.json,Node})::count);
} else {
if($var(count) == 1) {
- xlog("L_WARNING", "$(kzE{kz.json,Msg-ID})|nodes|heartbeat from new node $(kzE{kz.json,Node})\n");
+ xlog("L_NOTICE", "$(kzE{kz.json,Msg-ID})|nodes|heartbeat from new node $(kzE{kz.json,Node})\n");
} else {
xlog("L_DEBUG", "$(kzE{kz.json,Msg-ID})|nodes|heartbeat from existing node $(kzE{kz.json,Node})\n");
}
- }
+ }
mq_add("node_heartbeat", "$(kzE{kz.json,Node})", "$kzE");
}
@@ -115,11 +105,11 @@ route[NODE_HEARTBEAT_ROUTE]
xlog("L_DEBUG", "$(var(Payload){kz.json,Msg-ID})|nodes|processing heartbeat for node $var(Node)\n");
route(CHECK_MEDIA_SERVERS);
-
+
$sht(nodes=>$var(Node)) = $var(Payload);
- $shtex(nodes=>$var(Node)) = ($(var(Payload){kz.json,Expires}{s.int}) / 1000) + NODES_FUDGE_FACTOR;
+ $shtex(nodes=>$var(Node)) = ($(var(Payload){kz.json,Expires}{s.int}) / 1000) + NODES_FUDGE_EXPIRE;
$var(runloop) = $var(runloop) + 1;
- }
+ }
}
route[CHECK_MEDIA_SERVERS]
@@ -148,13 +138,22 @@ route[CHECK_MEDIA_SERVERS]
$var(MediaProfile) = $(avp(ProfileKeys)[$var(ProfileIdx)]);
$var(MediaRawUrl) = $(var(Payload){kz.json,Media-Servers.$var(MediaKey).Interfaces.$var(MediaProfile).URL});
$var(MediaUrl) = $(var(MediaRawUrl){re.subst,/^sip:(.*)@(.*)/sip:\2/});
+ $var(MediaInstanceUUID) = $(var(Payload){kz.json,Media-Servers.$var(MediaKey).Instance-UUID});
+ $var(MediaIP) = $(var(Payload){kz.json,Media-Servers.$var(MediaKey).Interfaces.$var(MediaProfile).SIP-IP});
if($shtinc(media=>$var(MediaUrl)::count) == 1) {
$sht(media=>$var(MediaUrl)::zone) = $var(Zone);
$shtex(media=>$var(MediaUrl)::zone) = 0;
+ $sht(media=>$var(MediaUrl)::uuid) = $var(MediaInstanceUUID);
+ $shtex(media=>$var(MediaUrl)::uuid) = 0;
route(MEDIA_SERVER_UP);
+ } else if($sht(media=>$var(MediaUrl)::uuid) != $var(MediaInstanceUUID)) {
+ $sht(media=>$var(MediaUrl)::uuid) = $var(MediaInstanceUUID);
+ $shtex(media=>$var(MediaUrl)::uuid) = 0;
+ $var(Zone) = $sht(media=>$var(MediaUrl)::zone);
+ route(MEDIA_SERVER_RESTART);
};
- $var(MediaExpire) = ($(var(Payload){kz.json,Expires}{s.int}) / 1000) + NODES_FUDGE_FACTOR;
- xlog("L_DEBUG", "nodes|media|$var(Node) media expiration $var(MediaExpire) for $var(MediaUrl)\n");
+ $var(MediaExpire) = ($(var(Payload){kz.json,Expires}{s.int}) / 1000) + NODES_FUDGE_EXPIRE;
+ xlog("L_DEBUG", "nodes|media|$var(Node) media expiration $var(MediaExpire) for $var(MediaUrl)\n");
$shtex(media=>$var(MediaUrl)::count) = $var(MediaExpire);
$var(ProfileIdx) = $var(ProfileIdx) + 1;
}
@@ -173,14 +172,14 @@ event_route[htable:expired:media]
route[MEDIA_SERVER_UP]
{
- xlog("L_WARNING", "nodes|media|$var(Node) reported new media server $var(MediaUrl) in zone $var(Zone)\n");
+ xlog("L_NOTICE", "nodes|media|$var(Node) reported new media server $var(MediaUrl) in zone $var(Zone)\n");
#!ifdef DISPATCHER_ROLE
route(DISPATCHER_CHECK_MEDIA_SERVER);
#!endif
-#!ifdef FAST_PICKUP_ROLE
- route(FAST_PICKUP_START);
+#!ifdef PRESENCE_ROLE
+ route(PRESENCE_FAST_PICKUP_START);
#!endif
}
@@ -188,7 +187,17 @@ route[MEDIA_SERVER_UP]
route[MEDIA_SERVER_DOWN]
{
xlog("L_WARNING", "htable|media|heartbeat expired for media server $var(MediaUrl) in zone $var(Zone)\n");
-
+
+#!ifdef PRESENCE_ROLE
+ route(RESET_PUBLISHER);
+#!endif
+
+}
+
+route[MEDIA_SERVER_RESTART]
+{
+ xlog("L_NOTICE", "htable|media|media server $var(MediaUrl) restarted in zone $var(Zone)\n");
+
#!ifdef PRESENCE_ROLE
route(RESET_PUBLISHER);
#!endif
@@ -198,7 +207,7 @@ route[MEDIA_SERVER_DOWN]
#!ifndef NODES_CUSTOM_BINDINGS
route[NODES_BINDINGS]
{
- $var(payload) = "{ 'exchange' : 'nodes' , 'type' : 'fanout', 'queue' : 'nodes-MY_HOSTNAME', 'exclusive' : 0, 'federate' : 1}";
+ $var(payload) = $_s({"name": "nodes", "exchange" : "nodes" , "type" : "fanout", "queue" : "nodes-MY_HOSTNAME", "exclusive":0, "federate":1 });
kazoo_subscribe("$var(payload)");
}
#!endif
@@ -214,17 +223,25 @@ route[LISTENER_STATUS]
$var(listener) = $(jsonrpl(body){kz.json,result[$var(loop)]});
$var(proto) = $(var(listener){kz.json,PROTO});
$var(address) = $(var(listener){kz.json,ADDRLIST.ADDR});
- $var(port) = $(var(listener){kz.json,PORT});
- $var(uri) = $_s($var(proto):$var(address):$var(port));
- if($(var(listener){kz.json,ADVERTISE}) != "-") {
- $var(advertise) = $_s( , "advertise" : "$(var(listener){kz.json,ADVERTISE})");
- } else {
- $var(advertise) = "";
+ if($var(address) != "127.0.0.1") {
+ $var(port) = $(var(listener){kz.json,PORT});
+ if($var(port) == "WS_PORT") {
+ $var(proto) = "ws";
+ }
+ if($var(port) == "WSS_PORT") {
+ $var(proto) = "wss";
+ }
+ $var(uri) = $_s($var(proto):$var(address):$var(port));
+ if($(var(listener){kz.json,ADVERTISE}) != "-") {
+ $var(advertise) = $_s( , "advertise" : "$(var(listener){kz.json,ADVERTISE})");
+ } else {
+ $var(advertise) = "";
+ }
+ $var(x) = $_s("$var(uri)" : {"proto" : "$var(proto)", "address" : "$var(address)", "port" : $var(port) $var(advertise) });
+ $var(listeners) = $_s($var(listeners)$var(sep)$var(x));
+ $var(sep) = " , ";
}
- $var(x) = $_s("$var(uri)" : {"proto" : "$var(proto)", "address" : "$var(address)", "port" : $var(port) $var(advertise) });
- $var(listeners) = $_s($var(listeners)$var(sep)$var(x));
$var(loop) = $var(loop) + 1;
- $var(sep) = " , ";
}
$var(listeners) = $_s({"Listeners" : { $var(listeners) }});
}
diff --git a/kamailio/fast-pickup-role.cfg b/kamailio/presence-fast-pickup.cfg
similarity index 60%
rename from kamailio/fast-pickup-role.cfg
rename to kamailio/presence-fast-pickup.cfg
index 36c05e7..692a32e 100644
--- a/kamailio/fast-pickup-role.cfg
+++ b/kamailio/presence-fast-pickup.cfg
@@ -2,18 +2,22 @@
modparam("htable", "htable", "park=>size=16;autoexpire=600")
modparam("htable", "htable", "fp=>size=8");
-kazoo.fast_pickup_cookies = KZ_FAST_PICKUP_COOKIES descr "maintains a hash table for correlating call-ids with media servers"
-kazoo.fast_pickup_realtime = KZ_FAST_PICKUP_REALTIME descr "queries channels api for realtime status of call-id"
+#!trydef KZ_PRESENCE_FAST_PICKUP_COOKIES 1
+#!trydef KZ_PRESENCE_FAST_PICKUP_REALTIME 1
+#!trydef KZ_PRESENCE_FAST_PICKUP_STAR_5 1
-route[FAST_PICKUP_START]
+kazoo.presence_fast_pickup_cookies = KZ_PRESENCE_FAST_PICKUP_COOKIES descr "maintains a hash table for correlating call-ids with media servers"
+kazoo.presence_fast_pickup_realtime = KZ_PRESENCE_FAST_PICKUP_REALTIME descr "queries channels api for realtime status of call-id"
+kazoo.presence_fast_pickup_star_5 = KZ_PRESENCE_FAST_PICKUP_STAR_5 descr "treats *5 as park pickup, queries state of *3"
+
+route[PRESENCE_FAST_PICKUP_START]
{
$sht(fp=>count) = 0;
}
-route[FAST_PICKUP_LOAD]
+route[PRESENCE_FAST_PICKUP_LOAD]
{
sht_reset("fp");
-#!ifndef KZ_USE_DISPATCHER_LIST
xlog("L_INFO", "$ci|log|fast|initializing fastpick hash table from dispatcher\n");
if (sql_xquery("exec", "select destination from dispatcher", "ra") == 1) {
while($xavp(ra) != $null) {
@@ -22,21 +26,17 @@ route[FAST_PICKUP_LOAD]
$var(destination) = $xavp(ra=>destination);
$var(i) = 0;
if(!is_ip("$var(host)")) {
- if(dns_query("$var(host)", "xyz")) {
- $var(destination) = $_s(sip:$dns(xyz=>addr[$var(i)]):$var(port));
- }
+ xlog("L_INFO", "$ci|log|fast|ignoring $var(host) since its not a ip address\n");
+ } else {
+ xlog("L_INFO", "$ci|log|fast|adding key $(var(destination){s.md5}) for $var(destination)\n");
+ $sht(fp=>$(var(destination){s.md5})) = $var(destination);
}
- xlog("L_INFO", "$ci|log|fast|adding key $(var(destination){s.md5}) for $var(destination)\n");
- $sht(fp=>$(var(destination){s.md5})) = $var(destination);
pv_unset("$xavp(ra)");
}
}
-#!else
- xlog("L_INFO", "$ci|log|fast|cannot initialize hash table from dispatcher. check KZ_USE_DISPATCHER_LIST option in local.cfg\n");
-#!endif
}
-route[FAST_PICKUP_ATTEMPT]
+route[PRESENCE_FAST_PICKUP_ATTEMPT]
{
if (!is_method("INVITE")) {
return;
@@ -50,18 +50,18 @@ route[FAST_PICKUP_ATTEMPT]
if($var(replaced_call_id) =~ "kfp+") {
if($shtinc(fp=>count) == 1) {
- route(FAST_PICKUP_LOAD);
+ route(PRESENCE_FAST_PICKUP_LOAD);
}
remove_hf_re("^Replaces");
$var(PickupOptions) = $(var(replaced_call_id){re.subst,/^kfp\+(.{2})([^@]*)@(.*)/\1/}{s.decode.hexa});
$var(md5) = $(var(replaced_call_id){re.subst,/^kfp\+(.{2})([^@]*)@(.*)/\2/});
$var(replaced_call_id) = $(var(replaced_call_id){re.subst,/^kfp\+(.{2})([^@]*)@(.*)/\3/});
if( $sht(fp=>$var(md5)) != $null) {
- route(FAST_PICKUP_OPTION);
+ route(PRESENCE_FAST_PICKUP_OPTION);
$du = $sht(fp=>$var(md5));
append_hf("Replaces: $var(replaced_call_id)$var(Pickup)\r\n");
xlog("L_INFO", "$ci|log|fast|found shortcut for call-id $var(replaced_call_id) , redirecting ($(ru{uri.user})) to $du\n");
- route(EXTERNAL_TO_INTERNAL_RELAY);
+ route(RELAY);
exit();
} else {
$var(replaced_call_id) = "none";
@@ -69,7 +69,7 @@ route[FAST_PICKUP_ATTEMPT]
}
}
- if(@cfg_get.kazoo.fast_pickup_realtime == 1) {
+ if($sel(cfg_get.kazoo.presence_fast_pickup_realtime) == 1) {
if($var(replaced_call_id) != "none") {
xlog("L_INFO", "$ci|log|request has replaces call-id $var(replaced_call_id)\n");
$var(amqp_payload_request) = '{"Event-Category" : "call_event" , "Event-Name" : "channel_status_req", "Call-ID" : "' + $var(replaced_call_id) + '", "Active-Only" : true }';
@@ -89,7 +89,7 @@ route[FAST_PICKUP_ATTEMPT]
remove_hf_re("^Replaces");
append_hf("Replaces: $var(rep)\r\n");
xlog("L_INFO", "$ci|log|call-id $var(replaced_call_id) found, redirecting call ($(ru{uri.user})) to $du => $var(rep)\n");
- route(EXTERNAL_TO_INTERNAL_RELAY);
+ route(RELAY);
exit();
} else {
xlog("L_WARN", "$ci|log|call-id $var(replaced_call_id) not found in cluster, proceeding with normal dispatch\n");
@@ -101,15 +101,48 @@ route[FAST_PICKUP_ATTEMPT]
}
##### CALL-PARK ####
+
+ ##### STAR 5 CHECK ####
+ if($sel(cfg_get.kazoo.presence_fast_pickup_star_5) == 1) {
+ if($(ru{uri.user}) =~ "\*5") {
+ $var(park) = $_s(*3$(ru{uri.user}{s.substr,2,0})@$(ru{uri.domain}));
+ if($sht(park=>$var(park)) != $null) {
+ $du = $sht(park=>$var(park));
+ xlog("L_INFO", "$ci|log|redirecting park request to $du , callid : $sht(park=>$var(park)::callid)\n");
+ route(RELAY);
+ exit();
+ }
+ }
+ }
+
if($sht(park=>$(ru{uri.user})@$(ru{uri.domain})) != $null) {
$du = $sht(park=>$(ru{uri.user})@$(ruri{uri.domain}));
- xlog("L_INFO", "$ci|log|redirecting park request to $du\n");
- route(EXTERNAL_TO_INTERNAL_RELAY);
+ xlog("L_INFO", "$ci|log|redirecting park request to $du, callid: $sht(park=>$(ru{uri.user})@$(ruri{uri.domain})::callid)\n");
+ route(RELAY);
exit();
}
+
+ ##### CALL-PARK IN KAZOO ####
+ $var(park_extension) = "\*3";
+ if($sel(cfg_get.kazoo.presence_fast_pickup_star_5) == 1) {
+ $var(park_extension) = "\*[3,5]";
+ }
+ if($(ru{uri.user}) =~ $var(park_extension) && !($rd =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") ) {
+ xlog("L_INFO", "$ci|log|checking park request to $(ru{uri.user})@$(ru{uri.domain})\n");
+ $var(amqp_payload_request) = '{"Event-Category" : "call_event" , "Event-Name" : "query_user_channels_req", "Username" : "*3$(ru{uri.user}{s.substr,2,0})", "Realm" : "$(ru{uri.domain})", "Active-Only" : true }';
+ $var(amqp_routing_key) = "call.status_req." + $(ci{kz.encode});
+ if(kazoo_query("callevt", $var(amqp_routing_key), $var(amqp_payload_request))) {
+ $du = $(kzR{kz.json,Channels[0].switch_url});
+ if($du != $null) {
+ xlog("L_INFO", "$ci|log|redirecting park request to $du from realtime query reply\n");
+ route(RELAY);
+ exit();
+ }
+ }
+ }
}
-route[FAST_PICKUP_OPTION]
+route[PRESENCE_FAST_PICKUP_OPTION]
{
$var(Pickup) = "";
switch($var(PickupOptions))
@@ -125,7 +158,7 @@ route[FAST_PICKUP_OPTION]
}
}
-route[FAST_PICKUP_INIT]
+route[PRESENCE_FAST_PICKUP_INIT]
{
$var(AppName) = $(kzE{kz.json,App-Name});
@@ -133,14 +166,15 @@ route[FAST_PICKUP_INIT]
if($var(AppName) == "park") {
if($(kzE{kz.json,State}) == "terminated") {
$sht(park=>$(kzE{kz.json,Presence-ID})) = $null;
+ $sht(park=>$(kzE{kz.json,Presence-ID})::callid) = $null;
} else {
$sht(park=>$(kzE{kz.json,Presence-ID})) = $(kzE{kz.json,Switch-URI});
+ $sht(park=>$(kzE{kz.json,Presence-ID})::callid) = $(kzE{kz.json,Call-ID});
}
-
}
## fast pickup with cookies
- if(@cfg_get.kazoo.fast_pickup_cookies == 1) {
+ if($sel(cfg_get.kazoo.presence_fast_pickup_cookies) == 1) {
if($var(AppName) == "park") {
$var(Pickup) = 1; #";a-leg=true";
} else {
@@ -151,7 +185,7 @@ route[FAST_PICKUP_INIT]
$var(Cookie) = $(kzE{kz.json,Switch-URI}{s.md5});
$var(call_id) = $(kzE{kz.json,Call-ID});
$var(JObj) = $(kzE{re.subst,/"Call-ID"\s*\:\s*"([^"]*)"/"Call-ID" : "kfp+$var(Option)$var(Cookie)@\1"/});
- xlog("L_INFO", "$var(call_id)|fast|shortcut ($var(Pickup)) kfp+$var(Option)$var(Cookie)@$var(call_id)\n");
+ xlog("L_DEBUG", "$var(call_id)|fast|shortcut ($var(Pickup)) kfp+$var(Option)$var(Cookie)@$var(call_id)\n");
}
}
diff --git a/kamailio/presence-notify.cfg b/kamailio/presence-notify.cfg
new file mode 100644
index 0000000..7107249
--- /dev/null
+++ b/kamailio/presence-notify.cfg
@@ -0,0 +1,213 @@
+#!trydef KZ_PRESENCE_REMOVE_WATCHER_ON_EXPIRED_REGISTRATION 0
+#!trydef KZ_PRESENCE_MAX_NOTIFY_ERROR 3
+#!trydef KZ_PRESENCE_NOTIFY_LOG_LEVEL 4
+
+
+kazoo.presence_notify = 1 descr "enable/disable sending notify callback to omnipresence"
+kazoo.presence_notify_timeout = 5000 descr "timeout in ms waiting for notify reply"
+kazoo.presence_notify_log_body = 0 descr "logs the body sent in the notification"
+kazoo.presence_notify_log_resp_body = 0 descr "logs the body received from notification"
+kazoo.presence_notify_log_to_table = 1 descr "logs notify/reply to active_watchers_log table"
+kazoo.presence_notify_log_to_amqp = 0 descr "logs notify/reply to amqp"
+kazoo.presence_notify_record_route = 1 descr "add record route header to notify msg sent"
+kazoo.presence_notify_log_init_body = 0 descr "logs the body before its sent"
+kazoo.presence_notify_force_send_socket = 1 descr "forces the send socket to the contact"
+kazoo.presence_remove_watcher_on_expired_registration = KZ_PRESENCE_REMOVE_WATCHER_ON_EXPIRED_REGISTRATION descr "removes watcher on expired registration"
+kazoo.presence_max_notify_error = KZ_PRESENCE_MAX_NOTIFY_ERROR descr "number of consecutive fails allowed before removing the subscription"
+kazoo.presence_notify_log_level = KZ_PRESENCE_NOTIFY_LOG_LEVEL descr "loglevel for informational log messages"
+
+######## Generic Hash Table container in shared memory ########
+modparam("htable", "htable", "notify=>size=16;autoexpire=3600;updateexpire=1;initval=0")
+
+route[PRESENCE_LOCAL_REQ_NOTIFY]
+{
+ if($rm != "NOTIFY") {
+ return;
+ }
+ t_set_fr($sel(cfg_get.kazoo.presence_notify_timeout), $sel(cfg_get.kazoo.presence_notify_timeout));
+ xlog("L_DEBUG", "$ci|log|init preparing $subs(event) notify to $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) : $du\n");
+ if($sel(cfg_get.kazoo.presence_notify_log_init_body) == 1) {
+ xlog("L_INFO", "$ci|log|init|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n");
+ }
+ if($sel(cfg_get.kazoo.presence_notify_force_send_socket) == 1) {
+ $fs = $_s($(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}));
+ xlog("L_DEBUG", "$ci|log|init|forcing socket to $fs, $(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}) , $ct\n");
+ }
+ if($sel(cfg_get.kazoo.presence_notify_record_route) == 1) {
+ record_route();
+ }
+
+ #!ifdef NAT_TRAVERSAL_ROLE
+ if(!isdsturiset()) {
+ handle_ruri_alias();
+ }
+ #!endif
+
+}
+
+modparam("mqueue","mqueue", "name=presence_last_notity")
+
+modparam("rtimer", "timer", "name=notifytimer;interval=1;mode=1;")
+modparam("rtimer", "exec", "timer=notifytimer;route=PRESENCE_LOG_TIMER_ROUTE")
+
+modparam("rtimer", "timer", "name=pres_cleanup;interval=10;mode=1;")
+modparam("rtimer", "exec", "timer=pres_cleanup;route=PRESENCE_CLEANUP")
+
+modparam("rtimer", "timer", "name=pres_publisher_cleanup;interval=5;mode=1;")
+modparam("rtimer", "exec", "timer=pres_publisher_cleanup;route=PRESENCE_PUBLISHER_CLEANUP")
+
+
+event_route[presence:notify-reply]
+{
+ if($sel(cfg_get.kazoo.presence_notify) != 1)
+ return;
+
+ $xavp(pres=>delete_subscription) = 0;
+
+ if($notify_reply($rs) == 200) {
+ $sht(notify=>$ci) = $null;
+ $sht(notify=>$ci::count) = 0;
+ xlog("$(sel(cfg_get.kazoo.presence_notify_log_level){s.int})", "$ci|end|notified $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n");
+ } else if($subs(reason) == "timeout") {
+ $xavp(pres=>delete_subscription) = 1;
+ xlog("L_DEBUG", "$ci|end|deleting subscription $subs(pres_uri) for $subs(watcher_username)@$subs(watcher_domain) due to timeout\n");
+ } else if($notify_reply($rs) == 481 && $subs(reason) == "timeout") {
+ xlog("L_DEBUG","$ci|end|sent subscription $hdr(Subscription-State)\n");
+ } else if($notify_reply($rs) == 408) {
+ if($rP != "UDP") {
+ $xavp(pres=>delete_subscription) = 1;
+ xlog("L_ERROR", "$ci|warning|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri) with reply $notify_reply($rs)\n");
+ } else {
+ $var(shtinc) = $shtinc(notify=>$ci::count);
+ if($var(shtinc) > $sel(cfg_get.kazoo.presence_max_notify_error)) {
+ $xavp(pres=>delete_subscription) = 1;
+ xlog("L_WARNING", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri) with reply $notify_reply($rs)\n");
+ } else {
+ $var(level) = 6 - $var(shtinc);
+ xlog("$var(level)", "$ci|error|received $notify_reply($rs) ($var(shtinc)/$sel(cfg_get.kazoo.presence_max_notify_error)) when notifying $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) with reply $notify_reply($rs)\n");
+ }
+ }
+ } else {
+ $xavp(pres=>delete_subscription) = 1;
+ xlog("L_WARNING", "$ci|end|deleting subscription $subs(pres_uri) as $subs(watcher_username)@$subs(watcher_domain) replied with $notify_reply($rs)\n");
+ }
+
+ if($sel(cfg_get.kazoo.presence_notify_log_body) == 1)
+ xlog("L_INFO", "$ci|log|sent|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n");
+ if($sel(cfg_get.kazoo.presence_notify_log_resp_body) == 1)
+ xlog("L_INFO", "$ci|log|resp|body $(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})\n");
+
+ if($sel(cfg_get.kazoo.presence_notify_log_to_amqp) == 1) {
+ route(PRESENCE_NOTIFY_AMQP);
+ }
+
+ if($sel(cfg_get.kazoo.presence_notify_log_to_table) == 1) {
+ if($xavp(pres=>delete_subscription) != 1 && $subs(reason) != "timeout") {
+ $var(Query) = $_s(KZQ_REPLACE_WATCHERS_LOG);
+ mq_add("presence_last_notity", "$subs(callid)", "$var(Query)");
+ }
+ }
+}
+
+
+route[PRESENCE_LOG_TIMER_ROUTE]
+{
+ $var(runloop) = 1;
+ while(mq_fetch("presence_last_notity") == 1 && $var(runloop) < MAX_WHILE_LOOPS) {
+ $var(ci) = $mqk(presence_last_notity);
+ xlog("L_DEBUG", "Query : $mqv(presence_last_notity)\n");
+ $var(sqlres) = sql_query("cb", "$mqv(presence_last_notity)");
+ xlog("L_DEBUG", "Query result : $var(sqlres)\n");
+ if($var(sqlres) < 0) {
+ xlog("L_ERROR", "$var(ci)|log|error running query : $mqv(presence_last_notity)\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[PRESENCE_NOTIFY_AMQP]
+{
+ $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "notify", "Event-Package" : "$subs(event)", "Timestamp" : $TS, "Call-ID" : "$subs(callid)", "From" : "$fu", "To" : "$subs(to_user)@$subs(to_domain)", "Sent" : "$(TS{s.ftime,%Y-%m-%d %H:%M:%S})", "Body" : "Hostname : MY_HOSTNAME\r\nTimestamp : $(TS{s.ftime,%Y-%m-%d %H:%M:%S})\r\n$(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\r\nResponse\r\n$(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})","Remote-CSeq" : $subs(remote_cseq), "Local-CSeq" : $subs(local_cseq), "Sequence" : $cs, "Version" : $subs(version), "Reply" : $notify_reply($rs) });
+ $var(rk) = "notify." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode});
+ kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request));
+ xlog("L_INFO", "$ci|log|sent notify callback for event $subs(event) : $tu\n");
+}
+
+
+route[PRESENCE_CLEANUP]
+{
+ $var(Query) = $_s(DELETE FROM active_watchers WHERE expires > 0 AND datetime(expires, 'unixepoch') < datetime('now', '-90 seconds'););
+ mq_add("presence_last_notity", "$uuid(g)", "$var(Query)");
+ $var(Query) = $_s(DELETE FROM PRESENTITY WHERE expires > 0 AND datetime(expires, 'unixepoch') < datetime('now'););
+ mq_add("presence_last_notity", "$uuid(g)", "$var(Query)");
+ $var(Query) = $_s(DELETE FROM PRESENTITY WHERE ID IN(select id from presentities where event = "dialog" and state = "terminated" and received < datetime('now', '-5 minutes')););
+ mq_add("presence_last_notity", "$uuid(g)", "$var(Query)");
+ $var(Query) = $_s(DELETE FROM ACTIVE_WATCHERS_LOG WHERE ID IN(select id from active_watchers_log a where not exists(select callid from active_watchers b where b.callid = a.callid and b.watcher_username = a.watcher_username and b.watcher_domain = a.watcher_domain)););
+ mq_add("presence_last_notity", "$uuid(g)", "$var(Query)");
+}
+
+route[PRESENCE_PUBLISHER_CLEANUP]
+{
+ xlog("L_DEBUG", "processing presence publisher cleanup\n");
+
+ $var(sqlres) = sql_query("cb", "update tmp_probe set action = 1 where action = 0");
+ if($var(sqlres) < 0) {
+ xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n");
+ return;
+ } else {
+ $var(nrows) = $sqlrows(cb);
+ if($var(nrows) > 0) {
+ if (sql_xquery("cb", "select * from tmp_probe where action = 1", "cleanup_pres") == 1)
+ {
+ while($xavp(cleanup_pres) != $null) {
+ xlog("L_DEBUG", "processing $xavp(cleanup_pres=>event) notifies for $xavp(cleanup_pres=>presentity_uri)\n");
+ pres_refresh_watchers("$xavp(cleanup_pres=>presentity_uri)", "$xavp(cleanup_pres=>event)", 1);
+ pv_unset("$xavp(cleanup_pres)");
+ }
+ }
+
+ $var(sqlres) = sql_query("cb", "delete from tmp_probe where action = 1");
+ if($var(sqlres) < 0) {
+ xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n");
+ } else {
+ $var(nrows) = $sqlrows(cb);
+ if($var(nrows) > 0) {
+ xlog("L_DEBUG", "presence publisher cleanup processed $var(nrows) rows\n");
+ }
+ }
+ }
+ }
+
+}
+
+route[PRESENCE_DEFERRED_INIT]
+{
+ xlog("L_INFO", "processing presence deferred init\n");
+ $var(sqlres) = sql_query("cb", "update tmp_probe set action = 0 where action = 2");
+ if($var(sqlres) < 0) {
+ xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n");
+ return;
+ } else {
+ $var(nrows) = $sqlrows(cb);
+ if($var(nrows) > 0) {
+ xlog("L_NOTICE", "scheduled update for $var(nrows) watched presentities/event\n");
+ }
+ }
+}
+
+route[PRESENCE_EXPIRED_REGISTRATION]
+{
+ if($sel(cfg_get.kazoo.presence_remove_watcher_on_expired_registration) == 1) {
+ $var(watcher) = $_s(sip:$ulc(exp=>aor));
+ $var(watcher_username) = $(var(watcher){uri.user});
+ $var(watcher_domain) = $(var(watcher){uri.host});
+ $var(Query) = $_s(DELETE FROM active_watchers WHERE watcher_username = "$var(watcher_username)" and watcher_domain = "$var(watcher_domain)";);
+ mq_add("presence_last_notity", "$uuid(g)", "$var(Query)");
+ }
+}
diff --git a/kamailio/presence_query-role.cfg b/kamailio/presence-query.cfg
similarity index 75%
rename from kamailio/presence_query-role.cfg
rename to kamailio/presence-query.cfg
index ac087cc..95fa96d 100644
--- a/kamailio/presence_query-role.cfg
+++ b/kamailio/presence-query.cfg
@@ -1,8 +1,11 @@
######## Presence query server module ########
+#!trydef KZ_PRESENCE_QUERY_REPLY_ZONES 0
+kazoo.presence_query_reply_zones = KZ_PRESENCE_QUERY_REPLY_ZONES descr "0 - all, 1 - local, 2 - remote"
+
route[PRESENCE_SEARCH_SUMMARY]
{
- xlog("L_INFO", "processing presence summary query for $(kzE{kz.json,Realm})\n");
+ xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|query|processing presence summary query for $(kzE{kz.json,Realm})\n");
$var(Queue) = $(kzE{kz.json,Server-ID});
$var(Event) = $(kzE{kz.json,Event-Package});
$var(Domain) = $(kzE{kz.json,Realm});
@@ -54,8 +57,9 @@ route[PRESENCE_SEARCH_SUMMARY]
route[PRESENCE_SEARCH_DETAIL]
{
- xlog("L_INFO", "processing presence query detail for $(kzE{kz.json,Username}) in realm $(kzE{kz.json,Realm})\n");
+ xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|query|processing presence query detail for $(kzE{kz.json,Username}) in realm $(kzE{kz.json,Realm})\n");
$var(Queue) = $(kzE{kz.json,Server-ID});
+ $var(Msg-ID) = $(kzE{kz.json,Msg-ID});
$var(Event) = $(kzE{kz.json,Event-Package});
$var(Domain) = $(kzE{kz.json,Realm});
$var(Username) = $(kzE{kz.json,Username});
@@ -64,7 +68,7 @@ route[PRESENCE_SEARCH_DETAIL]
$var(Items) = "";
$var(Query) = $_s(KZQ_PRESENCE_SEARCH_DETAIL);
if($var(Event) != "") {
- $var(Query) = $var(Query) + $_s( and event = "$var(Event)");
+ $var(Query) = $var(Query) + $_s( and a.event = "$var(Event)");
}
$var(Query) = $var(Query) + " order by event, watcher_username, callid";
xlog("L_DEBUG", "$ci| STATUS QUERY $var(Query)\n");
@@ -75,38 +79,35 @@ route[PRESENCE_SEARCH_DETAIL]
while($xavp(ra) != $null && $var(Event) == $xavp(ra=>event)) {
$var(Sub) = $_s("$var(Username)" : {"$xavp(ra=>event)" : { "$xavp(ra=>watcher_username)" : {"kamailio@MY_HOSTNAME" : {"$xavp(ra=>callid)" : {"time" : $xavp(ra=>time), "result" : $xavp(ra=>result), "sent" : "$(xavp(ra=>sent_msg){s.escape.common}{s.replace,\','}{s.replace,$$,})", "received" : "$(xavp(ra=>received_msg){s.escape.common}{s.replace,\','}{s.replace,$$,})", "user_agent" : "$(xavp(ra=>user_agent){s.escape.common}{s.replace,\','}{s.replace,$$,})"}}}}});
xlog("L_DEBUG", "$ci| RESULT \"Subscriptions\" : { $var(Sub) }\n");
- $var(amqp_payload_request) = '{"Event-Category" : "presence", "Event-Name" : "search_partial_resp", "Msg-ID" : "$(kzE{kz.json,Msg-ID})", "Subscriptions" : { $var(Sub) } }';
+ $var(amqp_payload_request) = '{"Event-Category" : "presence", "Event-Name" : "search_partial_resp", "Msg-ID" : "$var(Msg-ID)", "Subscriptions" : { $var(Sub) } }';
kazoo_publish("targeted", "$var(Queue)", $var(amqp_payload_request));
pv_unset("$xavp(ra)");
}
}
}
- $var(amqp_payload_request) = '{"Event-Category" : "presence", "Event-Name" : "search_resp", "Msg-ID" : "$(kzE{kz.json,Msg-ID})" }';
+ $var(amqp_payload_request) = '{"Event-Category" : "presence", "Event-Name" : "search_resp", "Msg-ID" : "$var(Msg-ID)" }';
kazoo_publish("targeted", "$var(Queue)", $var(amqp_payload_request));
}
-
-
event_route[kazoo:consumer-event-presence-search-req]
{
- switch($(kzE{kz.json,Search-Type})) {
- case "summary":
- route(PRESENCE_SEARCH_SUMMARY);
- break;
- case "detail":
- route(PRESENCE_SEARCH_DETAIL);
- break;
- default:
- xlog("L_INFO", "$ci|search type '$(kzE{kz.json,Search-Type})' not handled\n");
- }
-}
+ $var(Zone) = $(kzE{kz.json,AMQP-Broker-Zone});
+ if( ($var(Zone) == "MY_AMQP_ZONE" && $sel(cfg_get.kazoo.presence_query_reply_zones) != 2) ||
+ ($var(Zone) != "MY_AMQP_ZONE" && $sel(cfg_get.kazoo.presence_query_reply_zones) != 1)) {
-route[PRESENCE_QUERY_BINDINGS]
-{
- $var(payload) = "{ 'exchange' : 'presence' , 'type' : 'topic', 'queue' : 'presence-search-MY_HOSTNAME', 'routing' : 'presence.search_req.*', 'exclusive' : 0, 'federate' : 1 }";
- kazoo_subscribe("$var(payload)");
+ switch($(kzE{kz.json,Search-Type})) {
+ case "summary":
+ route(PRESENCE_SEARCH_SUMMARY);
+ break;
+ case "detail":
+ route(PRESENCE_SEARCH_DETAIL);
+ break;
+ default:
+ xlog("L_INFO", "$ci|search type '$(kzE{kz.json,Search-Type})' not handled\n");
+ }
+ }
}
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
diff --git a/kamailio/presence-reset.cfg b/kamailio/presence-reset.cfg
index eafd672..61315e7 100644
--- a/kamailio/presence-reset.cfg
+++ b/kamailio/presence-reset.cfg
@@ -1,3 +1,4 @@
+#!trydef PRESENCE_RESET_BLF_DEFER_UPDATE 0
kazoo.presence_reset_blf_defer_update = PRESENCE_RESET_BLF_DEFER_UPDATE descr "defers blf reset"
@@ -14,21 +15,10 @@ route[PRESENCE_RESET_ROUTE]
}
}
-route[PRESENCE_RESET_BINDINGS]
-{
- #!import_file "presence-reset-custom-bindings.cfg"
-
- #!ifndef PRESENCE_RESET_CUSTOM_BINDINGS
- $var(payload) = "{ 'exchange' : 'presence' , 'queue' : 'presence-reset-MY_HOSTNAME', 'type' : 'topic', 'routing' : 'presence.reset.*.*', 'exclusive' : 0, 'federate' : 1 }";
- kazoo_subscribe("$var(payload)");
- #!endif
-
-}
-
route[RESET_PUBLISHER]
{
- xlog("L_INFO", "$var(Msg-ID)|reset|received presence reset for publisher $var(MediaUrl))\n");
- if(@cfg_get.kazoo.presence_reset_blf_defer_update == 0) {
+ xlog("L_INFO", "$var(Msg-ID)|reset|received presence reset for publisher $var(MediaUrl)\n");
+ if($sel(cfg_get.kazoo.presence_reset_blf_defer_update) == 0) {
$var(Query) = $_s(KZQ_RESET_PUBLISHER_UPDATE);
sql_query("exec", "$var(Query)");
}
@@ -36,6 +26,33 @@ route[RESET_PUBLISHER]
sql_query("exec", "$var(Query)");
$var(presentities) = $sqlrows(exec);
xlog("L_INFO", "$var(Msg-ID)|reset|removed $var(presentities) presentities from publisher $var(MediaUrl)\n");
+ if($var(presentities) > 0) {
+ route(PRESENCE_PUBLISHER_CLEANUP);
+ }
+}
+
+route[PRESENCE_ZONE_UNAVAILABLE]
+{
+ if($(kzE{kz.json,name}) == "presence") {
+ $var(Zone) = $(kzE{kz.json,zone});
+ xlog("L_WARN", "amqp|reset|resetting publisher zone $var(Zone)\n");
+ route(RESET_PUBLISHER_ZONE);
+ }
+}
+
+route[RESET_PUBLISHER_ZONE]
+{
+ if($sel(cfg_get.kazoo.presence_reset_blf_defer_update) == 0) {
+ $var(Query) = $_s(KZQ_RESET_PUBLISHER_ZONE_UPDATE);
+ sql_query("exec", "$var(Query)");
+ }
+ $var(Query) = $_s(KZQ_PRESENCE_ZONE_RESET);
+ sql_query("exec", "$var(Query)");
+ $var(presentities) = $sqlrows(exec);
+ xlog("L_INFO", "amqp|reset|removed $var(presentities) presentities from zone $var(Zone)\n");
+ if($var(presentities) > 0) {
+ route(PRESENCE_PUBLISHER_CLEANUP);
+ }
}
route[RESET_ALL]
@@ -62,11 +79,14 @@ route[RESET_SERVER]
route[RESET_ACCOUNT]
{
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|received presence reset for realm $(kzE{kz.json,Realm})\n");
- sql_query("exec", 'KZQ_RESET_ACCOUNT_DELETE');
- $var(presentities) = $sqlrows(exec);
sql_query("exec", 'KZQ_RESET_ACCOUNT_UPDATE');
$var(watchers) = $sqlrows(exec);
+ sql_query("exec", 'KZQ_RESET_ACCOUNT_RESET');
+ $var(presentities) = $sqlrows(exec);
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|removed $var(presentities) presentities and expired $var(watchers) subscribers for realm $(kzE{kz.json,Realm})\n");
+ if($var(watchers) > 0) {
+ route(PRESENCE_PUBLISHER_CLEANUP);
+ }
}
route[RESET_WILDCARD]
@@ -98,7 +118,6 @@ route[RESET_WILDCARD]
}
-
event_route[kazoo:consumer-event-presence-reset]
{
if($(kzE{kz.json,Username}) == "*" || $(kzE{kz.json,Realm}) == "*") {
@@ -106,7 +125,7 @@ event_route[kazoo:consumer-event-presence-reset]
exit();
}
- xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|received presence reset for $(kzE{kz.json,Username})@$(kzE{kz.json,Realm})\n");
+ xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|received presence reset for $(kzE{kz.json,Username})@$(kzE{kz.json,Realm})\n");
$var(presentity) = $_s(sip:$(kzE{kz.json,Username})@$(kzE{kz.json,Realm}));
route(COUNT_SUBSCRIBERS);
sql_query("exec", 'KZQ_EVENT_PRESENCE_RESET_DELETE');
@@ -115,21 +134,21 @@ event_route[kazoo:consumer-event-presence-reset]
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|notifying $xavp(watchers=>message-summary) message-summary subscribers of $var(presentity)\n");
pres_refresh_watchers("$var(presentity)", "message-summary", 1);
} else {
- xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|skip message-summary subscriber notification for $var(presentity)\n");
+ xlog("L_DEBUG", "$(kzE{kz.json,Msg-ID})|reset|skip message-summary subscriber notification for $var(presentity)\n");
}
if($xavp(watchers=>presence) > 0) {
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|notifying $xavp(watchers=>presence) presence subscribers of $var(presentity)\n");
pres_refresh_watchers("$var(presentity)", "presence", 1);
} else {
- xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|skip presence subscriber notification for $var(presentity)\n");
+ xlog("L_DEBUG", "$(kzE{kz.json,Msg-ID})|reset|skip presence subscriber notification for $var(presentity)\n");
}
if($xavp(watchers=>dialog) > 0) {
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|notifying $xavp(watchers=>dialog) dialog subscribers of $var(presentity)\n");
pres_refresh_watchers("$var(presentity)", "dialog", 1);
} else {
- xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|skip dialog subscriber notification for $var(presentity)\n");
+ xlog("L_DEBUG", "$(kzE{kz.json,Msg-ID})|reset|skip dialog subscriber notification for $var(presentity)\n");
}
}
diff --git a/kamailio/presence-role.cfg b/kamailio/presence-role.cfg
index d5d4997..e7e4815 100644
--- a/kamailio/presence-role.cfg
+++ b/kamailio/presence-role.cfg
@@ -4,9 +4,35 @@
#!trydef PRESENCE_MAX_EXPIRES 3600
#!trydef KZ_PRESENCE_IGNORE_STATUS_PROBE_RESP 1
+#!trydef KZ_PRESENCE_CSEQ_OFFSET 2
+#!trydef KZ_PRESENCE_MAX_CALL_PER_PRESENTITY 20
+#!trydef BLF_USE_SINGLE_DIALOG 1
+#!trydef KZ_PRESENCE_AMQP_PUBLISH 0
+#!trydef KZ_PRESENCE_REQUEST_RESUBSCRIBE_PROBE 0
+#!trydef KZ_PRESENCE_REQUEST_PROBE 1
+#!trydef KZ_PRESENCE_NO_TARGETS_LOG_LEVEL L_DBG
+#!trydef KZ_PRESENCE_WITH_TARGETS_LOG_LEVEL L_INFO
+#!trydef KZ_PRESENCE_REQUIRE_AUTHN 0
+#!trydef KZ_PRESENCE_KEEPALIVE_NAT_ONLY 0
+#!trydef KZ_PRESENCE_KEEPALIVE_UDP_ONLY 0
-modparam("htable", "htable", "p=>size=32;autoexpire=3600;")
-modparam("htable", "htable", "first=>size=32;autoexpire=3600;initval =0;updateexpire=1;")
+
+#!ifdef NAT_TRAVERSAL_ROLE
+#!ifndef KEEPALIVE_ROLE
+#!ifndef NAT_TRAVERSAL_LOADED
+#!trydef NAT_TRAVERSAL_LOADED
+loadmodule "nat_traversal.so"
+#!endif
+
+modparam("nat_traversal", "keepalive_method", "OPTIONS")
+modparam("nat_traversal", "keepalive_from", "sip:sipcheck@MY_HOSTNAME")
+modparam("nat_traversal", "keepalive_state_file", "KAZOO_DATA_DIR/keep_alive_state")
+modparam("nat_traversal", "keepalive_interval", 45)
+#!endif
+#!endif
+
+
+modparam("htable", "htable", "first=>size=32;autoexpire=3600;initval=0;")
loadmodule "presence.so"
loadmodule "presence_dialoginfo.so"
@@ -24,8 +50,10 @@ modparam("presence_xml", "disable_bla", 1)
modparam("presence", "subs_db_mode", 3)
modparam("presence", "expires_offset", 0)
modparam("presence", "send_fast_notify", 1)
-modparam("presence", "clean_period", 30)
-modparam("presence", "db_update_period", 10)
+
+modparam("presence", "clean_period", 0)
+modparam("presence", "db_update_period", 0)
+
modparam("presence", "publ_cache", 0)
modparam("presence", "min_expires_action", PRESENCE_MIN_EXPIRES_ACTION)
modparam("presence", "min_expires", PRESENCE_MIN_EXPIRES)
@@ -39,50 +67,42 @@ modparam("presence", "local_log_level", 6)
modparam("presence", "startup_mode", 0)
modparam("presence", "force_delete", 1)
modparam("presence", "timeout_rm_subs", 0)
-modparam("presence", "cseq_offset", 1)
+modparam("presence", "cseq_offset", KZ_PRESENCE_CSEQ_OFFSET)
modparam("kazoo", "db_url", "KAZOO_DB_URL")
modparam("kazoo", "pua_mode", 1)
-#!ifdef NAT_TRAVERSAL_ROLE
-#!ifndef NAT_TRAVERSAL_LOADED
-#!trydef NAT_TRAVERSAL_LOADED
-loadmodule "nat_traversal.so"
-#!endif
-modparam("nat_traversal", "keepalive_method", "OPTIONS")
-modparam("nat_traversal", "keepalive_from", "sip:sipcheck@MY_HOSTNAME")
-modparam("nat_traversal", "keepalive_state_file", "KAZOO_DATA_DIR/keep_alive_state")
-modparam("nat_traversal", "keepalive_interval", 45)
-#!endif
-
kazoo.presence_sync_amqp = KZ_PRESENCE_AMQP_PUBLISH descr "sync subscriptions to amqp"
kazoo.presence_request_probe = KZ_PRESENCE_REQUEST_PROBE descr "request probe for new subscriptions"
kazoo.presence_request_resubscribe_probe = KZ_PRESENCE_REQUEST_RESUBSCRIBE_PROBE descr "request probe for resubscriptions"
kazoo.presence_ignore_status_probe_resp = KZ_PRESENCE_IGNORE_STATUS_PROBE_RESP descr "ignore online/offline probe replies"
-
-#!ifdef FAST_PICKUP_ROLE
-#!include_file "fast-pickup-role.cfg"
-#!endif
-#!ifdef PRESENCE_QUERY_ROLE
-#!include_file "presence_query-role.cfg"
-#!endif
-#!ifdef PRESENCE_NOTIFY_SYNC_ROLE
-#!include_file "presence_notify_sync-role.cfg"
-#!endif
+kazoo.presence_max_call_per_presentity = KZ_PRESENCE_MAX_CALL_PER_PRESENTITY descr "max number of calls per presentity"
+kazoo.presence_no_targets_log_level = KZ_PRESENCE_NO_TARGETS_LOG_LEVEL descr "when a presence event is received and there no targets we can log at another level"
+kazoo.presence_with_targets_log_level = KZ_PRESENCE_WITH_TARGETS_LOG_LEVEL descr "when a presence event is received and there are targets we can log at another level"
+kazoo.presence_require_authn = KZ_PRESENCE_REQUIRE_AUTHN descr "require authenticated devices for presence"
+kazoo.presence_keepalive_udp_only = KZ_PRESENCE_KEEPALIVE_UDP_ONLY descr "should we send keepalive for udp only"
+kazoo.presence_keepalive_nat_only = KZ_PRESENCE_KEEPALIVE_NAT_ONLY descr "should we send keepalive for nat phones only"
+
+#!include_file "presence-query.cfg"
+#!include_file "presence-notify.cfg"
+#!include_file "presence-reset.cfg"
+#!include_file "presence-fast-pickup.cfg"
####### Presence Logic ########
-#!ifdef NAT_TRAVERSAL_ROLE
route[PRESENCE_NAT]
{
- force_rport();
- if (client_nat_test("3")) {
- if(is_first_hop())
- set_contact_alias();
- }
- nat_keepalive();
+ if(!( ($sel(cfg_get.kazoo.presence_keepalive_udp_only) == 1 && $proto != "udp")
+ || (!isflagset(FLT_NATS) && $sel(cfg_get.kazoo.presence_keepalive_nat_only) == 1)
+ || ($proto == "ws" || $proto == "wss")
+ )) {
+ #!ifdef KEEPALIVE_ROLE
+ route(KEEPALIVE_ON_SUBSCRIBE);
+ #!else
+ nat_keepalive();
+ #!endif
+ }
}
-#!endif
route[HANDLE_SUBSCRIBE]
{
@@ -90,9 +110,20 @@ route[HANDLE_SUBSCRIBE]
return;
}
- #!ifdef NAT_TRAVERSAL_ROLE
- route(PRESENCE_NAT);
- #!endif
+ if ($hdr(Event) != "dialog"
+ && $hdr(Event) != "presence"
+ && $hdr(Event) != "message-summary") {
+ xlog("L_INFO", "$ci|presence|subscribe event $hdr(Event) not supported\n");
+ send_reply(489, "Bad Event");
+ exit();
+ }
+
+ route(PRESENCE_AUTHN);
+
+ if (!t_newtran()) {
+ sl_reply_error();
+ exit;
+ }
if(has_totag()) {
loose_route();
@@ -100,11 +131,6 @@ route[HANDLE_SUBSCRIBE]
record_route();
- if (!t_newtran()) {
- sl_reply_error();
- exit;
- }
-
if(has_totag()) {
route(HANDLE_RESUBSCRIBE);
} else {
@@ -116,15 +142,22 @@ route[HANDLE_SUBSCRIBE]
exit;
}
+route[DELETE_DUPLICATED_SUBSCRIPTIONS]
+{
+ sql_query("exec", '$_s(DELETE FROM ACTIVE_WATCHERS WHERE PRESENTITY_URI="$subs(uri)" AND EVENT="$subs(event)" AND FROM_USER = "$subs(from_user)" AND FROM_DOMAIN="$subs(from_domain)" AND CALLID <> "$subs(callid)")');
+}
+
route[HANDLE_RESUBSCRIBE]
{
-
+
if(handle_subscribe()) {
if($subs(remote_cseq) < 5) {
$sht(first=>$subs(callid)) = $null;
$sht(first=>$subs(from_user)::$subs(pres_uri)::$subs(from_domain)::$subs(event)) = $null;
}
+ route(DELETE_DUPLICATED_SUBSCRIPTIONS);
route(SUBSCRIBE_AMQP);
+ route(REQUEST_PROBE);
};
}
@@ -164,8 +197,12 @@ route[HANDLE_NEW_SUBSCRIBE]
if (handle_subscribe()) {
xlog("L_INFO","$ci|end|new $hdr(Event) subscription from $fU to $tU in realm $fd : $sht(first=>$ci) : $sht(first=>$fU::$tU::$fd::$hdr(Event))\n");
+ route(DELETE_DUPLICATED_SUBSCRIPTIONS);
route(SUBSCRIBE_AMQP);
route(REQUEST_PROBE);
+ #!ifdef NAT_TRAVERSAL_ROLE
+ route(PRESENCE_NAT);
+ #!endif
} else {
xlog("L_INFO", "$ci|stop|error $T_reply_code for new $hdr(Event) subscription from $fU to $tU in realm $fd\n");
}
@@ -177,7 +214,7 @@ route[HANDLE_NEW_SUBSCRIBE]
route[SUBSCRIBE_AMQP]
{
- if(@cfg_get.kazoo.presence_sync_amqp == 1) {
+ if($sel(cfg_get.kazoo.presence_sync_amqp) == 1) {
$var(rk) = "subscribe." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode});
$var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "subscription", "Event-Package" : "$hdr(event)", "Expires" : $subs(expires), "Queue" : "BLF-MY_HOSTNAME", "Server-ID" : "BLF-MY_HOSTNAME" , "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci", "From" : "$fu", "User" : "$subs(uri)", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})" });
kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request));
@@ -186,9 +223,9 @@ route[SUBSCRIBE_AMQP]
route[REQUEST_PROBE]
{
- if( (@cfg_get.kazoo.presence_request_probe == 1 && (!has_totag()))
- || (@cfg_get.kazoo.presence_request_resubscribe_probe == 1 && has_totag()) ) {
- if( route(HAS_PRESENTITY) == 0) {
+ if( ($sel(cfg_get.kazoo.presence_request_probe) == 1 && (!has_totag()))
+ || ($sel(cfg_get.kazoo.presence_request_resubscribe_probe) == 1 && has_totag()) ) {
+ if( route(HAS_PRESENTITY) == 0) {
if($hdr(event) == "message-summary") {
$var(mwi) = $tU;
route(REQUEST_MWI);
@@ -209,26 +246,40 @@ route[REQUEST_PROBE]
route[REQUEST_MWI]
{
- xlog("L_INFO", "$ci|sub|requesting mwi probe for $var(mwi) in realm $subs(to_domain)\n");
- $var(rk) = "mwi_queries." + $(subs(to_domain){kz.encode});
- $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "mwi_query", "Username" : "$var(mwi)", "Realm" : "$fd", "Call-ID" : "$ci"});
- kazoo_publish("presence", "$var(rk)", $var(amqp_payload_request));
+ xlog("L_INFO", "$ci|sub|requesting mwi probe for $var(mwi) in realm $subs(to_domain)\n");
+ $var(rk) = "mwi_queries." + $(subs(to_domain){kz.encode});
+ $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "mwi_query", "Username" : "$var(mwi)", "Realm" : "$fd", "Call-ID" : "$ci"});
+ kazoo_publish("presence", "$var(rk)", $var(amqp_payload_request));
}
route[HANDLE_PUBLISH]
{
- if (is_method("PUBLISH")) {
- if (!t_newtran()) {
- sl_reply_error();
- exit;
- }
- if($hdr(Sender)!= $null)
- handle_publish("$hdr(Sender)");
- else
- handle_publish();
- t_release();
+ if(!is_method("PUBLISH")) {
+ return;
+ }
+
+ if ($hdr(Event) != "dialog"
+ && $hdr(Event) != "presence"
+ && $hdr(Event) != "message-summary") {
+ xlog("L_INFO", "$ci|presence|publish event $hdr(Event) not supported\n");
+ send_reply(489, "Bad Event");
+ exit();
+ }
+
+ route(PRESENCE_AUTHN);
+
+ if (!t_newtran()) {
+ sl_reply_error();
exit;
}
+
+ if($hdr(Sender)!= $null) {
+ handle_publish("$hdr(Sender)");
+ } else {
+ handle_publish();
+ }
+ t_release();
+ exit;
}
route[HAS_PRESENTITY]
@@ -248,7 +299,7 @@ route[HAS_PRESENTITY]
route[COUNT_PRESENTITIES]
{
$var(Query) = $_s(KZQ_COUNT_PRESENTITIES);
- $var(p) = $_s(uri=$var(presentity));
+ $var(p) = $_s(presence_id='$var(presentity)');
if (sql_xquery("cb", "$var(Query)", "subs") == 1)
{
while($xavp(subs) != $null) {
@@ -262,7 +313,7 @@ route[COUNT_PRESENTITIES]
route[COUNT_ALL_PRESENTITIES]
{
$var(Query) = $_s(select event, (select count(*) from presentity b where b.event = a.event) count from event_list a);
- $var(p) = "uri=none";
+ $var(p) = "presence_id=none";
if (sql_xquery("cb", "$var(Query)", "subs") == 1)
{
while($xavp(subs) != $null) {
@@ -293,7 +344,7 @@ route[COUNT_ALL_SUBSCRIBERS]
route[COUNT_SUBSCRIBERS]
{
$var(Query) = $_s(KZQ_COUNT_SUBSCRIBERS);
- $var(p) = $_s(uri=$var(presentity));
+ $var(p) = $_s(presence_id='$var(presentity)');
if (sql_xquery("cb", "$var(Query)", "subs") == 1)
{
while($xavp(subs) != $null) {
@@ -306,80 +357,157 @@ route[COUNT_SUBSCRIBERS]
event_route[kazoo:consumer-event-presence-dialog-update]
{
- $var(Now) = $TS;
- xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|received $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) from $(kzE{kz.json,Switch-URI}) at $(kzE{kz.json,AMQP-Received})/$var(Now)\n");
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_no_targets_log_level){s.int});
+ $var(StartRoute) = $(TV(Sn){s.replace,.,});
+ $var(delta_to_start) = $var(StartRoute) - $(kzE{kz.json,AMQP-Received});
+ xlog("L_DEBUG", "$(kzE{kz.json,Call-ID})|log|received $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) from $(kzE{kz.json,AMQP-Broker-Zone}) => $(kzE{kz.json,Switch-URI}) (Δ1 $(kzE{kz.json,AMQP-Elapsed-Micro}) μs , Δ2 $var(delta_to_start) μs)\n");
+
$var(JObj) = $kzE;
- #!ifdef FAST_PICKUP_ROLE
- route(FAST_PICKUP_INIT);
- #!endif
-
+ route(PRESENCE_FAST_PICKUP_INIT);
+
$var(presentity) = $(kzE{kz.json,From});
$var(payload) = $kzE;
-
+
route(PRESENCE_UPDATE);
-
- xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|finished processing $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) from $(kzE{kz.json,Switch-URI}) at $(kzE{kz.json,AMQP-Received})/$var(Now)/$TS\n");
+ $var(EndRoute) = $(TV(Sn){s.replace,.,});
+ $var(delta_to_finish) = $var(EndRoute) - $var(StartRoute);
+
+ xlog("$var(kz_presence_log_level)", "$(kzE{kz.json,Call-ID})|log|$(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) from $(kzE{kz.json,AMQP-Broker-Zone}) => $(kzE{kz.json,Switch-URI}) (Δ1 $(kzE{kz.json,AMQP-Elapsed-Micro}) μs , Δ2 $var(delta_to_start) μs, Δ3 $var(delta_to_finish) μs)\n");
}
event_route[kazoo:consumer-event-presence-mwi-update]
{
- xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|received message-summary update for $(kzE{kz.json,From})\n");
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_no_targets_log_level){s.int});
+ $var(StartRoute) = $(TV(Sn){s.replace,.,});
+ $var(delta_to_start) = $var(StartRoute) - $(kzE{kz.json,AMQP-Received});
+ xlog("L_DBG", "$(kzE{kz.json,Call-ID})|log|received message-summary update for $(kzE{kz.json,From}) ($(kzE{kz.json,AMQP-Broker-Zone}))\n");
$var(presentity) = $(kzE{kz.json,From});
+ $var(payload) = $kzE;
route(COUNT_SUBSCRIBERS);
if($xavp(watchers=>message-summary) > 0) {
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_with_targets_log_level){s.int});
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing $(kzE{kz.json,From}) message-summary update for $xavp(watchers=>message-summary) watchers\n");
kazoo_pua_publish_mwi($kzE);
pres_refresh_watchers("$(kzE{kz.json,From})", "message-summary", 1);
} else {
- xlog("L_DEBUG", "$(kzE{kz.json,Call-ID})|log|skip message-summary update for $(kzE{kz.json,From})\n");
+#!ifdef PRESENCE_TRACK_ALL_PKG_MWI
+ if($(kzE{kz.json,Event-Package}) == "message-summary") {
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_with_targets_log_level){s.int});
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|saving $var(presentity) from mwi update => $var(payload)\n");
+ if(kazoo_pua_publish_mwi($kzE) != 1) {
+ xlog("L_ERR", "$(var(payload){kz.json,Call-ID})|log|error publishing $var(presentity) mwi update => $var(payload)\n");
+ }
+ }
+#!else
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|skip mwi update for $var(presentity)\n");
+#!endif
}
-
+
route(MWI_AS_PRESENCE);
- xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|finished processing message-summary update for $(kzE{kz.json,From}) light should be on ? $(kzE{kz.json,Messages-Waiting}) at $(kzE{kz.json,AMQP-Received})/$var(Now)/$TS\n");
+ $var(mwi_state) = "ON";
+ if($(kzE{kz.json,Messages-Waiting}) == "no") {
+ $var(mwi_state) = "OFF";
+ }
+
+ $var(EndRoute) = $(TV(Sn){s.replace,.,});
+ $var(delta_to_finish) = $var(EndRoute) - $var(StartRoute);
+
+ xlog("$var(kz_presence_log_level)", "$(kzE{kz.json,Call-ID})|log|message-summary update for $(kzE{kz.json,From}) light should be $var(mwi_state) (Δ1 $(kzE{kz.json,AMQP-Elapsed-Micro}) μs , Δ2 $var(delta_to_start) μs, Δ3 $var(delta_to_finish) μs)\n");
}
event_route[kazoo:consumer-event-presence-update]
{
- if(@cfg_get.kazoo.presence_ignore_status_probe_resp == 1) {
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_no_targets_log_level){s.int});
+ $var(StartRoute) = $(TV(Sn){s.replace,.,});
+ $var(delta_to_start) = $var(StartRoute) - $(kzE{kz.json,AMQP-Received});
+ if($sel(cfg_get.kazoo.presence_ignore_status_probe_resp) == 1) {
if($(kzE{kz.json,State}) == "offline" || $(kzE{kz.json,State}) == "online") {
+ xlog("L_DEBUG", "$(kzE{kz.json,Call-ID})|log|ignoring $(kzE{kz.json,State}) state $(kzE{kz.json,Presence-ID})\n");
return;
}
}
- xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|received presence update for $(kzE{kz.json,Presence-ID})\n");
+ xlog("L_DEBUG", "$(kzE{kz.json,Call-ID})|log|received presence update for $(kzE{kz.json,Presence-ID})");
$var(JObj) = $kzE;
$var(presentity) = $_s(sip:$(kzE{kz.json,Presence-ID}));
$var(payload) = $kzE;
route(PRESENCE_UPDATE);
-
- xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|finished processing $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) from $(kzE{kz.json,Switch-URI}) at $(kzE{kz.json,AMQP-Received})/$var(Now)/$TS\n");
+
+ $var(EndRoute) = $(TV(Sn){s.replace,.,});
+ $var(delta_to_finish) = $var(EndRoute) - $var(StartRoute);
+
+ xlog("$var(kz_presence_log_level)", "$(kzE{kz.json,Call-ID})|log|$(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) from $(kzE{kz.json,AMQP-Broker-Zone}) => $(kzE{kz.json,Switch-URI}) (Δ1 $(kzE{kz.json,AMQP-Elapsed-Micro}) μs , Δ2 $var(delta_to_start) μs, Δ3 $var(delta_to_finish) μs)\n");
}
route[PRESENCE_UPDATE]
{
+ $var(callid) = $(var(payload){kz.json,Call-ID});
if($(var(payload){kz.json,State}) == "terminated") {
route(COUNT_PRESENTITIES);
} else {
route(COUNT_SUBSCRIBERS);
}
- if($xavp(watchers=>dialog) > 0) {
- xlog("L_INFO", "$(var(payload){kz.json,Call-ID})|log|publishing $var(presentity) dialog update for $xavp(watchers=>dialog) watchers\n");
- kazoo_pua_publish_dialoginfo($var(JObj));
- pres_refresh_watchers("$var(presentity)", "dialog", 1);
+ if($xavp(watchers=>self) > $sel(cfg_get.kazoo.presence_max_call_per_presentity) &&
+ ( $(var(payload){kz.json,State}) == "early" ||
+ ($(var(payload){kz.json,State}) == "confirmed" && $(var(payload){kz.json,State}) == "initiator")
+ )) {
+ xlog("L_WARN", "$(var(payload){kz.json,Call-ID})|log|not publishing state $(var(payload){kz.json,State}) for presentity $var(presentity) with $xavp(watchers=>self) calls, policy limit of $sel(cfg_get.kazoo.presence_max_call_per_presentity) calls per presentity \n");
} else {
- xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|skip dialog update for $var(presentity)\n");
- }
+ if($xavp(watchers=>dialog) > 0) {
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_with_targets_log_level){s.int});
+ if($(var(payload){kz.json,State}) == "terminated") {
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|publishing $var(presentity) dialog update for terminated dialog\n");
+ } else {
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|publishing $var(presentity) dialog update for $xavp(watchers=>dialog) watchers\n");
+ }
+ if(kazoo_pua_publish_dialoginfo($var(JObj)) == 1) {
+ pres_refresh_watchers("$var(presentity)", "dialog", 1);
+ } else {
+ xlog("L_ERR", "$(var(payload){kz.json,Call-ID})|log|error publishing $var(presentity) dialog update\n");
+ };
+ } else {
+#!ifdef PRESENCE_TRACK_ALL_PKG_DIALOG
+ if($(kzE{kz.json,Event-Package}) == "dialog") {
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_with_targets_log_level){s.int});
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|saving $var(presentity) from dialog update => $var(payload)\n");
+ if(kazoo_pua_publish_dialoginfo($var(JObj)) != 1) {
+ xlog("L_ERR", "$(var(payload){kz.json,Call-ID})|log|error publishing $var(presentity) dialog update => $var(payload)\n");
+ }
+ }
+#!else
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|skip dialog update for $var(presentity)\n");
+#!endif
+ }
- if($xavp(watchers=>presence) > 0) {
- xlog("L_INFO", "$(var(payload){kz.json,Call-ID})|log|publishing $var(presentity) presence update for $xavp(watchers=>presence) watchers\n");
- kazoo_pua_publish_presence($var(payload));
- pres_refresh_watchers("$var(presentity)", "presence", 1);
- } else {
- xlog("L_DEBUG", "$(kzE{kz.json,Call-ID})|log|skip presence update for $var(presentity)\n");
- }
+ if($xavp(watchers=>presence) > 0) {
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_with_targets_log_level){s.int});
+ if($(var(payload){kz.json,State}) == "terminated") {
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|publishing $var(presentity) presence update for terminated dialog\n");
+ } else {
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|publishing $var(presentity) presence update for $xavp(watchers=>presence) watchers\n");
+ }
+ if(kazoo_pua_publish_presence($var(JObj)) == 1) {
+ pres_refresh_watchers("$var(presentity)", "presence", 1);
+ } else {
+ xlog("L_ERR", "$(var(payload){kz.json,Call-ID})|log|error publishing $var(presentity) presence update\n");
+ };
+ } else {
+#!ifdef PRESENCE_TRACK_ALL_PKG_PRESENCE
+ if($(kzE{kz.json,Event-Package}) == "presence") {
+ $var(kz_presence_log_level) = $(sel(cfg_get.kazoo.presence_with_targets_log_level){s.int});
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|saving $var(presentity) from presence update => $var(payload)\n");
+ if(kazoo_pua_publish_presence($var(JObj)) != 1) {
+ xlog("L_ERR", "$(var(payload){kz.json,Call-ID})|log|error publishing $var(presentity) presence update => $var(payload)\n");
+ }
+ }
+#!else
+ xlog("L_DEBUG", "$(var(payload){kz.json,Call-ID})|log|skip presence update for $var(presentity)\n");
+#!endif
+ }
+ }
}
@@ -405,44 +533,55 @@ route[MWI_AS_PRESENCE]
$var(State) = "confirmed";
} else {
$var(State) = "terminated";
- }
+ }
$var(payload) = MWI_PRESENCE_BODY
$var(JObj) = $var(payload);
-
route(PRESENCE_UPDATE);
}
-#!include_file "presence-reset.cfg"
-
route[PRESENCE_BINDINGS]
{
#!import_file "presence-custom-bindings.cfg"
-
+
#!ifndef PRESENCE_CUSTOM_BINDINGS
- $var(payload) = $_s({ "exchange" : "presence", "type" : "topic", "queue" : "presence-dialog-MY_HOSTNAME", "routing" : "dialog.*.*", "exclusive" : 0, "federate" : 1 });
+ $var(payload) = $_s({ "name" : "presence", "exchange" : "presence", "type" : "topic", "queue" : "presence-dialog-MY_HOSTNAME", "routing" : ["dialog.*.*", "update.*.*", "mwi_updates.*.*"], "exclusive" : 0, "federate" : 1 });
kazoo_subscribe("$var(payload)");
-
+ #!endif
- $var(payload) = $_s({ "exchange" : "presence", "type" : "topic", "queue" : "presence-presence-MY_HOSTNAME", "routing" : "update.*.*", "exclusive" : 0, "federate" : 1 });
- kazoo_subscribe("$var(payload)");
+ route(PRESENCE_API_BINDINGS);
- $var(payload) = $_s({ "exchange" : "presence", "type" : "topic", "queue" : "presence-mwi-MY_HOSTNAME", "routing" : "mwi_updates.*.*", "exclusive" : 0 , "federate" : 1 });
- kazoo_subscribe("$var(payload)");
- #!endif
+ route(PRESENCE_FAST_PICKUP_START);
- route(PRESENCE_RESET_BINDINGS);
-
- #!ifdef PRESENCE_QUERY_ROLE
- route(PRESENCE_QUERY_BINDINGS);
- #!endif
+}
- #!ifdef FAST_PICKUP_ROLE
- route(FAST_PICKUP_START);
+route[PRESENCE_API_BINDINGS]
+{
+ #!import_file "presence-api-custom-bindings.cfg"
+
+ #!ifndef PRESENCE_API_CUSTOM_BINDINGS
+ $var(payload) = $_s({"name": "presence-api", "exchange": "presence", "type": "topic", "queue": "presence-api-MY_HOSTNAME", "routing": ["presence.search_req.*", "presence.reset.*.*"], "exclusive": 0, "federate": 1 });
+ kazoo_subscribe("$var(payload)");
#!endif
}
+route[PRESENCE_LOCAL_REQUEST]
+{
+ route(PRESENCE_LOCAL_REQ_NOTIFY);
+}
+
+route[PRESENCE_AUTHN]
+{
+ if($sel(cfg_get.kazoo.presence_require_authn) == 1) {
+ $xavp(regcfg=>match_received) = $su;
+ if(registered("location", "$rz:$Au", 2, 1) != 1) {
+ xlog("L_WARNING", "$ci|stop|$rm from unregistered ($rz:$Au) user agent $ua => $su\n");
+ send_reply(403, "Forbidden");
+ exit;
+ }
+ }
+}
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
diff --git a/kamailio/presence_notify_sync-role.cfg b/kamailio/presence_notify_sync-role.cfg
deleted file mode 100644
index d8b4b8e..0000000
--- a/kamailio/presence_notify_sync-role.cfg
+++ /dev/null
@@ -1,117 +0,0 @@
-kazoo.presence_notify = 1 descr "enable/disable sending notify callback to omnipresence"
-kazoo.presence_notify_timeout = 3000 descr "timeout in ms waiting for notify reply"
-kazoo.presence_notify_log_body = 0 descr "logs the body sent in the notification"
-kazoo.presence_notify_log_resp_body = 0 descr "logs the body received from notification"
-kazoo.presence_notify_log_to_table = 1 descr "logs notify/reply to active_watchers_log table"
-kazoo.presence_notify_log_to_amqp = 0 descr "logs notify/reply to amqp"
-kazoo.presence_notify_record_route = 1 descr "add record route header to notify msg sent"
-kazoo.presence_notify_log_init_body = 0 descr "logs the body before its sent"
-kazoo.presence_notify_force_send_socket = 0 descr "forces the send socket to the contact"
-
-######## Generic Hash Table container in shared memory ########
-modparam("htable", "htable", "notify=>size=16;autoexpire=3600;updateexpire=1;initval=0")
-
-#!trydef PRESENCE_NOTIFY_INIT
-#!trydef MAX_NOTIFY_ERROR 5
-
-route[PRESENCE_LOCAL_NOTIFY]
-{
- if($rm != "NOTIFY") {
- return;
- }
- t_set_fr(@cfg_get.kazoo.presence_notify_timeout, @cfg_get.kazoo.presence_notify_timeout);
- xlog("L_INFO", "$ci|log|init preparing $subs(event) notify to $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) : $du\n");
- if(@cfg_get.kazoo.presence_notify_log_init_body == 1) {
- xlog("L_INFO", "$ci|log|init|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n");
- }
- if(@cfg_get.kazoo.presence_notify_force_send_socket == 1) {
- $fs = $_s($(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}));
- xlog("L_INFO", "$ci|log|init|forcing socket to $fs, $(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}) , $ct\n");
- }
- if(@cfg_get.kazoo.presence_notify_record_route == 1) {
- record_route();
- }
-}
-
-modparam("mqueue","mqueue", "name=presence_last_notity")
-
-####### RTIMER module ##########
-#!ifndef RTIMER_LOADED
-loadmodule "rtimer.so"
-#!trydef RTIMER_LOADED
-#!endif
-modparam("rtimer", "timer", "name=notifytimer;interval=500000u;mode=2;")
-modparam("rtimer", "exec", "timer=notifytimer;route=PRESENCE_LOG_TIMER_ROUTE")
-
-
-event_route[presence:notify-reply]
-{
- if(@cfg_get.kazoo.presence_notify != 1)
- return;
-
- $xavp(pres=>delete_subscription) = 0;
-
- if($subs(reason) == "timeout") {
- $xavp(pres=>delete_subscription) = 1;
- xlog("L_INFO", "$ci|end|deleting subscribtion $subs(pres_uri) for $subs(watcher_username)@$subs(watcher_domain) due to timeout\n");
- } else if($notify_reply($rs) == 200) {
- $sht(notify=>$ci) = $null;
- $sht(notify=>$ci::count) = 0;
- xlog("L_INFO", "$ci|end|notified $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n");
- } else {
- xlog("L_ERROR", "$ci|error|received $notify_reply($rs) when notifying $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n");
- if($rP != "UDP") {
- $xavp(pres=>delete_subscription) = 1;
- xlog("L_ERROR", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri)\n");
- } else {
- $var(shtinc) = $shtinc(notify=>$ci::count);
- if($var(shtinc) > MAX_NOTIFY_ERROR) {
- $xavp(pres=>delete_subscription) = 1;
- xlog("L_ERROR", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri)\n");
- }
- }
- }
- if(@cfg_get.kazoo.presence_notify_log_body == 1)
- xlog("L_INFO", "$ci|log|sent|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n");
- if(@cfg_get.kazoo.presence_notify_log_resp_body == 1)
- xlog("L_INFO", "$ci|log|resp|body $(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})\n");
-
- if(@cfg_get.kazoo.presence_notify_log_to_amqp == 1) {
- route(PRESENCE_NOTIFY_AMQP);
- }
-
- if(@cfg_get.kazoo.presence_notify_log_to_table == 1) {
- $var(Query) = $_s(REPLACE INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES ("$subs(uri)", "$subs(watcher_username)", "$subs(watcher_domain)", "$subs(event)","$subs(callid)","$subs(to_user)","$subs(to_domain)", '$(subs(user_agent){s.escape.common}{s.replace,\',''}{s.replace,$$,})', $TS, $notify_reply($rs), '$(mb{s.escape.common}{s.replace,\',''}{s.replace,$$,})', '$(notify_reply($mb){s.escape.common}{s.replace,\',''}{s.replace,$$,})'));
- mq_add("presence_last_notity", "$subs(callid)", "$var(Query)");
- }
-}
-
-
-route[PRESENCE_LOG_TIMER_ROUTE]
-{
- $var(runloop) = 1;
- while(mq_fetch("presence_last_notity") == 1 && $var(runloop) < MAX_WHILE_LOOPS) {
- $var(ci) = $mqk(presence_last_notity);
- xlog("L_DEBUG", "Query : $mqv(presence_last_notity)\n");
- $var(sqlres) = sql_query("cb", "$mqv(presence_last_notity)");
- xlog("L_DEBUG", "Query result : $var(sqlres)\n");
- if($var(sqlres) < 0) {
- xlog("L_ERROR", "$var(ci)|log|error updating active_watchers_log\n");
- } else {
- $var(nrows) = $sqlrows(cb);
- xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows)\n");
- if($var(nrows) == 0) {
- xlog("L_ERROR", "$var(ci)|log|error no rows affected when updating active_watchers_log\n");
- }
- }
- $var(runloop) = $var(runloop) + 1;
- }
-}
-
-route[PRESENCE_NOTIFY_AMQP]
-{
- $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "notify", "Event-Package" : "$subs(event)", "Timestamp" : $TS, "Call-ID" : "$subs(callid)", "From" : "$fu", "To" : "$subs(to_user)@$subs(to_domain)", "Sent" : "$(TS{s.ftime,%Y-%m-%d %H:%M:%S})", "Body" : "Hostname : MY_HOSTNAME\r\nTimestamp : $(TS{s.ftime,%Y-%m-%d %H:%M:%S})\r\n$(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\r\nResponse\r\n$(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})","Remote-CSeq" : $subs(remote_cseq), "Local-CSeq" : $subs(local_cseq), "Sequence" : $cs, "Version" : $subs(version), "Reply" : $notify_reply($rs) });
- $var(rk) = "notify." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode});
- kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request));
- xlog("L_INFO", "$ci|log|sent notify callback for event $subs(event) : $tu\n");
-}
diff --git a/kamailio/pusher-role.cfg b/kamailio/pusher-role.cfg
index 6097a06..8925ac3 100644
--- a/kamailio/pusher-role.cfg
+++ b/kamailio/pusher-role.cfg
@@ -3,8 +3,6 @@
######## Generic Hash Table container in shared memory ########
modparam("htable", "htable", "push_cache=>autoexpire=60;")
-modparam("tm", "failure_exec_mode", 1)
-
route[PUSHER_ROUTE]
{
if ( (!is_method("INVITE")) || (!isflagset(FLAG_INTERNALLY_SOURCED)) || $hdr(X-KAZOO-PUSHER-Token-ID) == $null)
@@ -66,7 +64,7 @@ route[PUSHER_PREPARE_PUSH]
route[PUSHER_PREPARE_PUSH_PAYLOAD]
{
-
+
$var(TokenID) = $hdr(X-KAZOO-PUSHER-Token-ID);
$var(TokenType) = $hdr(X-KAZOO-PUSHER-Token-Type);
$var(TokenApp) = $hdr(X-KAZOO-PUSHER-Token-App);
@@ -90,13 +88,13 @@ route[PUSHER_PREPARE_PUSH_PAYLOAD]
$var(from_user) = $(hdr(From){tobody.user});
$var(from_name) = $(hdr(From){tobody.display}{re.subst,/"//g});
}
-
+
$var(from) = $_s($var(from_user) - $var(from_name));
$var(PushPayload) = $_s({"call-id" : "$ci", "proxy" : "$var(TokenProxy)", "caller-id-number" : "$var(from_user)", "caller-id-name" : "$var(from_name)", "registration-token" : "$var(TokenReg)"});
$var(Payload) = $_s({ "Event-Category" : "notification", "Event-Name" : "push_req", "Call-ID" : "$ci", "Token-ID" : "$var(TokenID)", "Token-Type" : "$var(TokenType)", "Token-App" : "$var(TokenApp)", "Alert-Key" : "IC_SIL", "Alert-Params" : ["$var(from)"], "Sound" : "ring.caf", "Payload" : $var(PushPayload) });
-
+
$avp(push_routing_key) = "notification.push." + $var(TokenType) + "." + $var(TokenID);
$avp(push_payload) = $var(Payload);
}
@@ -126,6 +124,7 @@ route[PUSHER_ATTEMPT_REGISTRATION]
$xavp(ulattrs=>custom_channel_vars) = "{}";
$xavp(ulattrs[0]=>x_token_reg) = $hdr(X-Token-Reg);
route(SAVE_LOCATION);
+ exit;
} else {
xlog("L_INFO", "$ci|pusher|registration x-token-reg '$hdr(X-Token-Reg)' from header was not found\n");
}
@@ -139,6 +138,7 @@ route[PUSHER_ATTEMPT_REGISTRATION]
$xavp(ulattrs=>custom_channel_vars) = "{}";
$xavp(ulattrs[0]=>x_token_reg) = $(sel(contact.uri){uri.param,x-token-reg});
route(SAVE_LOCATION);
+ exit;
} else {
xlog("L_INFO", "$ci|pusher|registration x-token-reg from contact uri param '$(sel(contact.uri){uri.param,x-token-reg})' was not found\n");
}
@@ -152,6 +152,7 @@ route[PUSHER_ATTEMPT_REGISTRATION]
$xavp(ulattrs=>custom_channel_vars) = "{}";
$xavp(ulattrs[0]=>x_token_reg) = $(sel(contact){tobody.params}{param.value,x-token-reg});
route(SAVE_LOCATION);
+ exit;
} else {
xlog("L_INFO", "$ci|pusher|registration x-token-reg from contact param '$(sel(contact){tobody.params}{param.value,x-token-reg})' was not found\n");
}
@@ -160,8 +161,8 @@ route[PUSHER_ATTEMPT_REGISTRATION]
route[PUSHER_ON_REGISTRATION]
{
- if( ( $(xavp(ulattrs=>x_token_reg){s.len}) > 0 ||
- $(xavp(ulattrs=>custom_channel_vars){kz.json,Pusher-Application}{s.len}) > 0) &&
+ if( ( $(xavp(ulattrs=>x_token_reg){s.len}) > 0 ||
+ $(xavp(ulattrs=>custom_channel_vars){kz.json,Pusher-Application}{s.len}) > 0) &&
$var(Status) == "Registered") {
if($sht(push_cache=>$(tu{s.tolower})) != $null) {
xlog("L_INFO", "$ci|pusher|device registered, delivering the call\n");
diff --git a/kamailio/registrar-role.cfg b/kamailio/registrar-role.cfg
index 3474fd0..52952be 100644
--- a/kamailio/registrar-role.cfg
+++ b/kamailio/registrar-role.cfg
@@ -1,62 +1,85 @@
+#### NAT PINGING PARAMS ###
#!trydef REGISTRAR_NAT_PING_INTERVAL 30
+
+## REGISTRAR_NAT_PING_TIMEOUT should be (REGISTRAR_NAT_PING_INTERVAL * 3 + 10) or 0 to disable
+#!trydef REGISTRAR_NAT_PING_TIMEOUT 0
+
+#!trydef REGISTRAR_NAT_PING_NAT_ONLY 1
#!trydef REGISTRAR_NAT_PING_WORKERS 5
+#####
+
#!trydef REGISTRAR_MIN_EXPIRES 300
#!trydef REGISTRAR_MAX_EXPIRES 3600
+#!trydef REGISTRAR_DEFAULT_EXPIRES 600
+#!trydef REGISTRAR_ERROR_MIN_EXPIRES 1
+#!trydef REGISTRAR_ERROR_MISSING_EXPIRES 1
#!trydef REGISTRAR_CONTACT_MAX_SIZE 2048
+#!trydef REGISTRAR_QUERY_TIMEOUT_MS 2500
#!trydef REGISTRAR_HANDLE_LOST_TCP 1
-#!trydef REGISTRAR_CLOSE_EXPIRED_TCP 1
-
+#!trydef REGISTRAR_CLOSE_EXPIRED_TCP 0
#!trydef REGISTRAR_HANDLE_EXPIRED_TCP 1
#!trydef REGISTRAR_HANDLE_EXPIRED_UDP 0
#!trydef REGISTRAR_HANDLE_EXPIRED_TLS 1
#!trydef REGISTRAR_HANDLE_EXPIRED_WS 1
+#!trydef REGISTRAR_FORCE_QUERY 0
+#!trydef REGISTRAR_FORCE_FAILOVER 0
+#!trydef REGISTRAR_CHECK_AMQP_AVAILABILITY 1
+#!trydef KZ_REGISTRAR_KEEPALIVE_UDP_ONLY 0
+#!trydef REGISTRAR_AMQP_EXCHANGE callmgr
+#!trydef REGISTRAR_AMQP_FLAGS 0
+#!trydef REGISTRAR_AMQP_RK_PREFIX authn.req.
+#!trydef REGISTRAR_SEND_100 1
+#!trydef REGISTRAR_DB_MODE 2
+#!trydef REGISTRAR_DB_TIMER_CLEANUP 0
+#!trydef REGISTRAR_DB_REMOVE_EXPIRED_DELAY 0
+#!trydef REGISTRAR_SYNC_TIMER_INTERVAL 5
+#!trydef REGISTRAR_SYNC_TIMER_PROCS 1
+
+
+#!ifdef REGISTRAR_WARM_CACHE
+#!substdef "!REGISTRAR_S_WARM_CACHE!dbtable=auth_cache;dbmode=1;!g"
+#!else
+#!substdef "!REGISTRAR_S_WARM_CACHE!!g"
+#!endif
######## Generic Hash Table container in shared memory ########
-modparam("htable", "htable", "auth_cache=>size=16;autoexpire=7200;")
+modparam("htable", "htable", "auth_cache=>size=16;autoexpire=7200;REGISTRAR_S_WARM_CACHE")
####### Authentication Interface module ##########
loadmodule "auth.so"
-#!ifdef OPENBTS_AUTH_ROLE
-loadmodule "auth_openbts.so"
-modparam("auth", "qop", "")
-modparam("auth", "secret", "OPENBTS_AUTH_SECRET")
-modparam("auth_openbts", "challenge_attr", "$avp(digest_challenge)")
-#!endif
-
####### User Location Implementation module ##########
loadmodule "usrloc.so"
modparam("usrloc", "db_update_as_insert", 0)
modparam("usrloc", "use_domain", 1)
modparam("usrloc", "nat_bflag", FLB_NATB)
modparam("usrloc", "db_url", "KAZOO_DB_URL")
-modparam("usrloc", "db_mode", 1)
-modparam("usrloc", "handle_lost_tcp", 1)
-modparam("usrloc", "xavp_contact", "ulattrs")
+
+modparam("usrloc", "db_mode", REGISTRAR_DB_MODE)
+
+modparam("usrloc", "db_timer_clean", REGISTRAR_DB_TIMER_CLEANUP)
+modparam("usrloc", "handle_lost_tcp", REGISTRAR_HANDLE_LOST_TCP)
+modparam("usrloc", "rm_expired_delay", REGISTRAR_DB_REMOVE_EXPIRED_DELAY)
+
modparam("usrloc", "db_check_update", 1)
-modparam("usrloc", "timer_interval", 30)
-modparam("usrloc", "timer_procs", 1)
-modparam("usrloc", "db_timer_clean", 1)
+modparam("usrloc", "db_ops_ruid", 1)
+
+
+modparam("usrloc", "xavp_contact", "ulattrs")
+modparam("usrloc", "timer_interval", REGISTRAR_SYNC_TIMER_INTERVAL)
+modparam("usrloc", "timer_procs", REGISTRAR_SYNC_TIMER_PROCS)
+
modparam("usrloc", "fetch_rows", 400)
modparam("usrloc", "handle_lost_tcp", REGISTRAR_HANDLE_LOST_TCP)
modparam("usrloc", "close_expired_tcp", REGISTRAR_CLOSE_EXPIRED_TCP)
-######## NAT Traversal module - signaling functions ########
-#!ifdef NAT_TRAVERSAL_ROLE
-#!trydef NATHELPER_LOADED
-loadmodule "nathelper.so"
-modparam("nathelper", "natping_interval", REGISTRAR_NAT_PING_INTERVAL)
-modparam("nathelper", "ping_nated_only", 0)
-modparam("nathelper", "natping_processes", REGISTRAR_NAT_PING_WORKERS)
-modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
-#!endif
-
####### SIP Registrar implementation module ##########
loadmodule "registrar.so"
modparam("registrar", "received_avp", "$avp(AVP_RECV_PARAM)")
modparam("registrar", "min_expires", REGISTRAR_MIN_EXPIRES)
modparam("registrar", "max_expires", REGISTRAR_MAX_EXPIRES)
+modparam("registrar", "default_expires", REGISTRAR_DEFAULT_EXPIRES)
modparam("registrar", "xavp_cfg", "regcfg")
modparam("registrar", "gruu_enabled", 1)
modparam("registrar", "outbound_mode", 1)
@@ -64,172 +87,236 @@ modparam("registrar", "regid_mode", 1)
modparam("registrar", "path_mode", 1)
modparam("registrar", "use_path", 1)
modparam("registrar", "received_param", "")
-##modparam("registrar", "xavp_rcd", "ulrcd")
+modparam("registrar", "xavp_rcd", "ulrcd")
modparam("registrar", "contact_max_size", REGISTRAR_CONTACT_MAX_SIZE)
-##### handle expired registrations realtime params #####
+####### NAT ##########
+#!ifdef NAT_TRAVERSAL_ROLE
+#!ifndef NATHELPER_LOADED
+loadmodule "nathelper.so"
+#!trydef NATHELPER_LOADED
+#!endif
+#!ifdef KEEPALIVE_ROLE
+modparam("nathelper", "natping_interval", 0)
+modparam("nathelper", "natping_processes", 0)
+#!else
+modparam("nathelper", "natping_interval", REGISTRAR_NAT_PING_INTERVAL)
+modparam("nathelper", "ping_nated_only", REGISTRAR_NAT_PING_NAT_ONLY)
+modparam("nathelper", "natping_processes", REGISTRAR_NAT_PING_WORKERS)
+modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
+modparam("nathelper", "keepalive_timeout", REGISTRAR_NAT_PING_TIMEOUT)
+#!endif
+#!endif
+
+## stats ##
+modparam("statistics","variable", "registrar:force_failover")
+modparam("statistics","variable", "registrar:cached")
+modparam("statistics","variable", "registrar:ip_realm")
+modparam("statistics","variable", "registrar:new_tran")
+modparam("statistics","variable", "registrar:amqp_not_available")
+modparam("statistics","variable", "registrar:challenge")
+modparam("statistics","variable", "registrar:amqp_async_error")
+modparam("statistics","variable", "registrar:amqp_returned")
+modparam("statistics","variable", "registrar:amqp_timeout")
+modparam("statistics","variable", "registrar:drops")
+modparam("statistics","variable", "registrar:authn_perm_err")
+modparam("statistics","variable", "registrar:authn_err")
+modparam("statistics","variable", "registrar:authn_resp")
+modparam("statistics","variable", "registrar:authn_unknown")
+modparam("statistics","variable", "registrar:save_error")
+modparam("statistics","variable", "registrar:missing_expires")
+modparam("statistics","variable", "registrar:missing_expires_allowed")
+modparam("statistics","variable", "registrar:min_expires")
+modparam("statistics","variable", "registrar:min_expires_allowed")
+
+
+##### registrar realtime params #####
+kazoo.registrar_error_min_expires = REGISTRAR_ERROR_MIN_EXPIRES descr "send error when UAS sends expires < min-expires"
+kazoo.registrar_error_missing_expires = REGISTRAR_ERROR_MISSING_EXPIRES descr "send error when UAS do not send expires header"
kazoo.registrar_handle_expired_tcp = REGISTRAR_HANDLE_EXPIRED_TCP descr "handles expired tcp registrations"
kazoo.registrar_handle_expired_udp = REGISTRAR_HANDLE_EXPIRED_UDP descr "handles expired udp registrations"
kazoo.registrar_handle_expired_tls = REGISTRAR_HANDLE_EXPIRED_TLS descr "handles expired tls registrations"
kazoo.registrar_handle_expired_ws = REGISTRAR_HANDLE_EXPIRED_WS descr "handles expired ws registrations"
+kazoo.registrar_query_timeout_ms = REGISTRAR_QUERY_TIMEOUT_MS descr "timeout waiting for reply from registrar"
+kazoo.registrar_failover = REGISTRAR_FORCE_FAILOVER descr "force failover if 1"
+kazoo.registrar_force_query = REGISTRAR_FORCE_QUERY descr "force query if 1"
+kazoo.registrar_check_amqp_availability = REGISTRAR_CHECK_AMQP_AVAILABILITY descr "checks if amqp connection is available before querying registrar"
+kazoo.registrar_keepalive_udp_only = KZ_REGISTRAR_KEEPALIVE_UDP_ONLY descr "should we keepalive nat phones for udp only"
+kazoo.registrar_send_100 = REGISTRAR_SEND_100 descr "should we send 100 reply while doing directory search"
####### Registrar Logic ########
-route[HANDLE_REGISTER]
-{
- if (is_method("REGISTER")) {
- #!ifdef NAT_TRAVERSAL_ROLE
- if (nat_uac_test("3")) {
- xlog("L_INFO", "$ci|log|correcting NATed contact in registration\n");
- force_rport();
- }
+route[REGISTRAR_NAT_FLAGS]
+{
+ if (isflagset(FLT_NATS)) {
+ xlog("L_DEBUG", "$ci|log|fixing contact for nat request\n");
+ setbflag(FLB_NATB);
fix_nated_register();
## KAZOO-1846: Cisco SPA8000 freaks out on options pings
if (!($ua =~ "Linksys/SPA8000"
- || $ua =~ "OpenBTS"
|| $ua =~ "SIPp"
|| (af==INET6)
+ || ($sel(cfg_get.kazoo.registrar_keepalive_udp_only) == 1 && $proto != "udp")
+ || ($proto =="ws" || $proto == "wss")
+ || ($(xavp(ulattrs=>custom_channel_vars){kz.json,Keep-Alive}) == "false")
)) {
- setbflag(FLB_NATB);
+ xlog("L_DEBUG", "$ci|log|set nat pinging\n");
setbflag(FLB_NATSIPPING);
}
- #!endif
-
- route(ATTEMPT_AUTHORIZATION);
-
+ } else {
+ $avp(AVP_RECV_PARAM) = $su;
}
}
-route[AUTHORIZATION_CHECK]
+route[HANDLE_REGISTER]
{
- if (!is_method("MESSAGE|NOTIFY|SUBSCRIBE|PUBLISH"))
+ if (!is_method("REGISTER")) {
return;
-
- if(has_totag())
- return;
-
- if (isflagset(FLAG_INTERNALLY_SOURCED))
- return;
-
- if (isflagset(FLAG_TRUSTED_SOURCE))
- return;
-
- $xavp(regcfg=>match_received) = $su;
- if(!(registered("location", "$fu", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1)) {
- xlog("L_INFO", "$ci|log|not authorized $fu from $si:$sp\n");
- send_reply("503", "Not Registered");
- exit;
-# route(ATTEMPT_AUTHORIZATION);
}
-}
-route[ATTEMPT_AUTHORIZATION]
-{
#!ifdef PUSHER_ROLE
route(PUSHER_ATTEMPT_REGISTRATION);
#!endif
- $var(nonce) = $(uuid(g){s.rm,-});
- #!ifdef OPENBTS_AUTH_ROLE
- if($ua =~ "OpenBTS" && $sht(auth_cache=>$Au::nonce) != $null ) {
- $var(nonce) = $sht(auth_cache=>$Au::nonce);
+ if($sel(cfg_get.kazoo.registrar_failover) == 1) {
+ xlog("L_INFO", "$ci|log|register|forcing failover\n");
+ update_stat("registrar:force_failover", "+1");
+ drop;
}
- #!endif
- $xavp(regcfg=>match_received) = $su;
- if($sht(auth_cache=>$Au) != $null && registered("location", "$rz:$Au", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1) {
- $var(password) = $sht(auth_cache=>$Au);
- route(SAVE_LOCATION);
+ if($sel(cfg_get.kazoo.registrar_force_query) == 0) {
+ if($sht(auth_cache=>$Au) == "authn_perm_err") {
+ xlog("L_INFO", "$ci|end|issuing auth challenge to cached permanent failed registration attempt for $Au from IP $si:$sp\n");
+ update_stat("registrar:authn_perm_err", "+1");
+ #!ifdef ANTIFLOOD_ROLE
+ route(ANITFLOOD_FAILED_AUTH);
+ #!endif
+ update_stat("registrar:challenge", "+1");
+ auth_challenge("$fd", "4");
+ exit;
+ } else if($sht(auth_cache=>$Au) != $null) {
+ $xavp(regcfg=>match_received) = $su;
+ if(registered("location", "$rz:$Au", 2, 1) == 1) {
+ if($(xavp(ulattrs=>custom_channel_vars){s.len}) > 1) {
+ $var(password) = $sht(auth_cache=>$Au);
+ update_stat("registrar:cached", "+1");
+ route(SAVE_LOCATION);
+ exit;
+ }
+ }
+ }
}
- if( is_present_hf("Authorization")) {
- route(KAZOO_AUTHORIZATION);
+ if($td =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}" ||
+ $fd =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") {
+ xlog("L_INFO", "$ci|log|register|invalid domain\n");
+ update_stat("registrar:ip_realm", "+1");
+ drop;
}
- #!ifdef OPENBTS_AUTH_ROLE
- if($ua =~ "OpenBTS") {
- openbts_auth_challenge("$fd", "$var(nonce)");
- } else {
- #!endif
- auth_challenge("$fd", "0");
- #!ifdef OPENBTS_AUTH_ROLE
+ if($sel(cfg_get.kazoo.registrar_check_amqp_availability) == 1) {
+ if($xavp(amqpc=>default::MY_AMQP_ZONE) == 0) {
+ xlog("L_WARNING", "$ci|end|register|no amqp connection available for default worker in zone MY_AMQP_ZONE\n");
+ update_stat("registrar:amqp_not_available", "+1");
+ drop;
+ }
}
- #!endif
- xlog("L_INFO", "$ci|end|issued auth challenge to new registration for $fu $si:$sp\n");
- exit;
-}
+ route(REGISTRAR_BOUNDS);
+
+ $var(auth) = pv_auth_check("$fd", "$uuid(g)", "0", "0");
+ if($var(auth) != -2) {
+ xlog("L_INFO", "$ci|end|challenging $Au $si:$sp\n");
+ $var(auth) = auth_challenge("$fd", "4");
+ update_stat("registrar:challenge", "+1");
+ if($var(auth) != 1) {
+ xlog("L_ERROR", "$ci|register|error creating or sending challenge to registration attempt for $fu from $si:$sp\n");
+ drop;
+ }
+ exit;
+ }
-route[KAZOO_AUTHORIZATION]
-{
- $var(nonce) = $adn;
- $var(amqp_payload_request) = $_s({"Event-Category" : "directory" , "Event-Name" : "authn_req", "Method" : "REGISTER", "Auth-Nonce" : "$adn", "Auth-Realm" : "$fd", "Auth-User" : "$fU", "From" : "$fu", "To" : "$tu", "Orig-IP" : "$si", "Orig-Port" : "$sp", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci" });
- $var(amqp_routing_key) = "authn.req." + $(fd{kz.encode});
- $avp(kz_timeout) = 2500;
if (!t_newtran()) {
- sl_reply_error();
- exit();
+ xlog("L_ERROR", "$ci|log|failed to create transaction to query for authentication credentials for $Au $si:$sp\n");
+ update_stat("registrar:new_tran", "+1");
+ drop;
}
- if(kazoo_async_query("callmgr", $var(amqp_routing_key), $var(amqp_payload_request), "KAZOO_AUTHORIZATION_OK", "KAZOO_AUTHORIZATION_ERROR") != 1) {
- xlog("L_INFO", "$ci|log|failed to send Kazoo query for authentication credentials for $Au $si:$sp\n");
- append_to_reply("Retry-After: 60\r\n");
- send_reply("503", "Retry Later");
- exit;
+
+ if($sel(cfg_get.kazoo.registrar_send_100) == 1) {
+ sl_send_reply("100", "checking your credentials");
+ }
+
+ $var(amqp_payload_request) = $_s({"Event-Category" : "directory" , "Event-Name" : "authn_req", "Method" : "REGISTER", "Auth-Nonce" : "$adn", "Auth-Realm" : "$fd", "Auth-User" : "$fU", "From" : "$fu", "To" : "$tu", "Orig-IP" : "$si", "Orig-Port" : "$sp", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci" });
+ $var(amqp_routing_key) = $_s($def(REGISTRAR_AMQP_RK_PREFIX)$(fd{kz.encode}));
+ $avp(kz_timeout) = $sel(cfg_get.kazoo.registrar_query_timeout_ms);
+ $xavp(deltas=>query) = $(TV(Sn){s.replace,.,});
+
+ xlog("L_DEBUG", "$ci|amqp|publishing to $def(REGISTRAR_AMQP_EXCHANGE) => $var(amqp_routing_key) : $def(REGISTRAR_AMQP_FLAGS) : $var(amqp_payload_request)\n");
+ if(kazoo_async_query("$def(REGISTRAR_AMQP_EXCHANGE)", $var(amqp_routing_key), $var(amqp_payload_request), "KZ_AUTHORIZATION_REPLY", "KZ_AUTHORIZATION_TIMEOUT", "$def(REGISTRAR_AMQP_FLAGS)") != 1) {
+ xlog("L_INFO", "$ci|log|failed to send registrar query for authentication credentials for $Au $si:$sp\n");
+ update_stat("registrar:amqp_async_error", "+1");
+ t_drop();
}
}
-route[KAZOO_AUTHORIZATION_OK]
+failure_route[KZ_AUTHORIZATION_TIMEOUT]
{
- $var(password) = $(kzR{kz.json,Auth-Password});
- $var(nonce) = $adn;
- #!ifdef OPENBTS_AUTH_ROLE
- if( $(kzR{kz.json,Auth-Nonce}) != "" && $var(nonce) != $(kzR{kz.json,Auth-Nonce})) {
- xlog("L_INFO", "$ci|log|nonce replace $var(nonce) with $(kzR{kz.json,Auth-Nonce})\n");
- $var(nonce) = $(kzR{kz.json,Auth-Nonce});
- $sht(auth_cache=>$Au::nonce) = $var(nonce);
- }
- #!endif
- if( $(kzR{kz.json,Event-Name}) == "authn_err" ) {
- auth_challenge("$fd", "0");
- xlog("L_INFO", "$ci|end|issued auth challenge to registration attempt for $Au $si:$sp\n");
- exit;
+ if($(kzR{kz.json,Event-Name}) == "message_returned" ) {
+ xlog("L_WARNING", "$ci|amqp|message was returned by broker $(kzR{kz.json,Error-Code}) $(kzR{kz.json,Error-Reason})\n");
+ update_stat("registrar:amqp_returned", "+1");
} else {
- $xavp(ulattrs=>custom_channel_vars) = $(kzR{kz.json,Custom-Channel-Vars});
- xlog("L_INFO", "$ci|log|authenticating $Au via Kazoo query response\n");
- route(CHECK_AUTHORIZATION);
+ xlog("L_WARNING", "$ci|end|failed $T_reply_code $T_reply_reason [$T(id_index):$T(id_label)] querying directory for authentication credentials for $Au $si:$sp\n");
+ update_stat("registrar:amqp_timeout", "+1");
}
+ update_stat("registrar:drops", "+1");
+ t_drop();
}
-route[KAZOO_AUTHORIZATION_ERROR]
+onreply_route[KZ_AUTHORIZATION_REPLY]
{
- xlog("L_INFO", "$ci|log|failed to query Kazoo for authentication credentials for $Au $si:$sp\n");
- append_to_reply("Retry-After: 60\r\n");
- send_reply("503", "Retry Later");
- exit;
+ $var(StartRoute) = $(TV(Sn){s.replace,.,});
+ $var(delta_to_start) = $var(StartRoute) - $(kzR{kz.json,AMQP-Received});
+ $var(delta_from_query) = $(kzR{kz.json,AMQP-Received}) - $xavp(deltas=>query);
+ xlog("L_INFO", "$ci|log|received $(kzR{kz.json,Event-Category}) $(kzR{kz.json,Event-Name}) reply from $(kzR{kz.json,App-Name})-$(kzR{kz.json,App-Version}) (Δ1 $(kzR{kz.json,AMQP-Elapsed-Micro}) μs , Δ2 $var(delta_to_start) μs, Δ3 $var(delta_from_query) μs)\n");
+ $var(password) = $(kzR{kz.json,Auth-Password});
+ $var(nonce) = $adn;
+ if( $(kzR{kz.json,Event-Name}) == "authn_err" ) {
+ if($(kzR{kz.json,Permanent-Error}) == "true") {
+ $sht(auth_cache=>$Au) = "authn_perm_err";
+ }
+ update_stat("registrar:authn_err", "+1");
+ #!ifdef ANTIFLOOD_ROLE
+ route(ANITFLOOD_FAILED_AUTH);
+ #!endif
+ update_stat("registrar:challenge", "+1");
+ auth_challenge("$fd", "4");
+ xlog("L_INFO", "$ci|end|challenging $Au $si:$sp via $(kzR{kz.json,App-Name})-$(kzR{kz.json,App-Version}) response\n");
+ exit;
+ } else if( $(kzR{kz.json,Event-Name}) == "authn_resp" ) {
+ update_stat("registrar:authn_resp", "+1");
+ xlog("L_INFO", "$ci|log|authenticating $Au via $(kzR{kz.json,App-Name})-$(kzR{kz.json,App-Version}) response\n");
+ route(CHECK_AUTHORIZATION);
+ } else {
+ update_stat("registrar:authn_unknown", "+1");
+ update_stat("registrar:drops", "+1");
+ xlog("L_INFO", "$ci|log|unhandle response from directory $Au via $(kzR{kz.json,App-Name})-$(kzR{kz.json,App-Version})\n");
+ t_drop();
+ }
}
route[CHECK_AUTHORIZATION]
{
- if($ua =~ "OpenBTS") {
- xlog("L_INFO", "$ci|end|OPENBTS attempt for $Au $si:$sp\n");
- } else {
- if($var(password) == $null || $var(password) == "") {
- auth_challenge("$fd", "0");
- xlog("L_INFO", "$ci|end|issued auth challenge to registration attempt for $Au $si:$sp\n");
- exit;
- }
-
- if (!pv_auth_check("$fd", "$var(password)", "0", "0")) {
- #!ifdef ANTIFLOOD_ROLE
- route(ANITFLOOD_FAILED_AUTH);
- #!endif
+ if (!pv_auth_check("$fd", "$var(password)", "0", "0")) {
+ #!ifdef ANTIFLOOD_ROLE
+ route(ANITFLOOD_FAILED_AUTH);
+ #!endif
- auth_challenge("$fd", "0");
- xlog("L_WARNING", "$ci|end|issued auth challenge to failed registration attempt for $Au from IP $si:$sp\n");
- exit;
- }
+ xlog("L_WARNING", "$ci|end|issuing auth challenge to failed registration attempt for $Au from IP $si:$sp\n");
+ update_stat("registrar:challenge", "+1");
+ auth_challenge("$fd", "5");
+ exit;
}
#!ifdef ANTIFLOOD_ROLE
@@ -239,26 +326,27 @@ route[CHECK_AUTHORIZATION]
# user authenticated - remove auth header
consume_credentials();
+ $xavp(ulattrs=>custom_channel_vars) = $(kzR{kz.json,Custom-Channel-Vars});
+ $xavp(ulattrs[0]=>token) = $_s($(kzR{kz.json,Custom-Channel-Vars.Authorizing-ID})@$(kzR{kz.json,Custom-Channel-Vars.Account-ID}));
+
route(SAVE_LOCATION);
}
route[SAVE_LOCATION]
{
- if ($sht(auth_cache=>$Au) == $null) {
+
+ if ($sht(auth_cache=>$Au) == $null && $var(password) != $null) {
xlog("L_INFO", "$ci|log|caching sip credentials for $Au\n");
};
$sht(auth_cache=>$Au) = $var(password);
- #!ifdef OPENBTS_AUTH_ROLE
- if($ua =~ "OpenBTS") {
- $sht(auth_cache=>$Au::nonce) = $var(nonce);
- }
- #!endif
+
+ route(REGISTRAR_NAT_FLAGS);
$var(save_result) = save("location", "0x04");
- if($var(save_result) == -1) {
- auth_challenge("$fd", "0");
- xlog("L_INFO", "$ci|end|issued auth challenge after failed attempt to save contact for $Au $si:$sp\n");
+ if($var(save_result) < 0) {
+ xlog("L_WARNING", "$ci|end|not expected result $var(save_result) when saving $Au registration from IP $si:$sp\n");
+ update_stat("registrar:save_error", "+1");
exit;
} else {
if($var(save_result) == 1) {
@@ -268,34 +356,17 @@ route[SAVE_LOCATION]
}
}
- if((int)@contact.expires) {
- $var(expires) = @contact.expires;
+ if($var(save_result) == 3) {
+ $var(expires) = 0;
} else {
- if(is_present_hf("Expires")) {
- $var(expires) = $hdr(Expires);
- } else {
- $var(expires) = REGISTRAR_MIN_EXPIRES;
- }
+ $var(expires) = $xavp(ulrcd=>expires);
}
-## this is what we should be using
-## but ulrcd seems to have a weird leak
-## if($var(save_result) == 3) {
-## $var(expires) = 0;
-## } else {
-## $var(expires) = $xavp(ulrcd=>expires);
-## }
-
if($var(expires) == 0) {
xlog("L_INFO", "$ci|end|unregister request from $Au $si:$sp\n");
$var(Status) = "Unregistered";
} else {
$var(Status) = "Registered";
- if($var(expires) < REGISTRAR_MIN_EXPIRES) {
- $var(expires) = REGISTRAR_MIN_EXPIRES;
- } else if($var(expires) > REGISTRAR_MAX_EXPIRES) {
- $var(expires) = REGISTRAR_MAX_EXPIRES;
- }
}
$var(ip) = $Ri;
@@ -340,17 +411,20 @@ route[SAVE_LOCATION]
$var(AdvIP) = "[" + $RAi + "]";
}
-
- $var(amqp_payload_request) = $_s({"Event-Category" : "directory", "Event-Name" : "reg_success", "Status" : "$var(Status)", "Event-Timestamp" : $TS, "Expires" : $(var(expires){s.int}), "First-Registration" : $var(new_reg), "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci", "Realm" : "$fd", "Username" : "$fU", "From-User" : "$fU", "From-Host" : "$fd", "To-User" : "$tU", "To-Host" : "$td", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})" , "Custom-Channel-Vars" : $xavp(ulattrs=>custom_channel_vars), "Proxy-Path" : "sip:$var(ip):$var(port)", "Proxy-Protocol" : "$proto", "Proxy-IP" : "$var(AdvIP)", "Proxy-Port" : "$RAp", "Source-IP": "$si", "Source-Port": "$sp" });
+ $var(amqp_payload_request) = $_s({"Event-Category" : "directory", "Event-Name" : "reg_success", "Status" : "$var(Status)", "Event-Timestamp" : $TS, "Expires" : $(var(expires){s.int}), "First-Registration" : $var(new_reg), "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci", "Realm" : "$fd", "Username" : "$fU", "From-User" : "$fU", "From-Host" : "$fd", "To-User" : "$tU", "To-Host" : "$td", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})" , "Custom-Channel-Vars" : $xavp(ulattrs=>custom_channel_vars), "Proxy-Path" : "sip:MY_IP_ADDRESS:$var(port)", "Proxy-Protocol" : "$proto", "Proxy-IP" : "$var(AdvIP)", "Proxy-Port" : "$RAp", "Source-IP": "$si", "Source-Port": "$sp" });
$var(amqp_routing_key) = "registration.success." + $(fd{kz.encode}) + "." + $(fU{kz.encode});
kazoo_publish("registrar", $var(amqp_routing_key), $var(amqp_payload_request));
- xlog("L_INFO", "$ci|end|successful $(var(Status){s.tolower}) with contact : $ct\n");
+ xlog("L_INFO", "$ci|end|successful $(var(Status){s.tolower}) with contact : $ct : $var(expires)\n");
#!ifdef PUSHER_ROLE
route(PUSHER_ON_REGISTRATION);
#!endif
+ #!ifdef KEEPALIVE_ROLE
+ route(KEEPALIVE_ON_REGISTRATION);
+ #!endif
+
exit;
}
@@ -364,6 +438,10 @@ event_route[kazoo:consumer-event-directory-reg-flush]
$sht(auth_cache=>$var(user)) = $null;
}
+ if( $(kzE{kz.json,Cache-Only}) == "true") {
+ return;
+ }
+
if(reg_fetch_contacts("location", "sip:$var(user)", "caller")) {
$var(i) = 0;
while($var(i) < $(ulc(caller=>count))) {
@@ -379,8 +457,81 @@ event_route[kazoo:consumer-event-directory-reg-flush]
#!endif
}
+route[REGISTRAR_BINDINGS]
+{
+ #!import_file "registrar-custom-bindings.cfg"
+
+ #!ifndef REGISTRAR_CUSTOM_BINDINGS
+
+ $var(payload) = $_s({"name": "registrar-api", "exchange": "registrar", "type": "topic", "queue": "registrar-flush-MY_HOSTNAME", "routing": "registration.flush.*", "federate": 1 });
+ kazoo_subscribe("$var(payload)");
+
+ #!endif
+
+ #!ifdef REGISTRAR_SYNC_ROLE
+ route(REGISTRAR_SYNC_BINDINGS);
+ #!endif
+
+}
+
+route[REGISTRAR_BOUNDS]
+{
+ if((int)@contact.expires) {
+ $var(expires) = @contact.expires;
+ } else if(is_present_hf("Expires")) {
+ $var(expires) = $hdr(Expires);
+ } else if($(sel(contact){tobody.params}{param.value,expires}) != "") {
+ $var(expires) = $(sel(contact){tobody.params}{param.value,expires}{s.int});
+ } else {
+ if($sel(cfg_get.kazoo.registrar_error_missing_expires) == 1) {
+ xlog("L_WARNING", "$ci|end|missing expires registering $Au from IP $si:$sp\n");
+ send_reply("400", "Missing Expires");
+ update_stat("registrar:missing_expires", "+1");
+ exit;
+ } else {
+ update_stat("registrar:missing_expires_allowed", "+1");
+ xlog("L_WARNING", "$ci|end|allowing missing expires registering $Au from IP $si:$sp\n");
+ }
+ }
+
+ if($var(expires) != 0) {
+ if($var(expires) < REGISTRAR_MIN_EXPIRES) {
+ if($sel(cfg_get.kazoo.registrar_error_min_expires) == 1) {
+ xlog("L_WARNING", "$ci|end|expires $var(expires) too brief (configured $def(REGISTRAR_MIN_EXPIRES)) registering $Au from IP $si:$sp\n");
+ append_to_reply("Min-Expires: $def(REGISTRAR_MIN_EXPIRES)\r\n");
+ send_reply("423", "Interval Too Brief");
+ update_stat("registrar:min_expires", "+1");
+ exit;
+ } else {
+ update_stat("registrar:min_expires_allowed", "+1");
+ xlog("L_WARNING", "$ci|end|allowing expires $var(expires) too brief (configured $def(REGISTRAR_MIN_EXPIRES)) registering $Au from IP $si:$sp\n");
+ }
+ }
+ }
+
+}
+
+##
+## this needs handling logic in ecallmgr
+## because we will fire the unregister from this server
+## after device registers in another proxy
+## causing ecallmgr to delete the registration
+## from the other server
+##
event_route[usrloc:contact-expired]
{
+ #!ifdef PRESENCE_ROLE
+ route(PRESENCE_EXPIRED_REGISTRATION);
+ #!endif
+
+ #!ifdef KEEPALIVE_ROLE
+ route(KEEPALIVE_ON_EXPIRED_REGISTRATION);
+ #!endif
+
+ ## return until we handle this in ecallmr
+ xlog("L_INFO", "$ulc(exp=>callid)|expired|removed registration for $ulc(exp=>aor) with contact : $ulc(exp=>addr)\n");
+ return;
+
$var(transport) = $(ulc(exp=>received){uri.transport});
$var(proto) = $(ulc(exp=>socket){re.subst,/^([^:]*):(.*)/\1/});
if($var(proto) == "tls" && $var(transport) == "ws") {
@@ -391,25 +542,25 @@ event_route[usrloc:contact-expired]
{
case "ws":
case "wss":
- if(@cfg_get.kazoo.registrar_handle_expired_ws == 1) {
+ if($sel(cfg_get.kazoo.registrar_handle_expired_ws) == 1) {
$var(handle) = 1;
}
break;
case "tls":
- if(@cfg_get.kazoo.registrar_handle_expired_tls == 1) {
+ if($sel(cfg_get.kazoo.registrar_handle_expired_tls) == 1) {
$var(handle) = 1;
}
break;
case "tcp":
- if(@cfg_get.kazoo.registrar_handle_expired_tcp == 1) {
+ if($sel(cfg_get.kazoo.registrar_handle_expired_tcp) == 1) {
$var(handle) = 1;
}
break;
case "udp":
- if(@cfg_get.kazoo.registrar_handle_expired_udp == 1) {
+ if($sel(cfg_get.kazoo.registrar_handle_expired_udp) == 1) {
$var(handle) = 1;
}
break;
@@ -425,27 +576,9 @@ event_route[usrloc:contact-expired]
$var(amqp_payload_request) = $_s({"Event-Category" : "directory", "Event-Name" : "reg_success", "Status" : "Unregistered", "Event-Timestamp" : $TS, "Expires" : 0, "First-Registration" : false, "Contact" : "$(ulc(exp=>addr){s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ulc(exp=>callid)", "Realm" : "$var(domain)", "Username" : "$var(username)", "From-User" : "$var(username)", "From-Host" : "$var(domain)", "To-User" : "$var(username)", "To-Host" : "$var(domain)", "Proxy-Path" : "$ulc(exp=>socket)", "User-Agent" : "$(ulc(exp=>user_agent){s.escape.common}{s.replace,\','}{s.replace,$$,})"});
$var(amqp_routing_key) = "registration.success." + $(var(domain){kz.encode}) + "." + $(var(username){kz.encode});
kazoo_publish("registrar", $var(amqp_routing_key), $var(amqp_payload_request));
- xlog("L_INFO", "$ulc(exp=>callid)|expired|notified kazoo about removed registration with contact : $ulc(exp=>addr)\n");
- } else {
- xlog("L_INFO", "$ulc(exp=>callid)|expired|removed registration with contact : $ulc(exp=>addr)\n");
+ xlog("L_INFO", "$ulc(exp=>callid)|expired|notified registration removal with contact : $ulc(exp=>addr)\n");
}
-}
-
-route[REGISTRAR_BINDINGS]
-{
- #!import_file "registrar-custom-bindings.cfg"
-
- #!ifndef REGISTRAR_CUSTOM_BINDINGS
-
- $var(payload) = "{ 'exchange' : 'registrar' , 'type' : 'topic', 'queue' : 'registrar-flush-MY_HOSTNAME', 'routing' : 'registration.flush.*', 'federate' : 1 }";
- kazoo_subscribe("$var(payload)");
-
- #!endif
-
- #!ifdef REGISTRAR_SYNC_ROLE
- route(REGISTRAR_SYNC_BINDINGS);
- #!endif
-
+ xlog("L_INFO", "$ulc(exp=>callid)|expired|removed registration for $ulc(exp=>aor) with contact : $ulc(exp=>addr)\n");
}
#!ifdef REGISTRAR_SYNC_ROLE
diff --git a/kamailio/sanity.cfg b/kamailio/sanity.cfg
new file mode 100644
index 0000000..01d323e
--- /dev/null
+++ b/kamailio/sanity.cfg
@@ -0,0 +1,74 @@
+
+#!trydef SANITY_CHECK_USE_PORT 1
+#!trydef SANITY_DROPS_REQUEST 1
+#!trydef SANITY_DEFAULT_CHECK 17895
+#!trydef SANITY_URI_CHECKS 7
+#!trydef SANITY_TRACE_REQUEST 1
+
+#!substdef "!SANITY_SUBST_CACHE_PERIOD!$def(SANITY_CACHE_PERIOD)!g"
+
+######## SIP message formatting sanity checks [requires sl] ########
+loadmodule "sanity.so"
+modparam("sanity", "default_checks", SANITY_DEFAULT_CHECK)
+modparam("sanity", "uri_checks", SANITY_URI_CHECKS)
+modparam("sanity", "autodrop", 0)
+modparam("sanity", "noreply", 1)
+
+modparam("debugger", "mod_level", "sanity=-3")
+
+kazoo.sanity_check_use_port = SANITY_CHECK_USE_PORT descr "should we keep track of ip and port for sanity failures"
+kazoo.sanity_drops_request = SANITY_DROPS_REQUEST descr "should we drop the request or send error on sanity failure"
+kazoo.sanity_trace_request = SANITY_TRACE_REQUEST descr "should we trace the request if sip trace role is enabled"
+
+route[SANITY_CHECK]
+{
+ ## CVE-2018-14767
+ if($(hdr(To)[1]) != $null) {
+ xlog("second To header not null - dropping message");
+ drop;
+ }
+
+ $var(sanity_key) = "";
+ if($sel(cfg_get.kazoo.sanity_check_use_port) == 1) {
+ $var(sanity_key) = $_s("$si::$sp");
+ } else {
+ $var(sanity_key) = $_s("$si");
+ }
+
+ if (!sanity_check()) {
+ #!ifdef SIP_TRACE_ROLE
+ sip_trace();
+ #!endif
+ if($sel(cfg_get.kazoo.sanity_drops_request) == 1) {
+ xlog("L_WARN", "$ci|end|dropping insane message from $si:$sp\n");
+ drop;
+ } else {
+ xlog("L_WARN", "$ci|end|insane message from $si:$sp\n");
+ send_reply("400", "Bad Request");
+ exit;
+ }
+ }
+
+ if (!mf_process_maxfwd_header("10")) {
+ xlog("L_WARN", "$ci|end|too much hops, not enough barley from $si:$sp\n");
+ send_reply("483", "Too Many Hops");
+ exit;
+ }
+
+ if ($ua == "friendly-scanner" ||
+ $ua == "sundayddr" ||
+ $ua == "pplsip" ||
+ $ua =~ "NiceGuy" ||
+ $ua =~ "PortSIP" ||
+ $ua =~ "sipcli" ) {
+ xlog("L_WARN", "$ci|end|dropping message with user-agent $ua from $si:$sp\n");
+ drop;
+ }
+
+ if(sdp_get_line_startswith("$avp(sanity_sline)", "s=")) {
+ if ($avp(sanity_sline) == "s=portsip.com") {
+ xlog("L_WARN", "$ci|end|dropping message with '$avp(sanity_sline)' string in SDP\n");
+ exit;
+ }
+ }
+}
diff --git a/kamailio/sip_trace-role.cfg b/kamailio/sip_trace-role.cfg
index 6fb847b..afae3c7 100644
--- a/kamailio/sip_trace-role.cfg
+++ b/kamailio/sip_trace-role.cfg
@@ -1,11 +1,26 @@
+#################################
+## SIP_TRACE_ROLE Defs
+
+#!trydef KZ_TRACE 0
+#!trydef KZ_TRACE_INTERNAL 1
+#!trydef KZ_TRACE_EXTERNAL 1
+#!trydef KZ_TRACE_LOCAL 1
+#!trydef KZ_TRACE_INTERNAL_INCOMING 1
+#!trydef KZ_TRACE_INTERNAL_OUTGOING 1
+#!trydef KZ_TRACE_EXTERNAL_INCOMING 1
+#!trydef KZ_TRACE_EXTERNAL_OUTGOING 1
+#!trydef SIP_TRACE_URI "sip:127.0.0.1:9060"
+#!trydef HEP_CAPTURE_ID 1
+
##############################################################
-## Kamailio siptrace settings configration examples at runtime
+## Kamailio siptrace settings configuration examples at runtime
## kamcmd siptrace.status on
## kamcmd cfg.seti kazoo trace_external 0
## kamcmd cfg.seti kazoo trace_internal 0
kazoo.trace_external = KZ_TRACE_EXTERNAL descr "activates tracing from external sources"
kazoo.trace_internal = KZ_TRACE_INTERNAL descr "activates tracing from internal sources"
+kazoo.trace_local = KZ_TRACE_LOCAL descr "activates tracing for local requests"
kazoo.trace_internal_incoming = KZ_TRACE_INTERNAL_INCOMING descr "traces the original request as received from internal sources"
kazoo.trace_internal_outgoing = KZ_TRACE_INTERNAL_OUTGOING descr "traces the outgoing request to external sources after possible modification"
@@ -15,7 +30,7 @@ kazoo.trace_external_outgoing = KZ_TRACE_EXTERNAL_OUTGOING descr "traces the out
####### Siptrace module ##########
loadmodule "siptrace.so"
-modparam("siptrace", "duplicate_uri", "SIP_TRACE_URI")
+modparam("siptrace", "duplicate_uri", SIP_TRACE_URI)
modparam("siptrace", "hep_mode_on", 1)
modparam("siptrace", "hep_version", 3)
modparam("siptrace", "hep_capture_id", HEP_CAPTURE_ID)
@@ -26,33 +41,55 @@ modparam("siptrace", "trace_on", KZ_TRACE)
route[SIP_TRACE_INTERNAL]
{
- if(@cfg_get.kazoo.trace_internal == 0) {
+ if($sel(cfg_get.kazoo.trace_internal) == 0) {
return;
}
- if(@cfg_get.kazoo.trace_internal_incoming == 1) {
+ if($sel(cfg_get.kazoo.trace_internal_incoming) == 1) {
sip_trace();
}
- if(@cfg_get.kazoo.trace_internal_outgoing == 1) {
+ if($sel(cfg_get.kazoo.trace_internal_outgoing) == 1) {
setflag(FLAG_SIP_TRACE);
}
}
route[SIP_TRACE_EXTERNAL]
{
- if(@cfg_get.kazoo.trace_external == 0) {
+ if($sel(cfg_get.kazoo.trace_external) == 0) {
return;
}
- if(@cfg_get.kazoo.trace_external_incoming == 1) {
+ if($sel(cfg_get.kazoo.trace_external_incoming) == 1) {
sip_trace();
}
- if(@cfg_get.kazoo.trace_external_outgoing == 1) {
+ if($sel(cfg_get.kazoo.trace_external_outgoing) == 1) {
setflag(FLAG_SIP_TRACE);
}
}
-route[SEND_SIP_TRACE]
+route[SIP_TRACE_LOCAL]
+{
+ if($sel(cfg_get.kazoo.trace_local) == 0) {
+ return;
+ }
+
+ if($hdr(X-TM-Local) != $null) {
+ return;
+ }
+
+ sip_trace();
+}
+
+route[SIP_TRACE_LOCAL_ROUTE]
+{
+ setflag(FLAG_SIP_TRACE);
+}
+
+route[SIP_TRACE]
{
- if (isflagset(FLAG_INTERNALLY_SOURCED)) {
+ if (isflagset(FLAG_LOCAL_ROUTE)) {
+ route(SIP_TRACE_LOCAL_ROUTE);
+ } else if (isflagset(FLAG_LOCAL_REQUEST)) {
+ route(SIP_TRACE_LOCAL);
+ } else if (isflagset(FLAG_INTERNALLY_SOURCED)) {
route(SIP_TRACE_INTERNAL);
} else {
route(SIP_TRACE_EXTERNAL);
diff --git a/kamailio/tls-role.cfg b/kamailio/tls-role.cfg
index b1ea5ba..df6507e 100644
--- a/kamailio/tls-role.cfg
+++ b/kamailio/tls-role.cfg
@@ -6,4 +6,8 @@ listen=TLS_ALG_SIP
####### TLS Parameters #########
loadmodule "tls.so"
modparam("tls", "config", "/etc/kazoo/kamailio/tls.cfg")
-modparam("tls", "low_mem_threshold1", 0)
+modparam("tls", "low_mem_threshold1", 1)
+modparam("tls", "low_mem_threshold2", 1)
+
+modparam("debugger", "mod_level", "tls=1")
+
diff --git a/kamailio/websockets-role.cfg b/kamailio/websockets-role.cfg
index 0f6ee8a..2c8b77b 100644
--- a/kamailio/websockets-role.cfg
+++ b/kamailio/websockets-role.cfg
@@ -1,10 +1,8 @@
tcp_accept_no_cl=yes
listen=TCP_WS
-listen=UDP_WS_SIP
#!ifdef TLS_ROLE
listen=TLS_WSS
-listen=UDP_WSS_SIP
#!endif
######## NAT Traversal module - signaling functions ########
@@ -14,53 +12,37 @@ loadmodule "nathelper.so"
#!endif
######## Generic Hash Table container in shared memory ########
-modparam("htable", "htable", "websockets=>size=16;autoexpire=7200;initval=0")
+modparam("htable", "htable", "websockets=>size=16;initval=0")
######## Basic HTTP request handling ########
loadmodule "xhttp.so"
+
+#!trydef WS_KEEPALIVE_MECHANISM 0
+#!trydef WS_KEEPALIVE_TIMEOUT 30
+#!trydef WS_KEEPALIVE_PROCESSES 3
+#!trydef WS_KEEPALIVE_INTERVAL 1
+#!trydef WS_KEEPALIVE_DATA "Kazoo encourages you to keep alive"
+#!trydef WS_MAX_CONNECTIONS_PER_IP 50
+#!trydef WS_MAX_CONNECTIONS_PER_PROXY 0
+#!trydef WS_ALLOWED_PROXIES "0.0.0.0/0"
+#!trydef WS_CONNECTIONS_FROM_PROXY_ONLY 0
+
######## Websocket module ########
loadmodule "websocket.so"
-modparam("websocket", "keepalive_mechanism", 0)
-modparam("websocket", "keepalive_timeout", 30)
-modparam("websocket", "keepalive_processes", 1)
-modparam("websocket", "keepalive_interval", 1)
-modparam("websocket", "ping_application_data", "Kazoo encourages you to keep alive")
+modparam("websocket", "keepalive_mechanism", WS_KEEPALIVE_MECHANISM)
+modparam("websocket", "keepalive_timeout", WS_KEEPALIVE_TIMEOUT)
+modparam("websocket", "keepalive_processes", WS_KEEPALIVE_PROCESSES)
+modparam("websocket", "keepalive_interval", WS_KEEPALIVE_INTERVAL)
+modparam("websocket", "ping_application_data", WS_KEEPALIVE_DATA)
modparam("websocket", "sub_protocols", 1)
####### Websocket Logic ########
-route[HANDLE_WEBSOCKETS]
-{
- # Do NAT traversal stuff for requests from a WebSocket
- # connection - even if it is not behind a NAT!
- # This won't be needed in the future if Kamailio and the
- # WebSocket client support Outbound and Path.
- if (nat_uac_test(64)) {
- xlog("L_INFO", "$ci|log|this is a websocket request\n");
- force_rport();
- if (is_method("REGISTER")) {
- fix_nated_register();
- } else {
- if (!add_contact_alias()) {
- xlog("L_INFO", "$ci|stop|error aliasing contact <$ct>\n");
- sl_send_reply("400", "Bad Request");
- exit;
- }
- }
- }
-}
-route[NAT_WEBSOCKETS_CORRECT]
-{
- # Do NAT traversal stuff for replies to a WebSocket connection
- # - even if it is not behind a NAT!
- # This won't be needed in the future if Kamailio and the
- # WebSocket client support Outbound and Path.
- if (nat_uac_test(64)) {
- xlog("L_INFO", "$ci|log|this is a websocket request\n");
- add_contact_alias();
- }
-}
+kazoo.ws_allowed_proxies = WS_ALLOWED_PROXIES desc "comma separated list of allowed proxies in cidr notation"
+kazoo.ws_max_connection_per_ip = WS_MAX_CONNECTIONS_PER_IP desc "max connections per ip"
+kazoo.ws_max_connection_per_proxy = WS_MAX_CONNECTIONS_PER_PROXY desc "max connections per proxy"
+kazoo.ws_connections_via_proxy_only = WS_CONNECTIONS_FROM_PROXY_ONLY desc "only allow connections via proxy"
event_route[xhttp:request]
{
@@ -93,21 +75,54 @@ event_route[xhttp:request]
#!ifdef MY_WEBSOCKET_DOMAIN
if (!($hdr(Origin) =~ "MY_WEBSOCKET_DOMAIN")) {
- xlog("L_INFO", "websocket|log|rejecting HTTP request with unknown origin $hdr(Origin) from $si:$sp\n");
+ xlog("L_INFO", "websocket|log|rejecting HTTP request with unauthorized origin $hdr(Origin) from $si:$sp, allowed origin is MY_WEBSOCKET_DOMAIN\n");
xhttp_reply("400", "Bad Request", "", "");
exit;
}
#!endif
- if($sht(websockets=>$si::count) > 50) {
- xlog("L_WARN", "websocket|log|$si:$sp is at the maximum allowable sockets per IP, rejecting request for another websocket\n");
+ if ($hdr(X-Forwarded-For) == $null) {
+ if($sel(cfg_get.kazoo.ws_connections_via_proxy_only) == 1) {
+ xlog("L_INFO", "websocket|log|request from $si without X-Forwarded-For Header and only allowed connections are via proxy\n");
+ xhttp_reply("403", "Forbidden", "", "");
+ exit;
+ } else {
+ $var(ws_orig_ip) = $si;
+ }
+ } else {
+ xlog("L_INFO", "websocket|log|request X-Forwarded-For $hdr(X-Forwarded-For) from $si\n");
+ $var(ws_orig_ip) = $hdr(X-Forwarded-For);
+ }
+
+ if($si != $var(ws_orig_ip)) {
+ if(!is_in_subnet($si, $sel(cfg_get.kazoo.ws_allowed_proxies))) {
+ xlog("L_WARNING", "websocket|log|request X-Forwarded-For $hdr(X-Forwarded-For) from invalid ip $si - allowed $sel(cfg_get.kazoo.ws_allowed_proxies)\n");
+ xhttp_reply("403", "Forbidden", "", "");
+ exit;
+ }
+
+ if($sel(cfg_get.kazoo.ws_max_connection_per_proxy) > 0 && $sht(websockets=>$si::count) > $sel(cfg_get.kazoo.ws_max_connection_per_proxy)) {
+ xlog("L_WARN", "websocket|log|$si is at the maximum $sel(cfg_get.kazoo.ws_max_connection_per_proxy) allowable sockets per PROXY IP, rejecting request for another websocket\n");
+ xhttp_reply("403", "Forbidden", "", "");
+ exit;
+ }
+ }
+
+ if($sel(cfg_get.kazoo.ws_max_connection_per_ip) > 0 && $sht(websockets=>$var(ws_orig_ip)::count) > $sel(cfg_get.kazoo.ws_max_connection_per_ip)) {
+ xlog("L_WARN", "websocket|log|$var(ws_orig_ip) is at the maximum $sel(cfg_get.kazoo.ws_max_connection_per_ip) allowable sockets per IP, rejecting request for another websocket\n");
xhttp_reply("403", "Forbidden", "", "");
exit;
}
if (ws_handle_handshake()) {
- $var(shtinc) = $shtinc(websockets=>$si::count);
- xlog("L_INFO", "websocket|log|opened websocket $var(count) of 50 for $si:$sp\n");
+ $var(count) = $shtinc(websockets=>$var(ws_orig_ip)::count);
+ $sht(websockets=>$ws_conid::ws_orig_ip) = $var(ws_orig_ip);
+ if($si != $var(ws_orig_ip)) {
+ $var(proxy_count) = $shtinc(websockets=>$si::count);
+ xlog("L_INFO", "websocket|log|opened proxied websocket $ws_conid from $si for $var(ws_orig_ip):$sp\n");
+ } else {
+ xlog("L_INFO", "websocket|log|opened websocket $ws_conid from $var(ws_orig_ip):$sp\n");
+ }
exit;
}
@@ -115,12 +130,18 @@ event_route[xhttp:request]
xhttp_reply("404", "Not Found", "", "");
}
-event_route[websocket:closed] {
- $var(shtdec) = $shtdec(websockets=>$si::count);
- if ($sht(websockets=>$si::count) < 1) {
- xlog("L_INFO", "websocket|log|$si:$sp closed last websocket to that IP\n");
- sht_rm_name_re("websockets=>$(si{re.subst,/\\./\\\\./g})::.*");
+event_route[websocket:closed]
+{
+ $var(ws_orig_ip) = $sht(websockets=>$ws_conid::ws_orig_ip);
+ $sht(websockets=>$ws_conid::ws_orig_ip) = $null;
+
+ $var(count) = $shtdec(websockets=>$si::count);
+ if($var(ws_orig_ip) != $null && $si != $var(ws_orig_ip)) {
+ $var(countip) = $shtdec(websockets=>$var(ws_orig_ip)::count);
+ xlog("L_INFO", "websocket|log|$si closed proxied websocket $ws_conid for $var(ws_orig_ip):$sp\n");
+ if ($var(countip) < 1) $sht(websockets=>$var(ws_orig_ip)::count) = $null;
} else {
- xlog("L_INFO", "websocket|log|closed websocket from $si:$sp, $var(count) remaining from that IP\n");
+ xlog("L_INFO", "websocket|log|closed websocket $ws_conid from $var(ws_orig_ip):$sp\n");
}
+ if ($var(count) < 1) $sht(websockets=>$si::count) = $null;
}
diff --git a/system/sbin/kazoo-kamailio b/system/sbin/kazoo-kamailio
index 9fa4e00..23321be 100755
--- a/system/sbin/kazoo-kamailio
+++ b/system/sbin/kazoo-kamailio
@@ -1,20 +1,60 @@
#!/bin/bash
if [ -f /etc/default/kamailio ]; then
- . /etc/default/kamailio
+ . /etc/default/kamailio
fi
if [ -f /etc/sysconfig/kamailio ]; then
- . /etc/sysconfig/kamailio
+ . /etc/sysconfig/kamailio
fi
+if [ -f /etc/kazoo/kamailio/options ]; then
+ . /etc/kazoo/kamailio/options
+fi
+
+is_ipaddress ()
+{
+if [ $(echo $1 | grep -o '\.' | wc -l) -ne 3 ]; then
+ return 1
+elif [ $(echo $1 | tr '.' ' ' | wc -w) -ne 4 ]; then
+ return 1
+else
+ for OCTET in $(echo $1 | tr '.' ' '); do
+ if ! [[ $OCTET =~ ^[0-9]+$ ]]; then
+ return 1
+ elif [[ $OCTET -lt 0 || $OCTET -gt 255 ]]; then
+ return 1
+ fi
+ done
+fi
+return 0
+}
+
RETVAL=1
USER=${KAMAILIO_USER:-kamailio}
-GROUP=${KAMAILIO_GROUP:-kamailio}
+GROUP=${KAMAILIO_GROUP:-daemon}
BIN_FILE=${KAMAILIO_BIN:-/usr/sbin/kamailio}
PID_FILE=${KAMAILIO_PID:-/var/run/kamailio/kazoo-kamailio.pid}
CFG_FILE=${KAMAILIO_CONFIG:-/etc/kazoo/kamailio/kamailio.cfg}
+CFG_DIR=$(dirname ${CFG_FILE})
+export DB_SCRIPT_DIR=${KAMAILIO_DB_SCRIPT_DIR:-${CFG_DIR}/db_scripts}
+export DB_LOCATION=${KAMAILIO_DB_LOCATION:-/etc/kazoo/kamailio/db}
+export KAMAILIO_SHARE_DIR=${KAMAILIO_SHARE_DIR:-/usr/share/kamailio}
export HOME=${KAMAILIO_HOME:-/var/run/kamailio}
+RAM_DISK_SIZE=${RAM_DISK_SIZE:-256m}
+RAM_DISK_FREE_SIZE_PERC=${RAM_DISK_FREE_SIZE:-30}
+RAM_DISK_ENABLED=${RAM_DISK_ENABLED:-false}
+EXTRA_OPTIONS=${EXTRA_OPTIONS:-"-x tlsf -w /tmp"}
+
+MY_LOCAL_IP=$(ip route get 8.8.8.8 2> /dev/null | awk '{print ""$7""; exit}')
+if is_ipaddress ${MY_LOCAL_IP}; then
+ EXTRA_OPTIONS+=" -A MY_LOCAL_IP=${MY_LOCAL_IP}"
+fi
+
+MY_PUBLIC_IP=$(dig @ns1.google.com TXT o-o.myaddr.l.google.com +short -4 2> /dev/null | sed s/\"//g )
+if [[ ! -z ${MY_PUBLIC_IP} ]]; then
+ EXTRA_OPTIONS+=" -A MY_PUBLIC_IP=${MY_PUBLIC_IP}"
+fi
SHM_MEMORY=$((`echo $SHM_MEMORY | sed -e 's/[^0-9]//g'`))
PKG_MEMORY=$((`echo $PKG_MEMORY | sed -e 's/[^0-9]//g'`))
@@ -22,159 +62,244 @@ PKG_MEMORY=$((`echo $PKG_MEMORY | sed -e 's/[^0-9]//g'`))
[ $PKG_MEMORY -le 0 ] && PKG_MEMORY=8
if test "$DUMP_CORE" = "yes" ; then
- ulimit -c unlimited
+ ulimit -c unlimited
fi
prepare() {
- mkdir -p /var/run/kamailio
- chown -R ${USER} /var/run/kamailio
- if [ -e ${PID_FILE} ]; then
- rm -rf ${PID_FILE}
- fi
- if ram_disk_enabled; then
- if ! mount_point_exists; then
- if [ -f /etc/kazoo/kamailio/kazoo.db ]; then
- mv /etc/kazoo/kamailio/db /etc/kazoo/kamailio/db-backup
- fi
- mount -t tmpfs -o size=256m tmpfs /etc/kazoo/kamailio/db
- if [ -f /etc/kazoo/kamailio/db-backup/kazoo.db ]; then
- cp -a /etc/kazoo/kamailio/db-backup/* /etc/kazoo/kamailio/db/
- fi
- fi
- fi
- if [ ! -f /etc/kazoo/kamailio/db/kazoo.db ]; then
+ mkdir -p /var/run/kamailio
+ chown -R ${USER} /var/run/kamailio
+ if [ -e ${PID_FILE} ]; then
+ rm -rf ${PID_FILE}
+ fi
+ if ram_disk_enabled; then
+ if ! mount_point_exists; then
+ if [ -d ${DB_LOCATION}/../db-backup-temp ]; then
+ rm -rf ${DB_LOCATION}/../db-backup-temp
+ fi
+ if [ -d ${DB_LOCATION} ]; then
+ mkdir -p ${DB_LOCATION}/../db-backup-temp
+ cp -f ${DB_LOCATION}/* ${DB_LOCATION}/../db-backup-temp/
+ rm -rf ${DB_LOCATION}
+ fi
+ mkdir -p ${DB_LOCATION}
+ mount -t tmpfs -o size=${RAM_DISK_SIZE} tmpfs ${DB_LOCATION}
+ if [ -f ${DB_LOCATION}/../db-backup-temp/kazoo.db ]; then
+ cp -f ${DB_LOCATION}/../db-backup-temp/* ${DB_LOCATION}/
+ fi
+ if [ -d ${DB_LOCATION}/../db-backup-temp ]; then
+ rm -rf ${DB_LOCATION}/../db-backup-temp
+ fi
+ else
+ ### check ramdisk size
+ mountcurrentsize=$(mount_point_size)
+ mountwantedsize=$(convert_size ${RAM_DISK_SIZE})
+ if [ $mountcurrentsize -lt $mountwantedsize ]; then
+ echo "current size is $mountcurrentsize is below wanted size of $mountwantedsize, remounting"
+ rm -rf ${DB_LOCATION}/../db-backup-temp
+ mkdir -p ${DB_LOCATION}/../db-backup-temp
+ cp -f ${DB_LOCATION}/* ${DB_LOCATION}/../db-backup-temp/
+ umount ${DB_LOCATION}
+ rm -rf ${DB_LOCATION}
+ mkdir -p ${DB_LOCATION}
+ mount -t tmpfs -o size=${RAM_DISK_SIZE} tmpfs ${DB_LOCATION}
+ cp -f ${DB_LOCATION}/../db-backup-temp/* ${DB_LOCATION}/
+ rm -rf ${DB_LOCATION}/../db-backup-temp
+ elif [ $mountcurrentsize -gt $mountwantedsize ]; then
+ # check if it fits
+ echo "wanted size of $mountwantedsize is below current size of $mountcurrentsize , checking sizes"
+ mountusedsize=$(mount_point_used_size)
+ requiredsize=$(( mountusedsize * (100 + ${RAM_DISK_FREE_SIZE_PERC}) / 100))
+ if [ $requiredsize -gt $mountwantedsize ]; then
+ echo "wanted size of $mountwantedsize doesn't have enough space for required size of $requiredsize"
+ mountwantedsize=$requiredsize
+ else
+ echo "resizing from $mountcurrentsize to $mountwantedsize"
+ rm -rf ${DB_LOCATION}/../db-backup-temp
+ mkdir -p ${DB_LOCATION}/../db-backup-temp
+ cp -f ${DB_LOCATION}/* ${DB_LOCATION}/../db-backup-temp/
+ umount ${DB_LOCATION}
+ rm -rf ${DB_LOCATION}
+ mkdir -p ${DB_LOCATION}
+ mount -t tmpfs -o size=$mountwantedsize tmpfs ${DB_LOCATION}
+ cp -f ${DB_LOCATION}/../db-backup-temp/* ${DB_LOCATION}/
+ rm -rf ${DB_LOCATION}/../db-backup-temp
+ fi
+ fi
+ fi
+ else
+ if mount_point_exists; then
+ if [ -d ${DB_LOCATION}/../db-backup-temp ]; then
+ rm -rf ${DB_LOCATION}/../db-backup-temp
+ fi
+ mkdir -p ${DB_LOCATION}/../db-backup-temp
+ cp -f ${DB_LOCATION}/* ${DB_LOCATION}/../db-backup-temp/
+ umount ${DB_LOCATION}
+ rm -rf ${DB_LOCATION}
+ mkdir -p ${DB_LOCATION}
+ cp -f ${DB_LOCATION}/../db-backup-temp/* ${DB_LOCATION}/
+ fi
+ fi
+ if [ ! -f ${DB_LOCATION}/kazoo.db ]; then
init_database
- fi
- chown -R ${USER} /etc/kazoo/kamailio/db
- RETVAL=$?
+ else
+ check_database
+ fi
+ chown -R ${USER} ${DB_LOCATION}
+ RETVAL=$?
}
ram_disk_enabled() {
- grep -e "enable_ram_disk = true" /etc/kazoo/kamailio/local.cfg &> /dev/null
- return $?
+
+ grep -e "enable_ram_disk = true" ${CFG_DIR}/local.cfg &> /dev/null
+ config_enabled=$?
+ if [[ $RAM_DISK_ENABLED == "true" ]] || [[ $config_enabled -eq 0 ]]; then
+ return 0
+ else
+ return 1
+ fi
}
mount_point_exists() {
- mount | grep /etc/kazoo/kamailio/db &> /dev/null
- return $?
+ mount | grep $(readlink -f ${DB_LOCATION}) &> /dev/null
+ return $?
+}
+
+mount_point_size() {
+ echo $(df --block-size=1 | grep $(readlink -f ${DB_LOCATION}) | tr -s ' ' | cut -d ' ' --fields=2)
+}
+
+mount_point_used_size() {
+ echo $(df --block-size=1 | grep $(readlink -f ${DB_LOCATION}) | tr -s ' ' | cut -d ' ' --fields=3)
+}
+
+mount_point_free_size() {
+ echo $(df --block-size=1 | grep $(readlink -f ${DB_LOCATION}) | tr -s ' ' | cut -d ' ' --fields=4)
+}
+
+convert_size() {
+ echo "$1" | awk \
+ 'BEGIN{IGNORECASE = 1}
+ function printpower(n,b,p) {printf "%u\n", n*b^p; next}
+ /[0-9]$/{print $1;next};
+ /K(iB)?$/{printpower($1, 2, 10)};
+ /M(iB)?$/{printpower($1, 2, 20)};
+ /G(iB)?$/{printpower($1, 2, 30)};
+ /T(iB)?$/{printpower($1, 2, 40)};
+ /KB$/{ printpower($1, 10, 3)};
+ /MB$/{ printpower($1, 10, 6)};
+ /GB$/{ printpower($1, 10, 9)};
+ /TB$/{ printpower($1, 10, 12)}'
}
init_database() {
- /etc/kazoo/kamailio/db_scripts/create-kazoodb-sql.sh
+ ${DB_SCRIPT_DIR}/create-kazoodb-sql.sh
+ check_database
}
+check_database() {
+ ${DB_SCRIPT_DIR}/check-kazoodb-sql.sh
+}
start() {
- cd ${HOME}
+ cd ${HOME}
- check_config
- check_fork
+ check_config
+ check_fork
- if [ "$(whoami)" == "${USER}" ]; then
- set -- ${BIN_FILE} -f ${CFG_FILE} -m ${SHM_MEMORY} -M ${PKG_MEMORY} ${EXTRA_OPTIONS} "$@"
- exec "$@"
- else
- set -- ${BIN_FILE} -f ${CFG_FILE} -m ${SHM_MEMORY} -M ${PKG_MEMORY} -u ${USER} -g ${GROUP} ${EXTRA_OPTIONS} "$@"
- runuser -s /bin/bash ${USER} -c "$*"
- fi
- RETVAL=$?
+ if [ "$(whoami)" == "${USER}" ]; then
+ set -- ${BIN_FILE} -f ${CFG_FILE} -m ${SHM_MEMORY} -M ${PKG_MEMORY} ${EXTRA_OPTIONS} "$@"
+ exec "$@"
+ else
+ set -- ${BIN_FILE} -f ${CFG_FILE} -m ${SHM_MEMORY} -M ${PKG_MEMORY} -u ${USER} -g ${GROUP} ${EXTRA_OPTIONS} "$@"
+ runuser -s /bin/bash ${USER} -c "$*"
+ fi
+ RETVAL=$?
- if [ ${RETVAL} -ne 0 ]; then
- echo "Failed to start Kamailio!"
- RETVAL=1
- fi
+ if [ ${RETVAL} -ne 0 ]; then
+ echo "Failed to start Kamailio!"
+ RETVAL=1
+ fi
}
stop() {
- killall ${BIN_FILE}
- RETVAL=$?
- if mount_point_exists; then
- if [ -f /etc/kazoo/kamailio/kazoo.db ]; then
- mv /etc/kazoo/kamailio/db /etc/kazoo/kamailio/db-backup
- fi
- fi
+ kamcmd core.kill
+ RETVAL=$?
+ if mount_point_exists; then
+ mkdir -p ${DB_LOCATION}/../db-backup
+ cp -f ${DB_LOCATION}/* ${DB_LOCATION}/../db-backup/
+ fi
}
restart() {
- stop
- start
+ stop
+ start
}
reset-restart() {
- cd /etc/kazoo/kamailio/dbtext/
- stop
-
- head -n1 active_watchers > active_watchers.tmp
- mv -f active_watchers.tmp active_watchers
-
- head -n1 watchers > watchers.tmp
- mv -f watchers.tmp watchers
+ cd /etc/kazoo/kamailio/dbtext/
+ stop
- head -n1 presentity > presentity.tmp
- mv -f presentity.tmp presentity
+ chown kamailio:daemon *
- chown kamailio:daemon *
-
- start
+ start
}
status() {
- kamcmd dispatcher.list
- RETVAL=$?
+ kamcmd dispatcher.list
+ RETVAL=$?
}
# Do not start kamailio if fork=no is set in the config file
# otherwise the boot process will just stop
check_fork ()
{
- if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFG_FILE; then
- echo "WARNING: fork=no specified in config file"
- exit 1
- fi
+ if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFG_FILE; then
+ echo "WARNING: fork=no specified in config file"
+ exit 1
+ fi
}
check_config ()
{
- local ERRORS=$($BIN_FILE -c -f ${CFG_FILE} 2>&1 > /dev/null)
- RETVAL=$?
-
- if [ ${RETVAL} -ne 0 ]; then
- echo "ERROR: Invalid configuration file ${CFG_FILE}!"
- echo -e "\n${ERRORS}\n"
- else
- echo "No errors found in ${CFG_FILE}"
- fi
+ ERRORS="$($BIN_FILE -c -f ${CFG_FILE} -x tlsf 2>&1 > /dev/null)"
+ RETVAL=$?
+ if [ ${RETVAL} -ne 0 ]; then
+ echo "ERROR: Invalid configuration file ${CFG_FILE}!"
+ echo -e "\n${ERRORS}\n"
+ else
+ echo "No errors found in ${CFG_FILE}"
+ fi
}
case "$1" in
- prepare)
- prepare
- ;;
- background)
- shift
- start $@
- ;;
- start)
- shift
- start -DD $@
- ;;
- stop)
- stop
- ;;
- restart)
- restart
- ;;
- reset-restart)
- reset-restart
- ;;
- status)
- status
- ;;
- check)
- check_config
- ;;
- *)
- echo $"Usage: $0 {prepare|start|background|stop|restart|reset-restart|status|check|pid}"
+ prepare)
+ prepare
+ ;;
+ background)
+ shift
+ start $@
+ ;;
+ start)
+ shift
+ start -DD $@
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ restart
+ ;;
+ reset-restart)
+ reset-restart
+ ;;
+ status)
+ status
+ ;;
+ check)
+ check_config
+ ;;
+ *)
+ echo $"Usage: $0 {prepare|start|background|stop|restart|reset-restart|status|check|pid}"
esac
exit ${RETVAL}