#### Preprocessor Directives #########
|
|
#!define L_ALERT -5
|
|
#!define L_BUG -4
|
|
#!define L_CRIT2 -3
|
|
#!define L_CRIT -2
|
|
#!define L_ERR -1
|
|
#!define L_WARN 0
|
|
#!define L_NOTICE 1
|
|
#!define L_INFO 2
|
|
#!define L_DBG 3
|
|
|
|
#!define AVP_RECV_PARAM "recv_param"
|
|
#!define AVP_LOG_LEVEL "log_level"
|
|
#!define AVP_ROUTE_CNT "route_cnt"
|
|
#!define AVP_ASSOCIATED_SERVER "associated_server"
|
|
#!define AVP_ASSOCIATE_CONTACT "associate_contact"
|
|
|
|
####### Global Parameters #########
|
|
fork = yes
|
|
children = 25
|
|
group = kamailio
|
|
user = kamailio
|
|
server_signature = no
|
|
server_header = "Server: Kazoo"
|
|
user_agent_header = "User-Agent: Kazoo"
|
|
shm_force_alloc = yes
|
|
mlock_pages = yes
|
|
phone2tel = 1
|
|
max_while_loops = 500
|
|
|
|
####### Logging Parameters #########
|
|
debug = L_INFO
|
|
memdbg = 10
|
|
memlog = 10
|
|
corelog = L_ERR
|
|
log_stderror = no
|
|
log_facility = LOG_LOCAL0
|
|
log_name="kamailio"
|
|
|
|
####### Alias Parameters #########
|
|
auto_aliases = yes
|
|
# alias = "mydomain.net"
|
|
|
|
####### Binding Parameters #########
|
|
listen = tcp:127.0.0.1:5060
|
|
listen = udp:127.0.0.1:5060
|
|
listen = tcp:127.0.0.1:5080
|
|
listen = udp:127.0.0.1:5080
|
|
listen = tcp:127.0.0.1:7000
|
|
listen = udp:127.0.0.1:7000
|
|
tos = IPTOS_LOWDELAY
|
|
|
|
####### TCP Parameters #########
|
|
tcp_children = 25
|
|
disable_tcp = no
|
|
tcp_max_connections = 4096
|
|
tcp_connection_lifetime = 3605
|
|
tcp_accept_aliases = no
|
|
tcp_async = yes
|
|
tcp_connect_timeout = 10
|
|
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_linger2 = 30
|
|
tcp_rd_buf_size = 4096
|
|
tcp_send_timeout = 10
|
|
tcp_wq_blk_size = 2100
|
|
tcp_wq_max = 10485760
|
|
|
|
####### UDP Parameters #########
|
|
udp4_raw = -1
|
|
udp4_raw_mtu = 1500
|
|
|
|
####### DNS Parameters #########
|
|
dns = no
|
|
rev_dns = no
|
|
dns_try_ipv6 = no
|
|
use_dns_cache = on
|
|
dns_cache_del_nonexp = no
|
|
dns_cache_flags = 1
|
|
dns_cache_gc_interval = 120
|
|
dns_cache_init = 1
|
|
dns_cache_mem = 1000
|
|
dns_cache_negative_ttl = 60
|
|
dns_try_naptr = no
|
|
use_dns_failover = off
|
|
dns_srv_lb = off
|
|
|
|
####### TLS Parameters #########
|
|
enable_tls = yes
|
|
|
|
####### SCTP Parameters #########
|
|
disable_sctp = yes
|
|
|
|
####### Custom Parameters #########
|
|
|
|
|
|
####### Modules Section ########
|
|
mpath="/usr/lib64/kamailio/modules/"
|
|
|
|
####### Flags #######
|
|
flags
|
|
FLAG_INTERNALLY_SOURCED: 1,
|
|
FLAG_ASSOCIATE_SERVER: 2,
|
|
FLAG_SKIP_NAT_CORRECTION: 3,
|
|
FLAG_ASSOCIATE_USER: 4;
|
|
|
|
#!define FLB_NATB 6
|
|
#!define FLB_NATSIPPING 7
|
|
|
|
# ----- presence
|
|
loadmodule "pua_dialoginfo.so"
|
|
modparam("pua_dialoginfo", "library_mode", 1)
|
|
|
|
# TODO: ARE THESE NECESSARY
|
|
loadmodule "corex.so"
|
|
# loadmodule "ctl.so"
|
|
loadmodule "cfg_rpc.so"
|
|
loadmodule "mi_rpc.so"
|
|
|
|
######## Kamailio core extensions module ########
|
|
loadmodule "kex.so"
|
|
|
|
######## Transaction (stateful) module ########
|
|
loadmodule "tm.so"
|
|
loadmodule "tmx.so"
|
|
modparam("tm", "auto_inv_100", 1)
|
|
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", "fr_timer", 30000)
|
|
# modparam("tm", "fr_inv_timer", 120000)
|
|
|
|
######## Stateless replier module ########
|
|
loadmodule "sl.so"
|
|
|
|
######## Record-Route and Route module ########
|
|
loadmodule "rr.so"
|
|
modparam("rr", "enable_full_lr", 1)
|
|
|
|
######## Max-Forward processor module ########
|
|
loadmodule "maxfwd.so"
|
|
|
|
######## SIP utilities [requires sl] ########
|
|
loadmodule "siputils.so"
|
|
|
|
######## SIP message formatting sanity checks [requires sl] ########
|
|
loadmodule "sanity.so"
|
|
# sip_version, scheme, req_headers, cseq_method/value
|
|
# content_length, parse_uri, digest
|
|
modparam("sanity", "default_checks", 3303)
|
|
modparam("sanity", "uri_checks", 3)
|
|
modparam("sanity", "autodrop", 0)
|
|
|
|
######## Text operations module ########
|
|
loadmodule "textops.so"
|
|
loadmodule "textopsx.so"
|
|
|
|
######## Path support for SIP loadbalancer ########
|
|
loadmodule "path.so"
|
|
modparam("path", "use_received", 0)
|
|
|
|
######## Generic Hash Table container in shared memory ########
|
|
loadmodule "htable.so"
|
|
modparam("htable", "htable", "associations=>size=10;")
|
|
modparam("htable", "htable", "auth_cache=>size=10;")
|
|
|
|
# TODO: IS THIS NECESSARY
|
|
modparam("htable", "htable", "dbkp=>size=4;autoexpire=7200")
|
|
|
|
######## Pseudo-Variables module ########
|
|
loadmodule "pv.so"
|
|
|
|
######## Advanced logger module ########
|
|
loadmodule "xlog.so"
|
|
|
|
####### FIFO support for Management Interface ########
|
|
loadmodule "mi_fifo.so"
|
|
modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
|
|
|
|
####### Dispatcher module ########
|
|
loadmodule "dispatcher.so"
|
|
modparam("dispatcher", "list_file", "/etc/kazoo/kamailio/dispatcher.list")
|
|
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_from", "sip:sipcheck@127.0.0.1")
|
|
modparam("dispatcher", "ds_ping_interval", 10)
|
|
# modparam("dispatcher", "ds_ping_sock", "udp:{{SIP_IP}}:{{SIP_PORT}}")
|
|
modparam("dispatcher", "ds_probing_threshhold", 3)
|
|
modparam("dispatcher", "ds_probing_mode", 1)
|
|
modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200")
|
|
|
|
######## UAC Redirection module ########
|
|
loadmodule "uac_redirect.so"
|
|
|
|
####### Kazoo Integration module ##########
|
|
loadmodule "db_kazoo.so"
|
|
# FIXME: uncomment the next line and set the correct hostname that should be advertised to Kazoo
|
|
modparam("db_kazoo", "node_hostname", "kamailio.2600hz.com")
|
|
# If you want a certain fs_path to be sent Kazoo, uncomment the next line and set the right value
|
|
#modparam("db_kazoo", "register_fs_path", "127.0.0.1:5060")
|
|
|
|
####### Authentication Interface module ##########
|
|
loadmodule "auth.so"
|
|
loadmodule "auth_db.so"
|
|
modparam("auth_db", "use_domain", 1)
|
|
modparam("auth_db", "version_table", 0)
|
|
modparam("auth_db", "calculate_ha1", 1)
|
|
modparam("auth_db", "password_column", "password")
|
|
modparam("auth_db", "load_credentials", "$avp(password)=password")
|
|
|
|
####### User Location Implementation module ##########
|
|
loadmodule "usrloc.so"
|
|
modparam("usrloc", "db_mode", 1)
|
|
modparam("usrloc", "db_update_as_insert", 1)
|
|
modparam("usrloc", "use_domain", 1)
|
|
modparam("usrloc", "nat_bflag", FLB_NATB)
|
|
|
|
####### SIP Registrar implementation module ##########
|
|
loadmodule "registrar.so"
|
|
|
|
######## NAT Traversal module - signaling functions ########
|
|
loadmodule "nathelper.so"
|
|
modparam("nathelper|registrar", "received_avp", "$avp(AVP_RECV_PARAM)")
|
|
modparam("nathelper", "natping_interval", 30)
|
|
modparam("nathelper", "ping_nated_only", 1)
|
|
modparam("nathelper", "natping_processes", 5)
|
|
modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
|
|
modparam("nathelper", "sipping_from", "sip:sipcheck@127.0.0.1")
|
|
#modparam("nathelper", "natping_socket", "127.0.0.1:5060")
|
|
|
|
# ----- presence params -----
|
|
loadmodule "presence.so"
|
|
loadmodule "presence_dialoginfo.so"
|
|
modparam("presence", "subs_db_mode", 1)
|
|
modparam("presence", "db_url", "kazoo://guest:guest@127.0.0.1:5672/dialoginfo")
|
|
|
|
####### Common Module Parameters ##########
|
|
modparam("auth_db|usrloc", "db_url", "kazoo://guest:guest@127.0.0.1:5672/callmgr")
|
|
|
|
|
|
####### Routing Logic ########
|
|
route
|
|
{
|
|
# log the basic info regarding this call
|
|
xlog("L_INFO", "$ci|start|recieved $oP request $rm $ou");
|
|
xlog("L_INFO", "$ci|log|source $si:$sp");
|
|
xlog("L_INFO", "$ci|log|from $fu");
|
|
xlog("L_INFO", "$ci|log|to $tu");
|
|
|
|
route(SANITY_CHECK);
|
|
|
|
route(CLASSIFY_SOURCE);
|
|
|
|
route(HANDLE_OPTIONS);
|
|
|
|
route(HANDLE_IN_DIALOG_REQUESTS);
|
|
|
|
route(HANDLE_PRESENCE);
|
|
|
|
route(PREPARE_INITIAL_REQUESTS);
|
|
|
|
if (isflagset(FLAG_INTERNALLY_SOURCED)) {
|
|
route(INTERNAL_TO_EXTERNAL_RELAY);
|
|
exit();
|
|
}
|
|
|
|
route(HANDLE_MOVE_REQUEST);
|
|
|
|
route(FIND_ROUTES);
|
|
|
|
$avp(route_attempts) = 1;
|
|
route(EXTERNAL_TO_INTERNAL_RELAY);
|
|
}
|
|
|
|
route[SANITY_CHECK]
|
|
{
|
|
if (!mf_process_maxfwd_header("10")) {
|
|
xlog("L_WARN", "$ci|end|max-forward limit reached");
|
|
sl_send_reply("483", "Too Many Hops");
|
|
exit;
|
|
}
|
|
|
|
if (!sanity_check()) {
|
|
xlog("L_WARN", "$ci|end|message is insane");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
route[CLASSIFY_SOURCE]
|
|
{
|
|
if (ds_is_from_list("1") || ds_is_from_list("3")) {
|
|
xlog("L_INFO", "$ci|log|originated from internal sources");
|
|
|
|
setflag(FLAG_INTERNALLY_SOURCED);
|
|
} else {
|
|
xlog("L_INFO", "$ci|log|originated from external sources");
|
|
}
|
|
}
|
|
|
|
route[HANDLE_OPTIONS]
|
|
{
|
|
if (is_method("OPTIONS")) {
|
|
if (isflagset(FLAG_INTERNALLY_SOURCED)) {
|
|
route(INTERNAL_TO_EXTERNAL_RELAY);
|
|
} else {
|
|
sl_send_reply("200", "Rawr!!");
|
|
}
|
|
exit;
|
|
}
|
|
}
|
|
|
|
route[HANDLE_PRESENCE]
|
|
{
|
|
if (is_method("SUBSCRIBE")) {
|
|
if (!t_newtran()) {
|
|
sl_reply_error();
|
|
exit;
|
|
}
|
|
handle_subscribe();
|
|
t_release();
|
|
exit;
|
|
}
|
|
|
|
if (is_method("PUBLISH")) {
|
|
if (!t_newtran()) {
|
|
sl_reply_error();
|
|
exit;
|
|
}
|
|
handle_publish();
|
|
t_release();
|
|
exit;
|
|
}
|
|
}
|
|
|
|
route[HANDLE_IN_DIALOG_REQUESTS]
|
|
{
|
|
if (has_totag()) {
|
|
if (loose_route()) {
|
|
xlog("L_INFO", "$ci|log|loose_route in-dialog message");
|
|
# 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);
|
|
}
|
|
route(RELAY);
|
|
} else if (isflagset(FLAG_INTERNALLY_SOURCED)) {
|
|
xlog("L_INFO", "$ci|log|relay internally sourced in-dialog message without loose_route");
|
|
route(RELAY);
|
|
} else if (t_check_trans()) {
|
|
xlog("L_INFO", "$ci|log|allow message for a known transaction");
|
|
route(RELAY);
|
|
} else {
|
|
xlog("L_INFO", "$ci|log|message had a to-tag but can't be loose routed");
|
|
sl_send_reply("481", "Call Leg/Transaction Does Not Exist");
|
|
}
|
|
exit();
|
|
}
|
|
}
|
|
|
|
route[PREPARE_INITIAL_REQUESTS]
|
|
{
|
|
if (is_method("CANCEL")) {
|
|
if (t_check_trans()) {
|
|
route(RELAY);
|
|
} else {
|
|
sl_send_reply("481", "Call Leg/Transaction Does Not Exist");
|
|
}
|
|
exit();
|
|
} else if (is_method("ACK")) {
|
|
if (t_check_trans()) {
|
|
route(RELAY);
|
|
}
|
|
exit();
|
|
}
|
|
|
|
t_check_trans();
|
|
|
|
if (loose_route()) {
|
|
sl_send_reply("403", "No pre-loaded routes");
|
|
exit();
|
|
}
|
|
|
|
if (is_method("REGISTER")) {
|
|
if (nat_uac_test("3")) {
|
|
xlog("L_INFO", "$ci|log|Correcting NATed contact in registration\n");
|
|
force_rport();
|
|
|
|
setbflag(FLB_NATB);
|
|
setbflag(FLB_NATSIPPING);
|
|
|
|
fix_nated_register();
|
|
}
|
|
|
|
if (is_present_hf("Authorization")) {
|
|
if ($sht(auth_cache=>$Au) != $null && pv_auth_check("$fd", "$sht(auth_cache=>$Au)", "0", "0")) {
|
|
xlog("L_INFO", "$ci|log|Authenticated $Au via cached SIP creds\n");
|
|
} else {
|
|
## RABBITMQ - Credentials fetch
|
|
if (!auth_check("$fd", "subscriber", "1")) {
|
|
auth_challenge("$fd", "0");
|
|
xlog("L_INFO", "$ci|log|Issued new auth challenge to failed registration attempt\n");
|
|
exit;
|
|
} else {
|
|
xlog("L_INFO", "$ci|log|Caching SIP credentials for $Au\n");
|
|
$sht(auth_cache=>$Au) = $avp(password);
|
|
}
|
|
}
|
|
} else {
|
|
auth_challenge("$fd", "0");
|
|
xlog("L_INFO", "$ci|log|Issued new auth challenge to new registration attempt\n");
|
|
exit;
|
|
}
|
|
|
|
# user authenticated - remove auth header
|
|
consume_credentials();
|
|
|
|
save("location");
|
|
exit;
|
|
} else if (!is_method("MESSAGE")) {
|
|
record_route();
|
|
}
|
|
}
|
|
|
|
# Take the routes from dispatcher - hash over callid
|
|
# If prefered route defined, reorder the destionations
|
|
route[FIND_ROUTES]
|
|
{
|
|
# alg 0 = hash(Callid)
|
|
if (!ds_select_dst("1", "0")) {
|
|
xlog("L_ERR", "$ci|end|no servers avaliable");
|
|
|
|
sl_send_reply("480", "All servers busy");
|
|
|
|
exit;
|
|
}
|
|
|
|
# Handle the case when a prefered route is set
|
|
$var(contact_uri) = @from.uri.user + "@" + @from.uri.host;
|
|
if ($sht(associations=>$var(contact_uri)) != $null) {
|
|
$var(prefered_route) = $sht(associations=>$var(contact_uri));
|
|
|
|
xlog("L_INFO", "$ci|log|should route to $var(prefered_route)");
|
|
|
|
route(REORDER_ROUTES);
|
|
}
|
|
}
|
|
|
|
route[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(contact_uri)) = $null;
|
|
}
|
|
}
|
|
|
|
route[HANDLE_MOVE_REQUEST]
|
|
{
|
|
if (is_method("INVITE") && $rU == "*6683*") {
|
|
$var(contact_uri) = @from.uri.user + "@" + @from.uri.host;
|
|
|
|
if ($sht(associations=>$var(contact_uri)) != $null) {
|
|
xlog("L_INFO", "$ci|log|remove association for user $var(contact_uri)
|
|
with media server $sht(associations=>$var(contact_uri))\n");
|
|
|
|
$sht(associations=>$var(contact_uri)) = $null;
|
|
}
|
|
|
|
send_reply("503", "Removed association");
|
|
|
|
xlog("L_INFO", "$ci|log|removed association for user $var(contact_uri)
|
|
with media server $sht(associations=>$var(contact_uri))\n");
|
|
|
|
exit;
|
|
}
|
|
}
|
|
|
|
route[RELAY]
|
|
{
|
|
if (isflagset(FLAG_INTERNALLY_SOURCED)) {
|
|
route(INTERNAL_TO_EXTERNAL_RELAY);
|
|
} else {
|
|
route(EXTERNAL_TO_INTERNAL_RELAY);
|
|
}
|
|
|
|
exit();
|
|
}
|
|
|
|
route[INTERNAL_TO_EXTERNAL_RELAY]
|
|
{
|
|
remove_hf("X-AUTH-IP");
|
|
|
|
t_on_reply("EXTERNAL_REPLY");
|
|
|
|
t_set_fr(0, 10000);
|
|
|
|
t_relay();
|
|
}
|
|
|
|
route[EXTERNAL_TO_INTERNAL_RELAY]
|
|
{
|
|
if (!isflagset(FLAG_INTERNALLY_SOURCED)) {
|
|
route(NAT_TEST_AND_CORRECT);
|
|
}
|
|
|
|
remove_hf("X-AUTH-IP");
|
|
append_hf("X-AUTH-IP: $si\r\n");
|
|
|
|
t_on_reply("INTERNAL_REPLY");
|
|
t_on_failure("INTERNAL_FAULT");
|
|
|
|
t_set_fr(0, 1000);
|
|
|
|
t_relay();
|
|
}
|
|
|
|
route[LOG_DESTINATION]
|
|
{
|
|
if (isdsturiset()) {
|
|
$var(port) = $dp;
|
|
$var(domain) = $dd;
|
|
} else {
|
|
$var(port) = $rp;
|
|
$var(domain) = $rd;
|
|
}
|
|
|
|
if ($(var(port){s.len}) <= 0) {
|
|
$var(port) = "5060";
|
|
}
|
|
|
|
xlog("L_INFO", "$ci|pass|$var(domain):$var(port)");
|
|
}
|
|
|
|
route[NAT_TEST_AND_CORRECT]
|
|
{
|
|
if (is_present_hf("Record-Route")) {
|
|
$var(i) = $rr_count;
|
|
while($var(i) > 0) {
|
|
$var(i) = $var(i) - 1;
|
|
$var(rr) = $(hdr(Record-Route)[$var(i)]);
|
|
if (!is_myself("$(var(rr){nameaddr.uri})")) {
|
|
setflag(FLAG_SKIP_NAT_CORRECTION);
|
|
}
|
|
}
|
|
} else if ($Rp == "5080") {
|
|
setflag(FLAG_SKIP_NAT_CORRECTION);
|
|
}
|
|
|
|
if (isflagset(FLAG_SKIP_NAT_CORRECTION)) {
|
|
return();
|
|
}
|
|
|
|
if (nat_uac_test("3")) {
|
|
force_rport();
|
|
fix_nated_contact();
|
|
}
|
|
|
|
if (has_body("application/sdp") && nat_uac_test("8")) {
|
|
fix_nated_sdp("10");
|
|
}
|
|
}
|
|
|
|
onreply_route[EXTERNAL_REPLY]
|
|
{
|
|
xlog("L_INFO", "$ci|log|external reply $T_reply_code");
|
|
|
|
route(NAT_TEST_AND_CORRECT);
|
|
}
|
|
|
|
onreply_route[INTERNAL_REPLY]
|
|
{
|
|
# this route handles replies that are comming from our media server
|
|
xlog("L_INFO", "$ci|start|recieved internal reply $T_reply_code $rr");
|
|
xlog("L_INFO", "$ci|log|source $si:$sp");
|
|
|
|
if ($rs < 300) {
|
|
xlog("L_INFO", "$ci|pass|$T_req($si):$T_req($sp)");
|
|
}
|
|
|
|
# change 6xx to 4xx
|
|
if (t_check_status("6[0-9][0-9]")) {
|
|
$var(new_code) = "4" + $(T_reply_code{s.substr,1,0});
|
|
change_reply_status("$var(new_code)", "$rr");
|
|
}
|
|
|
|
}
|
|
|
|
failure_route[INTERNAL_FAULT]
|
|
{
|
|
# this branch handles failures (>=300) to our media servers,
|
|
# which we can sometimes overcome by routing to another server
|
|
|
|
# if the failure cause was due to the transaction being
|
|
# cancelled then we are complete
|
|
if (t_is_canceled()) {
|
|
xlog("L_INFO", "$ci|log|transaction was cancelled");
|
|
|
|
exit;
|
|
}
|
|
|
|
# if the failure case was something that we should recover
|
|
# from then try to find a new media server
|
|
if (t_check_status("(401)|(407)")) {
|
|
xlog("L_INFO", "$ci|log|failure route ignoring auth reply $T_reply_code $rr");
|
|
|
|
exit;
|
|
} else if (t_check_status("403")) {
|
|
xlog("L_INFO", "$ci|log|failure route overriding reply code 403 with 503");
|
|
|
|
xlog("L_INFO", "$ci|pass|$si:$sp");
|
|
|
|
send_reply("503", "Error: Services Unavailable. Try Later");
|
|
|
|
exit;
|
|
} else if (t_check_status("402")) {
|
|
xlog("L_INFO", "$ci|log|failure route overriding reply code 402 with 486");
|
|
|
|
xlog("L_INFO", "$ci|pass|$si:$sp");
|
|
|
|
send_reply("486", "Insufficient Funds");
|
|
|
|
exit;
|
|
} 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");
|
|
|
|
# try to find a new media server to send the call to
|
|
if ($avp(route_attempts) < 3 && ds_next_domain()) {
|
|
xlog("L_INFO", "$ci|log|attempting retry $avp(route_attempts) of failed request");
|
|
xlog("L_INFO", "$ci|log|routing call to next media server $rd:$rp");
|
|
|
|
# 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);
|
|
|
|
$avp(route_attempts) = $avp(route_attempts) + 1;
|
|
} else if (t_check_status("404")) {
|
|
xlog("L_ERR", "$ci|log|no other media servers avaliable, sending 486");
|
|
|
|
send_reply("486", "Not found");
|
|
|
|
exit;
|
|
} else {
|
|
xlog("L_ERR", "$ci|log|no other media servers avaliable");
|
|
|
|
exit;
|
|
}
|
|
} else if (t_check_status("302")) {
|
|
## TODO - test this
|
|
## get_redirects("*");
|
|
|
|
if($T_rpl($hdr(X-Redirect-Server)) != $null) {
|
|
$var(contact_uri) = @from.uri.user + "@" + @from.uri.host;
|
|
|
|
$sht(associations=>$var(contact_uri)) = $T_rpl($hdr(X-Redirect-Server));
|
|
|
|
xlog("L_INFO", "$ci|log|stored redirect mapping for $var(contact_uri) to $T_rpl($hdr(X-Redirect-Server))");
|
|
|
|
remove_hf("X-Redirect-Server");
|
|
}
|
|
} else {
|
|
xlog("L_INFO", "$ci|log|failure route ignoring reply $T_reply_code $rr");
|
|
|
|
exit;
|
|
}
|
|
|
|
route(LOG_DESTINATION);
|
|
}
|
|
|
|
onsend_route {
|
|
if (isflagset(FLAG_ASSOCIATE_USER)) {
|
|
$var(contact_uri) = @from.uri.user + "@" + @from.uri.host;
|
|
xlog("L_INFO", "$ci|log|associate user $var(contact_uri) with media server sip:$sndto(ip):$sndto(port)\n");
|
|
$sht(associations=>$var(contact_uri))= "sip:" + $sndto(ip) + ":" + $sndto(port);
|
|
}
|
|
|
|
xlog("L_INFO", "$ci|pass|$sndfrom(ip):$sndfrom(port) -> $sndto(ip):$sndto(port)");
|
|
}
|
|
|
|
## vim:set tabstop=4 softtabstop=4 shiftwidth=4 expandtab
|