######## Generic Hash Table container in shared memory ########
|
|
modparam("htable", "htable", "failover=>size=16;autoexpire=120")
|
|
|
|
kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr"
|
|
|
|
####### Dispatcher module ########
|
|
loadmodule "dispatcher.so"
|
|
modparam("dispatcher", "db_url", "KAZOO_DB_URL")
|
|
modparam("dispatcher", "flags", 2)
|
|
modparam("dispatcher", "use_default", 0)
|
|
modparam("dispatcher", "force_dst", 1)
|
|
modparam("dispatcher", "dst_avp", "$avp(ds_dst)")
|
|
modparam("dispatcher", "attrs_avp", "$avp(ds_attrs)")
|
|
modparam("dispatcher", "grp_avp", "$avp(ds_grp)")
|
|
modparam("dispatcher", "cnt_avp", "$avp(ds_cnt)")
|
|
modparam("dispatcher", "hash_pvar", "$avp(ds_grp)")
|
|
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_ping_reply_codes", "501,403,404,400,200")
|
|
modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME")
|
|
|
|
|
|
## Dispatcher Groups:
|
|
## 1 - Primary media servers
|
|
## 2 - Backup media servers
|
|
## 3 - Alternate media server IPs (used only for classification)
|
|
## 10 - Presence servers (if not locally handled)
|
|
## 20 - Registrar servers (if not locally handled)
|
|
|
|
####### Dispatcher Logic ########
|
|
route[DISPATCHER_CLASSIFY_SOURCE]
|
|
{
|
|
if (is_myself("$ou")) {
|
|
xlog("L_INFO", "$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)
|
|
) {
|
|
xlog("L_INFO", "$ci|log|originated from internal sources\n");
|
|
|
|
setflag(FLAG_INTERNALLY_SOURCED);
|
|
} else {
|
|
xlog("L_INFO", "$ci|log|originated from external sources\n");
|
|
}
|
|
}
|
|
|
|
# Take the routes from dispatcher - hash over callid
|
|
# If prefered route defined, reorder the destionations
|
|
route[DISPATCHER_FIND_ROUTES]
|
|
{
|
|
if ($sht(failover=>$ci::current) != $null) {
|
|
$du = $sht(failover=>$ci::current);
|
|
return;
|
|
}
|
|
|
|
$var(ds_group) = 1;
|
|
|
|
#!ifndef PRESENCE_ROLE
|
|
if (is_method("SUBSCRIBE")) {
|
|
$var(ds_group) = 10;
|
|
}
|
|
#!endif
|
|
|
|
#!ifndef REGISTRAR_ROLE
|
|
if (is_method("REGISTER")) {
|
|
$var(ds_group) = 20;
|
|
}
|
|
#!endif
|
|
|
|
#!ifdef FAST_PICKUP_ROLE
|
|
route(FAST_PICKUP_ATTEMPT);
|
|
#!endif
|
|
|
|
if (!ds_select_dst("$var(ds_group)", "0") || $(avp(ds_dst)[0]) == $null) {
|
|
# if we selected from group 1, try again in group 2
|
|
if ($var(ds_group) == 1) {
|
|
if (!ds_select_dst("2", "0")) {
|
|
xlog("L_WARN", "$ci|end|no servers available in group 1 or 2\n");
|
|
sl_send_reply("480", "All servers busy");
|
|
exit;
|
|
}
|
|
} else {
|
|
xlog("L_INFO", "$ci|end|no servers available in group $var(ds_group)\n");
|
|
sl_send_reply("480", "All servers busy");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
$var(contact_uri) = $(ct{tobody.user}) + "@" + $(ct{tobody.host});
|
|
$var(redirect) = @from.uri.user + "@" + @from.uri.host + "->"
|
|
+ @ruri.user + "@" + @ruri.host;
|
|
if ($sht(redirects=>$var(redirect)) != $null) {
|
|
$var(prefered_route) = $sht(redirects=>$var(redirect));
|
|
xlog("L_INFO", "$ci|log|found redirect for $var(redirect)\n");
|
|
if (route(DISPATCHER_REORDER_ROUTES)) {
|
|
$avp(AVP_REDIRECT_KEY) = $var(redirect);
|
|
}
|
|
} else if ($sht(associations=>$var(contact_uri)) != $null) {
|
|
$var(prefered_route) = $sht(associations=>$var(contact_uri));
|
|
xlog("L_INFO", "$ci|log|found association for contact uri $var(contact_uri)\n");
|
|
if (!route(DISPATCHER_REORDER_ROUTES)) {
|
|
$sht(associations=>$var(association)) = $null;
|
|
}
|
|
}
|
|
}
|
|
|
|
route[DISPATCHER_REORDER_ROUTES]
|
|
{
|
|
$var(i) = 0;
|
|
$var(found) = 0;
|
|
while($(avp(ds_dst)[$var(i)]) != $null) {
|
|
if($(avp(ds_dst)[$var(i)]) != $var(prefered_route)) {
|
|
$avp(tmp_ds_dst) = $(avp(ds_dst)[$var(i)]);
|
|
} else {
|
|
$var(found) = 1;
|
|
}
|
|
|
|
$var(i) = $var(i) + 1;
|
|
}
|
|
|
|
if (!$var(found) && $var(ds_group) == 1 && ds_select_dst("2", "0")) {
|
|
$var(i) = 0;
|
|
while($(avp(ds_dst)[$var(i)]) != $null) {
|
|
if($(avp(ds_dst)[$var(i)]) == $var(prefered_route)) {
|
|
xlog("L_INFO", "$ci|log|found associated media server in backup list\n");
|
|
$var(found) = 1;
|
|
break;
|
|
}
|
|
$var(i) = $var(i) + 1;
|
|
}
|
|
}
|
|
|
|
if ($var(found)) {
|
|
xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n");
|
|
|
|
$(avp(ds_dst)[*]) = $null;
|
|
|
|
$var(i) = 0;
|
|
while($(avp(tmp_ds_dst)[$var(i)]) != $null) {
|
|
$avp(ds_dst) = $(avp(tmp_ds_dst)[$var(i)]);
|
|
|
|
$var(i) = $var(i) + 1;
|
|
}
|
|
$avp(ds_dst) = $var(prefered_route);
|
|
$du = $var(prefered_route);
|
|
|
|
$(avp(tmp_ds_dst)[*]) = $null;
|
|
} else {
|
|
xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $rd\n");
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
route[DISPATCHER_NEXT_ROUTE]
|
|
{
|
|
$var(failover_count) = $sht(failover=>$ci::counts);
|
|
|
|
if ($sht(failover=>$ci::counts) == $null) {
|
|
$var(i) = 0;
|
|
while($(avp(ds_dst)[$var(i)]) != $null) {
|
|
$sht(failover=>$ci[$var(i)]) = $(avp(ds_dst)[$var(i)]);
|
|
$var(i) = $var(i) + 1;
|
|
if ($var(i) >= 3) {
|
|
break;
|
|
}
|
|
}
|
|
$sht(failover=>$ci::counts) = $var(i);
|
|
$var(failover_count) = $var(i);
|
|
}
|
|
|
|
# try to find a new media server to send the call to
|
|
if ($var(failover_count) > 1) {
|
|
$var(failover_count) = $var(failover_count) - 1;
|
|
|
|
$du = $sht(failover=>$ci[$var(failover_count)]);
|
|
$sht(failover=>$ci::counts) = $var(failover_count);
|
|
$sht(failover=>$ci::current) = $du;
|
|
|
|
xlog("L_INFO", "$ci|log|remaining failed retry attempts: $var(failover_count)\n");
|
|
xlog("L_INFO", "$ci|log|routing call to next media server $du\n");
|
|
|
|
setflag(FLAG_SKIP_NAT_CORRECTION);
|
|
|
|
# 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);
|
|
|
|
exit();
|
|
}
|
|
}
|
|
|
|
event_route[dispatcher:dst-down]
|
|
{
|
|
xlog("L_ERR", "Destination down: $ru\n");
|
|
}
|
|
|
|
event_route[dispatcher:dst-up]
|
|
{
|
|
xlog("L_WARNING", "Destination up: $ru\n");
|
|
}
|
|
|
|
|
|
route[DISPATCHER_CHECK_MEDIA_SERVER]
|
|
{
|
|
if(@cfg_get.kazoo.dispatcher_auto_add == 1) {
|
|
$var(SetId) = 1;
|
|
if($var(Zone) != "MY_AMQP_ZONE") {
|
|
$var(SetId) = 2;
|
|
}
|
|
sql_query("exec", "DISPATCHER_CHECK_MEDIA_SERVER_INSERT_QUERY");
|
|
if($sqlrows(exec) > 0) {
|
|
xlog("L_WARNING", "reloading dispatcher table\n");
|
|
ds_reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
route[DISPATCHER_SUMMARY]
|
|
{
|
|
$var(ds_groups_json) = "";
|
|
if (sql_xquery("cb", "select * from dispatcher order by setid, id", "ra") == 1)
|
|
{
|
|
$var(Sep1) = "";
|
|
while($xavp(ra) != $null) {
|
|
$var(ds_group) = $xavp(ra=>setid);
|
|
$var(Sep2)="";
|
|
$var(ds_group_json)="";
|
|
while($xavp(ra) != $null && $var(ds_group) == $xavp(ra=>setid) )
|
|
{
|
|
$var(record) = $_s("$xavp(ra=>id)" : {"destination" : "$xavp(ra=>destination)", "flags" : "$xavp(ra=>flags)", "priority" : $xavp(ra=>priority), "attrs" : "$xavp(ra=>attrs)" , "description" : "$xavp(ra=>description)"});
|
|
$var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record);
|
|
$var(Sep2) = ",";
|
|
pv_unset("$xavp(ra)");
|
|
}
|
|
$var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$var(ds_group)" : { $var(ds_group_json) });
|
|
$var(Sep1)=", ";
|
|
}
|
|
}
|
|
}
|
|
|
|
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
|