######## Generic Hash Table container in shared memory ######## modparam("htable", "htable", "failover=>size=16;autoexpire=120") ####### Dispatcher module ######## loadmodule "dispatcher.so" modparam("dispatcher", "list_file", "/etc/kazoo/kamailio/dbtext/dispatcher") 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_pvar", "$var(setid)") modparam("dispatcher", "ds_ping_method", "OPTIONS") modparam("dispatcher", "ds_ping_interval", 10) modparam("dispatcher", "ds_probing_threshhold", 3) modparam("dispatcher", "ds_probing_mode", 1) modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") ## 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 (ds_is_from_list("1", "1") || ds_is_from_list("2", "1") || ds_is_from_list("3", "1") || ds_is_from_list("10", "1") || ds_is_from_list("20", "1")) { xlog("L_INFO", "$ci|log|originated from internal sources"); setflag(FLAG_INTERNALLY_SOURCED); } else { xlog("L_INFO", "$ci|log|originated from external sources"); } } # 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 if (!ds_select_dst("$var(ds_group)", "0")) { # 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 avaliable in group 1 or 2"); sl_send_reply("480", "All servers busy"); exit; } } else { xlog("L_INFO", "$ci|end|no servers avaliable in group $var(ds_group)"); sl_send_reply("480", "All servers busy"); exit; } } else { # if we selected from group 1 and there are less than 3 available servers, choose from group 2 if ($var(ds_group) == 1 && $var(ds_cnt)< 3) { # clear $avp(ds_dst) and search in group 2 $(avp(ds_dst)[*]) = $null; if (!ds_select_dst("2", "0")) { xlog("L_ERR", "$ci|end|no servers avaliable in group 2"); sl_send_reply("480", "All servers busy"); exit; } } } $var(contact_uri) = $(ct{tobody.user}) + "@" + $(ct{tobody.host}); $var(from_uri) = @from.uri.user + "@" + @from.uri.host; if ($sht(associations=>$var(from_uri)) != $null) { $var(association) = $var(from_uri); $var(prefered_route) = $sht(associations=>$var(association)); xlog("L_INFO", "$ci|log|from uri $var(from_uri) associated with media server $var(prefered_route)"); route(DISPATCHER_REORDER_ROUTES); } else if ($sht(associations=>$var(contact_uri)) != $null) { $var(association) = $var(contact_uri); $var(prefered_route) = $sht(associations=>$var(association)); xlog("L_INFO", "$ci|log|contact uri $var(contact_uri) associated with media server $var(prefered_route)"); route(DISPATCHER_REORDER_ROUTES); } } 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)) { xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to keep associated server first"); $(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 is inactive, moving to $rd"); $sht(associations=>$var(association)) = $null; } } 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)"); xlog("L_INFO", "$ci|log|routing call to next media server $du"); 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(); } } # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab