1282 lines
35 KiB
INI
1282 lines
35 KiB
INI
#!KAMAILIO
|
|
#
|
|
# This config file implements the basic P-CSCF functionality
|
|
# - web: http://www.kamailio.org
|
|
# - git: http://sip-router.org
|
|
#
|
|
# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php
|
|
# for an explanation of possible statements, functions and parameters.
|
|
#
|
|
# Direct your questions about this file to: <sr-users@lists.kamailio.org>.
|
|
#
|
|
# For more information about the various parameters, functions and statements
|
|
# try http://sip-router.org/wiki/ .
|
|
#
|
|
|
|
####### Defined Values #########
|
|
# *** Value defines - IDs used later in config
|
|
|
|
# - flags
|
|
# FLT_ - per transaction (message) flags
|
|
# FLB_ - per branch flags
|
|
|
|
#!define FLT_CAPTURE 1
|
|
#!define FLT_DIALOG 2
|
|
|
|
#!define DLG_TIMEOUT_AVP "i:1"
|
|
#!define RR_CUSTOM_USER_AVP "i:2"
|
|
#!define DISPATCHER_DST_AVP "i:3"
|
|
#!define DISPATCHER_GRP_AVP "i:4"
|
|
#!define DISPATCHER_CNT_AVP "i:5"
|
|
#!define DISPATCHER_SOCK_AVP "i:6"
|
|
|
|
####### Global Parameters #########
|
|
|
|
include_file "scscf.cfg"
|
|
|
|
debug=2
|
|
log_stderror=no
|
|
sip_warning=no
|
|
|
|
#!ifdef WITH_XMLRPC
|
|
listen=tcp:127.0.0.1:6060
|
|
#!endif
|
|
|
|
alias=HOSTNAME
|
|
|
|
user_agent_header="User-Agent: Kamailio S-CSCF"
|
|
server_header="Server: Kamailio S-CSCF"
|
|
log_name="scscf"
|
|
log_prefix_mode=1
|
|
log_prefix="{$mt $hdr(CSeq) $ci $cfg(route)} "
|
|
|
|
/* comment the next line to enable the auto discovery of local aliases
|
|
based on reverse DNS on IPs (default on) */
|
|
auto_aliases=no
|
|
|
|
check_via=no # (cmd. line: -v)
|
|
dns=no # (cmd. line: -r)
|
|
rev_dns=no # (cmd. line: -R)
|
|
|
|
# Do SRV-Loadbalancing:
|
|
dns_srv_lb=on
|
|
# Always: Also try IPv6:
|
|
dns_try_ipv6=on
|
|
# Always prefer IPv6:
|
|
dns_cache_flags=4
|
|
# DNS-Based failover
|
|
use_dns_failover=on
|
|
# Query NAPTR-Records as well:
|
|
dns_try_naptr=on
|
|
# DNS cache won't be used (all dns lookups will result into a DNS request)
|
|
use_dns_cache=off
|
|
|
|
#!ifdef WITH_XMLRPC
|
|
#!ifndef WITH_TCP
|
|
#!define WITH_TCP
|
|
#!endif
|
|
#!ifndef TCP_PROCESSES
|
|
# Number of TCP Processes
|
|
#!define TCP_PROCESSES 3
|
|
#!endif
|
|
#!endif
|
|
|
|
#!ifdef WITH_TCP
|
|
# life time of TCP connection when there is no traffic
|
|
# - a bit higher than registration expires to cope with UA behind NAT
|
|
tcp_connection_lifetime=UE_SUBSCRIPTION_EXPIRES
|
|
#!ifdef TCP_PROCESSES
|
|
tcp_children=TCP_PROCESSES
|
|
#!endif
|
|
#!else
|
|
disable_tcp=yes
|
|
#!endif
|
|
|
|
children=4
|
|
|
|
system.shutdownmode = 0 desc "System shutdown mode"
|
|
system.service = "Serving-CSCF" desc "Function of this server"
|
|
|
|
# ------------------ module loading ----------------------------------
|
|
mpath="/usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/:/usr/lib/kamailio/modules_k/:/usr/lib/kamailio/modules/:/usr/lib/x86_64-linux-gnu/kamailio/modules/:/usr/local/lib64/kamailio/modules"
|
|
# (we try both the lib64 and the lib directory)
|
|
|
|
loadmodule "tm.so"
|
|
loadmodule "pv.so"
|
|
loadmodule "sl.so"
|
|
loadmodule "rr.so"
|
|
loadmodule "ims_dialog.so"
|
|
loadmodule "textops.so"
|
|
loadmodule "textopsx.so"
|
|
loadmodule "maxfwd.so"
|
|
loadmodule "xlog.so"
|
|
loadmodule "sanity.so"
|
|
loadmodule "siputils.so"
|
|
loadmodule "kex.so"
|
|
loadmodule "corex.so"
|
|
loadmodule "tmx.so"
|
|
loadmodule "pike.so"
|
|
#!ifdef DB_URL
|
|
loadmodule "presence"
|
|
#!endif
|
|
|
|
#!ifdef DB_URL
|
|
loadmodule "db_mysql"
|
|
#!ifdef DB_URL2
|
|
loadmodule "db_cluster"
|
|
#!endif
|
|
#!endif
|
|
|
|
loadmodule "dispatcher"
|
|
|
|
loadmodule "enum"
|
|
loadmodule "uac"
|
|
|
|
# Control interfaces:
|
|
loadmodule "ctl"
|
|
loadmodule "cfg_rpc"
|
|
#!ifdef WITH_XMLRPC
|
|
loadmodule "xmlrpc"
|
|
#!endif
|
|
|
|
loadmodule "cdp.so"
|
|
loadmodule "cdp_avp.so"
|
|
|
|
loadmodule "ims_usrloc_scscf.so"
|
|
loadmodule "ims_registrar_scscf.so"
|
|
loadmodule "ims_auth.so"
|
|
loadmodule "ims_isc.so"
|
|
|
|
#!ifdef WITH_RO
|
|
loadmodule "ims_charging.so"
|
|
#!endif
|
|
|
|
#!ifdef CAPTURE_NODE
|
|
loadmodule "siptrace.so"
|
|
#!endif
|
|
|
|
##!ifdef WITH_DEBUG
|
|
loadmodule "debugger.so"
|
|
modparam("debugger", "mod_hash_size", 5)
|
|
modparam("debugger", "mod_level_mode", 1)
|
|
modparam("debugger", "mod_level", "xlog=3")
|
|
modparam("debugger", "mod_level", "ims_usrloc_scscf=3")
|
|
modparam("debugger", "mod_level", "ims_registrar_scscf=3")
|
|
modparam("debugger", "mod_level", "ims_auth=3")
|
|
modparam("debugger", "mod_level", "ims_isc=3")
|
|
modparam("debugger", "mod_level", "ims_dialog=3")
|
|
modparam("debugger", "mod_level", "ims_charging=3")
|
|
##!endif
|
|
|
|
# ----------------- setting module-specific parameters ---------------
|
|
#!ifdef DB_URL2
|
|
# ----- db_cluster params -----
|
|
modparam("db_cluster", "connection", DB_URL)
|
|
modparam("db_cluster", "connection", DB_URL2)
|
|
modparam("db_cluster", "cluster", "cluster1=>con1=2s2s;con2=1s1s")
|
|
#!endif
|
|
|
|
# ----- presence params -----
|
|
#!ifdef DB_URL
|
|
#!ifdef DB_URL2
|
|
modparam("presence", "db_url", "cluster://cluster1")
|
|
#!else
|
|
modparam("presence", "db_url", DB_URL)
|
|
#!endif
|
|
#modparam("presence", "fallback2db", 1)
|
|
modparam("presence", "db_update_period", 20)
|
|
#!endif
|
|
|
|
loadmodule "jsonrpcs.so"
|
|
# ----- jsonrpcs params -----
|
|
modparam("jsonrpcs", "pretty_format", 1)
|
|
/* set the path to RPC fifo control file */
|
|
modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo")
|
|
/* set the path to RPC unix socket control file */
|
|
modparam("jsonrpcs", "dgram_socket", "/var/run/kamailio/kamailio_rpc.sock")
|
|
|
|
# ----- ctl params -----
|
|
modparam("ctl", "binrpc", "unix:/var/run/kamailio/kamailio_ctl")
|
|
|
|
# ----- tm params -----
|
|
# auto-discard branches from previous serial forking leg
|
|
modparam("tm", "failure_reply_mode", 3)
|
|
# default retransmission timeout: 10sec
|
|
modparam("tm", "fr_timer", 10000)
|
|
# default invite retransmission timeout after 1xx: 120sec
|
|
modparam("tm", "fr_inv_timer", 120000)
|
|
# Don't reply automatically with "100 Trying"
|
|
modparam("tm", "auto_inv_100", 0)
|
|
|
|
# ----- rr params -----
|
|
# add value to ;lr param to cope with most of the UAs
|
|
modparam("rr", "enable_full_lr", 1)
|
|
# append from tag to the RR
|
|
modparam("rr", "append_fromtag", 1)
|
|
# add a Username to RR-Header
|
|
modparam("rr", "add_username", 1)
|
|
# Take User from a custom AVP
|
|
modparam("rr", "custom_user_avp", "$avp(RR_CUSTOM_USER_AVP)")
|
|
|
|
# -- usrloc params --
|
|
modparam("ims_usrloc_scscf", "enable_debug_file", 0)
|
|
modparam("ims_usrloc_scscf", "matching_mode", 0)
|
|
# Set to one as a workaround for multiple contacts created due to unstable radio link.
|
|
modparam("ims_usrloc_scscf", "maxcontact", 1)
|
|
# Set to one as a workaround for multiple contacts created due to unstable radio link.
|
|
modparam("ims_usrloc_scscf", "maxcontact_3gpp", 1)
|
|
modparam("ims_registrar_scscf", "max_contacts", 5)
|
|
modparam("ims_usrloc_scscf", "maxcontact_behaviour", 2) #overwrite
|
|
#!ifdef DB_URL
|
|
#!ifdef DB_URL2
|
|
modparam("ims_usrloc_scscf", "db_url", "cluster://cluster1")
|
|
#!else
|
|
modparam("ims_usrloc_scscf", "db_url", DB_URL)
|
|
#!endif
|
|
modparam("ims_usrloc_scscf", "db_mode", 0)
|
|
#!endif
|
|
modparam("ims_registrar_scscf", "subscription_default_expires", UE_SUBSCRIPTION_EXPIRES)
|
|
modparam("ims_registrar_scscf", "subscription_min_expires", UE_SUBSCRIPTION_EXPIRES)
|
|
modparam("ims_registrar_scscf", "subscription_max_expires", UE_SUBSCRIPTION_EXPIRES)
|
|
|
|
# -- CDP params --
|
|
modparam("cdp","config_file","/etc/kamailio_scscf/scscf.xml")
|
|
|
|
# -- ims_dialog params --
|
|
modparam("ims_dialog", "dlg_flag", FLT_DIALOG)
|
|
modparam("ims_dialog", "timeout_avp", "$avp(DLG_TIMEOUT_AVP)")
|
|
modparam("ims_dialog", "detect_spirals", 0)
|
|
modparam("ims_dialog", "profiles_no_value", "orig ; term")
|
|
#!ifdef DB_URL
|
|
#!ifdef DB_URL2
|
|
modparam("ims_dialog", "db_url", "cluster://cluster1")
|
|
#!else
|
|
modparam("ims_dialog", "db_url", DB_URL)
|
|
#!endif
|
|
modparam("ims_dialog", "db_mode", 0)
|
|
#!endif
|
|
|
|
#!ifdef WITH_XMLRPC
|
|
# ----- xmlrpc params -----
|
|
modparam("xmlrpc", "route", "XMLRPC");
|
|
modparam("xmlrpc", "url_match", "^/RPC")
|
|
#!endif
|
|
|
|
#!ifdef WITH_DEBUG
|
|
#!ifdef WITH_DEBUG_TRACE
|
|
# ----- debugger params -----
|
|
modparam("debugger", "cfgtrace", 1)
|
|
#!endif
|
|
#!endif
|
|
|
|
#!ifdef CAPTURE_NODE
|
|
# Destination, where to send the traffic
|
|
modparam("siptrace", "duplicate_uri", CAPTURE_NODE)
|
|
# Trace all traffic
|
|
modparam("siptrace", "trace_on", 1)
|
|
modparam("siptrace", "trace_to_database", 0)
|
|
modparam("siptrace", "trace_flag", FLT_CAPTURE)
|
|
modparam("siptrace", "hep_mode_on", 1)
|
|
#!endif
|
|
|
|
# -- ims_auth params --
|
|
modparam("ims_auth", "name", URI)
|
|
modparam("ims_auth", "registration_default_algorithm", REG_AUTH_DEFAULT_ALG)
|
|
#!ifdef CXDX_FORCED_PEER
|
|
modparam("ims_auth", "cxdx_forced_peer", CXDX_FORCED_PEER)
|
|
#!endif
|
|
modparam("ims_auth", "cxdx_dest_realm", EPC_REALM)
|
|
modparam("ims_auth", "av_check_only_impu", 1)
|
|
|
|
modparam("ims_auth", "max_nonce_reuse", 20)
|
|
modparam("ims_auth", "auth_vector_timeout", 60)
|
|
modparam("ims_auth", "auth_data_timeout", UE_SUBSCRIPTION_EXPIRES)
|
|
modparam("ims_auth", "auth_used_vector_timeout", UE_SUBSCRIPTION_EXPIRES)
|
|
modparam("ims_auth", "av_request_at_once", 1)
|
|
modparam("ims_auth", "av_request_at_sync", 1)
|
|
modparam("ims_auth", "registration_qop", "auth")
|
|
|
|
# -- ims_registrar_scscf params --
|
|
#!ifdef WITH_DEBUG
|
|
modparam("ims_registrar_scscf", "default_expires", 60)
|
|
modparam("ims_registrar_scscf", "min_expires", 60)
|
|
modparam("ims_registrar_scscf", "max_expires", 60)
|
|
#!else
|
|
modparam("ims_registrar_scscf", "default_expires", UE_SUBSCRIPTION_EXPIRES)
|
|
modparam("ims_registrar_scscf", "min_expires", UE_SUBSCRIPTION_EXPIRES)
|
|
modparam("ims_registrar_scscf", "max_expires", UE_SUBSCRIPTION_EXPIRES)
|
|
#!endif
|
|
modparam("ims_registrar_scscf", "use_path", 1)
|
|
modparam("ims_registrar_scscf", "support_wildcardPSI",1)
|
|
modparam("ims_registrar_scscf", "user_data_xsd","/etc/kamailio_scscf/CxDataType_Rel7.xsd")
|
|
modparam("ims_registrar_scscf", "scscf_name", URI)
|
|
modparam("ims_registrar_scscf", "scscf_name", URI)
|
|
modparam("ims_registrar_scscf", "cxdx_dest_realm", EPC_REALM)
|
|
modparam("ims_registrar_scscf", "append_branches", 1)
|
|
modparam("ims_registrar_scscf", "user_data_always", 0)
|
|
modparam("ims_registrar_scscf", "ue_unsubscribe_on_dereg", 1)
|
|
|
|
#!ifdef WITH_MULTIDOMAIN
|
|
# ----- domain params -----
|
|
#!ifdef DB_URL
|
|
#!ifdef DB_URL2
|
|
modparam("domain", "db_url", "cluster://cluster1")
|
|
#!else
|
|
modparam("domain", "db_url", DB_URL)
|
|
#!endif
|
|
modparam("domain", "db_mode", 1)
|
|
#!endif
|
|
# register callback to match myself condition with domains list
|
|
modparam("domain", "register_myself", 1)
|
|
#!endif
|
|
|
|
# ----- ims_isc params -----
|
|
modparam("ims_isc", "my_uri", HOSTNAME)
|
|
modparam("ims_isc", "add_p_served_user", 1)
|
|
|
|
#!ifdef WITH_RO
|
|
# ----- ims_diameter_ro params -----
|
|
#!ifdef DB_URL
|
|
#!ifdef DB_URL2
|
|
#modparam("ims_charging", "db_url", "cluster://cluster1")
|
|
#!else
|
|
#modparam("ims_charging", "db_url", DB_URL)
|
|
#!endif
|
|
#modparam("ims_charging", "db_mode", 1)
|
|
#!endif
|
|
modparam("ims_charging", "origin_host", HOSTNAME);
|
|
modparam("ims_charging", "origin_realm", NETWORKNAME);
|
|
#!ifdef RO_FORCED_PEER
|
|
modparam("ims_charging", "ro_forced_peer", RO_FORCED_PEER);
|
|
#!endif
|
|
modparam("ims_charging", "destination_host", RO_DESTINATION);
|
|
modparam("ims_charging", "destination_realm", NETWORKNAME);
|
|
modparam("ims_charging", "ro_auth_expiry", UE_SUBSCRIPTION_EXPIRES)
|
|
|
|
modparam("ims_charging","service_context_id_root", RO_ROOT);
|
|
modparam("ims_charging","service_context_id_ext", RO_EXT);
|
|
modparam("ims_charging","service_context_id_mnc", RO_MNC);
|
|
modparam("ims_charging","service_context_id_mcc", RO_MCC);
|
|
modparam("ims_charging","service_context_id_release", RO_RELEASE);
|
|
|
|
modparam("ims_charging","interim_update_credits",30);
|
|
modparam("ims_charging","timer_buffer",5);
|
|
#!endif
|
|
|
|
# ----- enum params -----
|
|
modparam("enum", "domain_suffix", ENUM_SUFFIX)
|
|
|
|
# ----- sanity params -----
|
|
modparam("sanity", "autodrop", 0)
|
|
|
|
# ----------------- Settings for Dispatcher ---------------
|
|
modparam("dispatcher", "list_file", "/etc/kamailio_scscf/dispatcher.list")
|
|
# Dispatcher: Enable Failover-Support
|
|
modparam("dispatcher", "flags", 2)
|
|
# Dispatcher: Overwrite Destination address, if required.
|
|
modparam("dispatcher", "force_dst", 1)
|
|
# AVP's required for Fail-Over-Support:
|
|
#modparam("dispatcher", "dst_avp", "$avp(DISPATCHER_DST_AVP)")
|
|
#modparam("dispatcher", "grp_avp", "$avp(DISPATCHER_GRP_AVP)")
|
|
#modparam("dispatcher", "cnt_avp", "$avp(DISPATCHER_CNT_AVP)")
|
|
#modparam("dispatcher", "sock_avp", "$avp(DISPATCHER_SOCK_AVP)")
|
|
|
|
#modparam("dispatcher", "xavp_dst", "$avp(DISPATCHER_DST_AVP)")
|
|
#modparam("dispatcher", "xavp_dst_mode", 0)
|
|
#modparam("dispatcher", "xavp_ctx", "$avp(DISPATCHER_CNT_AVP)")
|
|
#modparam("dispatcher", "xavp_ctx_mode", 0)
|
|
|
|
# Try to recover disabled destinations every 15 seconds.
|
|
modparam("dispatcher", "ds_ping_interval", 15)
|
|
# Actively query the gateways:
|
|
modparam("dispatcher", "ds_probing_mode", 1)
|
|
modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=404;code=480")
|
|
|
|
####### Routing Logic ########
|
|
# Main SIP request routing logic
|
|
# - processing of any incoming SIP request starts with this route
|
|
|
|
route {
|
|
##!ifdef WITH_DEBUG
|
|
xnotice("SCSCF: $rm $ru ($fu ($si:$sp) to $tu, $ci)\n");
|
|
##!endif
|
|
|
|
# per request initial checks
|
|
route(REQINIT);
|
|
|
|
# Handle Registrations:
|
|
if (is_method("REGISTER")) {
|
|
route(REGISTER);
|
|
exit;
|
|
}
|
|
|
|
# we need to support subscription to reg event
|
|
if (is_method("SUBSCRIBE") && search("^(Event|o)([ \t]*):([ \t]*)reg")) {
|
|
route(SUBSCRIBE);
|
|
break;
|
|
}
|
|
|
|
if (is_method("PUBLISH") && search("^(Event|o)([ \t]*):([ \t]*)reg")) {
|
|
route(PUBLISH);
|
|
break;
|
|
}
|
|
|
|
# Evaluate Route-Header and set $route_uri
|
|
loose_route();
|
|
|
|
if (is_method("CANCEL|ACK")) {
|
|
t_relay();
|
|
exit;
|
|
}
|
|
|
|
#Set DLG flag to track dialogs using dialog2
|
|
if (!is_method("REGISTER|SUBSCRIBE"))
|
|
setflag(FLT_DIALOG);
|
|
|
|
if (($route_uri =~ "sip:orig@.*") || ($route_uri =~ "sip:orig@"+HOSTNAME_ESC+".*") || isc_from_as("orig")) {
|
|
xlog("Orig");
|
|
# we need something like this to assign SCSCF to unregistered user for services
|
|
# support for AS origination on behalf of unregistered useri
|
|
# can use the registrar is_registered methods - must see if we need to check orig or term?
|
|
|
|
# Sanitize the R-URI if domain is present in from of @MSISDN of caller
|
|
# What in case of Roaming? - Need to handle it
|
|
# if ($ru =~ ".*phone-context.*") {
|
|
# if ($ru =~ "tel:.*") {
|
|
# # Handle following request-uri
|
|
# # tel:0498765432100;phone-context=ims.mnc001.mcc001.3gppnetwork.org
|
|
# $ru = $(ru{re.subst,/tel:/sip:/g});
|
|
# }
|
|
# # Now in sip: uri format
|
|
# if ($ru =~ ".*@.*") {
|
|
# $ru = $(ru{re.subst,/@[0-9+-]*;user=phone/@NETWORKNAME;user=phone/g});
|
|
# #$ru = $(ru{re.subst,/;phone-context=[A-Za-z.0-9+-]*@/;phone-context=NETWORKNAME@/g});
|
|
# } else {
|
|
# $ru = $ru + "@" + NETWORKNAME + ";user=phone";
|
|
# #$ru = $(ru{re.subst,/;phone-context=[A-Za-z.0-9+-]*@/;phone-context=NETWORKNAME@/g});
|
|
# }
|
|
# }
|
|
if (!is_method("REGISTER|SUBSCRIBE")) {
|
|
# sip:xxx;phone-context=xxxx@xxx format is not desired
|
|
if (($ru =~ ".*phone-context.*") && ($ru =~ "sip:.*")) {
|
|
$var(old_ruri) = $ru;
|
|
$ru = $(ru{re.subst,/sip:/tel:/g});
|
|
$ru = $(ru{re.subst,/;phone-context=[A-Za-z.0-9+-@]*;user=phone//g});
|
|
$ru = $ru + ";phone-context=" + NETWORKNAME;
|
|
msg_apply_changes();
|
|
xnotice("SCSCF: Changed R-URI from $var(old_ruri) to $ru\n");
|
|
}
|
|
}
|
|
|
|
# Originating
|
|
route(orig);
|
|
break;
|
|
} else {
|
|
isc_from_as("term");
|
|
if ($retcode == -2) {
|
|
# Treat as originating, since it was retargeted:
|
|
route(orig);
|
|
break;
|
|
}
|
|
if ((is_in_profile("orig") || has_totag()) && ($route_uri =~ "sip:mo@"+".*")) {
|
|
route(orig_subsequent);
|
|
break;
|
|
}
|
|
if ((is_in_profile("term") || has_totag()) && ($route_uri =~ "sip:mt@"+".*")) {
|
|
route(term_subsequent);
|
|
break;
|
|
}
|
|
|
|
# Terminating
|
|
if (uri == myself || uri =~ "tel:.*") {
|
|
if (!term_impu_registered("location")) {
|
|
xlog("L_DBG", "We need to do an UNREG server SAR assignemnt");
|
|
assign_server_unreg("UNREG_SAR_REPLY", "location", "term");
|
|
exit;
|
|
} else {
|
|
sl_send_reply("403","Forbidden - Domain not served");
|
|
exit();
|
|
}
|
|
}
|
|
route(term);
|
|
break;
|
|
}
|
|
}
|
|
|
|
route[UNREG_SAR_REPLY]
|
|
{
|
|
xlog("L_DBG","saa_return code is $avp(s:saa_return_code)\n");
|
|
switch ($avp(s:saa_return_code)){
|
|
case 1: #success
|
|
xlog("L_DBG", "SAR success - will route message\n");
|
|
route(term);
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "SAR failure - error response sent from module\n");
|
|
break;
|
|
case -2: #error
|
|
xlog("L_ERR", "SAR error - error response sent from module\n");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from SAR, value is [$avp(s:saa_return_code)]\n");
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
|
|
######################################################################
|
|
# Helper routes (Basic-Checks, NAT-Handling/RTP-Control, XML-RPC)
|
|
######################################################################
|
|
# Per SIP request initial checks
|
|
route[REQINIT] {
|
|
$var(used) = 1 - ($stat(free_size) / $stat(total_size));
|
|
xlog("L_DBG", "Mem: Total $stat(total_size), Free $stat(free_size) [$var(used)% used]\n");
|
|
if ($var(used) > 95) {
|
|
send_reply("503", "Server overloaded");
|
|
exit;
|
|
}
|
|
|
|
# Trace this message
|
|
#!ifdef CAPTURE_NODE
|
|
sip_trace();
|
|
setflag(FLT_CAPTURE);
|
|
#!endif
|
|
|
|
if (!mf_process_maxfwd_header("10")) {
|
|
sl_send_reply("483","Too Many Hops");
|
|
exit;
|
|
}
|
|
|
|
if(!sanity_check("1511", "7")) {
|
|
xlog("Malformed SIP message from $si:$sp\n");
|
|
exit;
|
|
}
|
|
|
|
# Check for shutdown mode:
|
|
if (!has_totag() && ($sel(cfg_get.system.shutdownmode) > 0)) {
|
|
send_reply("503", "Server shutting down");
|
|
exit;
|
|
}
|
|
|
|
# Reply to OPTIONS:
|
|
if (is_method("OPTIONS") && (uri==myself)) {
|
|
options_reply();
|
|
exit;
|
|
}
|
|
|
|
# Ignore Re-Transmits:
|
|
if (t_lookup_request()) {
|
|
exit;
|
|
}
|
|
if (is_method("INVITE")) {
|
|
send_reply("100", "Trying");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
######################################################################
|
|
# Publish route
|
|
######################################################################
|
|
route[PUBLISH]
|
|
{
|
|
if (!t_newtran()) {
|
|
#absorb retransmissions
|
|
sl_reply("500","Could not create transaction");
|
|
exit;
|
|
}
|
|
|
|
if (can_publish_reg("location")) {
|
|
$var(ret)= publish_reg("location");
|
|
switch ($var(ret)){
|
|
case 1: #success
|
|
xlog("L_DBG", "Publish reg successful");
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "Publish reg failure - sending 500 Error now\n");
|
|
t_reply("500","Server Error publishing subscription");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from publish reg event alue is [$var(ret)]\n");
|
|
break;
|
|
}
|
|
} else {
|
|
t_reply("403","Forbidden to PUBLISH");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# Subscribe route
|
|
######################################################################
|
|
route[SUBSCRIBE]
|
|
{
|
|
if (!t_newtran()) {
|
|
#absorb retransmissions
|
|
sl_reply("500","Could not create transaction");
|
|
exit;
|
|
}
|
|
|
|
if (!has_totag()) {
|
|
xlog("L_DBG", "This is an initial SUBSCRIBE\n");
|
|
if (!term_impu_registered("location")) {
|
|
xlog("L_DBG", "We need to do an UNREG server SAR assignment\n");
|
|
assign_server_unreg("SUBSCRIBE_UNREG_SAR_REPLY", "location", "term");
|
|
exit;
|
|
}
|
|
if (!can_subscribe_to_reg("location")) {
|
|
t_reply("403","Forbidden to SUBSCRIBE");
|
|
exit;
|
|
}
|
|
} else {
|
|
xlog("L_DBG", "This is a subsequent SUBSCRIBE\n");
|
|
}
|
|
|
|
$var(ret)= subscribe_to_reg("location");
|
|
switch ($var(ret)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "Subscribe to reg successful");
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "Subscribe to reg failure - sending 500 Error now\n");
|
|
t_reply("500","Server Error saving subscription");
|
|
break;
|
|
case -2: #error
|
|
xlog("L_ERR", "Subscribe to reg error sending notify - 200 OK so subscription already sent\n");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from subscribe to reg event alue is [$var(ret)]\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
route[SUBSCRIBE_UNREG_SAR_REPLY]
|
|
{
|
|
|
|
xlog("L_DBG","saa_return code is $avp(s:saa_return_code)\n");
|
|
switch ($avp(s:saa_return_code)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "SAR success - will process subscribe\n");
|
|
if (can_subscribe_to_reg("location")) {
|
|
$var(ret)= subscribe_to_reg("location");
|
|
switch ($var(ret)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "Subscribe to reg successful");
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "Subscribe to reg failure - sending 500 Error now\n");
|
|
t_reply("500","Server Error saving subscription");
|
|
break;
|
|
case -2: #error
|
|
xlog("L_ERR", "Subscribe to reg error sending notify - 200 OK so subscription already sent\n");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from subscribe to reg event alue is [$var(ret)]\n");
|
|
break;
|
|
}
|
|
} else {
|
|
t_reply("403","Forbidden to SUBSCRIBE");
|
|
exit;
|
|
}
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "SAR failure - Sending 403 Forbidden\n");
|
|
t_reply("403","Forbidden to SUBSCRIBE");
|
|
break;
|
|
case -2: #error
|
|
xlog("L_ERR", "SAR error - Sending 403 Forbidden\n");
|
|
t_reply("403","Forbidden to SUBSCRIBE");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from SAR, value is [$avp(s:saa_return_code)] - sending 403 Forbidden\n");
|
|
t_reply("403","Forbidden to SUBSCRIBE");
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
######################################################################
|
|
# XMLRPC routing
|
|
######################################################################
|
|
#!ifdef WITH_XMLRPC
|
|
route[XMLRPC] {
|
|
if ((method=="POST" || method=="GET")
|
|
#!ifdef XMLRPC_WHITELIST_1
|
|
&& ((src_ip == XMLRPC_WHITELIST_1)
|
|
#!ifdef XMLRPC_WHITELIST_2
|
|
|| (src_ip == XMLRPC_WHITELIST_2)
|
|
#!endif
|
|
#!ifdef XMLRPC_WHITELIST_3
|
|
|| (src_ip == XMLRPC_WHITELIST_3)
|
|
#!endif
|
|
)
|
|
#!endif
|
|
) {
|
|
# close connection only for xmlrpclib user agents (there is a bug in
|
|
# xmlrpclib: it waits for EOF before interpreting the response).
|
|
if ($hdr(User-Agent) =~ "xmlrpclib")
|
|
set_reply_close();
|
|
set_reply_no_connect();
|
|
dispatch_rpc();
|
|
exit;
|
|
}
|
|
send_reply("403", "Forbidden");
|
|
exit;
|
|
}
|
|
#!endif
|
|
|
|
######################################################################
|
|
# Route for handling Registrations:
|
|
######################################################################
|
|
route[REGISTER] {
|
|
xnotice("ALGORITHM IS [$aa] and User-Agent is [$ua]\n");
|
|
$avp(alg) = $aa;
|
|
if ($aa == $null) {
|
|
$avp(alg) = "MD5"; #force to MD5 for zoiper.... non-ims
|
|
}
|
|
#!ifdef WITH_AUTH
|
|
if (!ims_www_authenticate("$td")) {
|
|
#!else
|
|
if (($avp(alg) == "MD5") && (!ims_www_authenticate("$td"))) {
|
|
#!endif
|
|
if ($? == -2) {
|
|
send_reply("403", "Authentication Failed");
|
|
exit;
|
|
} else if ($? == -3) {
|
|
send_reply("400", "Bad Request");
|
|
exit;
|
|
} else if ($? == -9) {
|
|
xlog("L_DBG", "Authentication re-sync requested\n");
|
|
ims_www_resync_auth("REG_RESYNC_REPLY", "$td");
|
|
exit;
|
|
} else {
|
|
#user has not been authenticated. Lets send a challenge via 401 Unauthorized
|
|
xlog("L_DBG","About to challenge! auth_ims[$avp(alg)]\n");
|
|
ims_www_challenge("REG_MAR_REPLY", "$td", "$avp(alg)");
|
|
exit;
|
|
}
|
|
} else {
|
|
xlog("L_DBG", "Auth succeeded\n");
|
|
# We need to check if this user is registered or not
|
|
if (!impu_registered("location")) {
|
|
xlog("L_ERR", "Not REGISTERED\n");
|
|
save("PRE_REG_SAR_REPLY","location");
|
|
exit;
|
|
} else {
|
|
isc_match_filter_reg("1","location");
|
|
save("REG_SAR_REPLY","location");
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
route[REG_MAR_REPLY]
|
|
{
|
|
#this is async so to know status we have to check the reply avp
|
|
xlog("L_DBG","maa_return code is $avp(s:maa_return_code)\n");
|
|
|
|
switch ($avp(s:maa_return_code)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "MAR success - 401/407 response sent from module\n");
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "MAR failure - error response sent from module\n");
|
|
break;
|
|
case -2: #error
|
|
xlog("L_ERR", "MAR error - sending error response now\n");
|
|
send_reply("500", "MAR failed");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from MAR, value is [$avp(s:maa_return_code)]\n");
|
|
send_reply("500", "Unknown response code from MAR");
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
route[PRE_REG_SAR_REPLY]
|
|
{
|
|
xlog("L_DBG","saa_return code is $avp(s:saa_return_code)\n");
|
|
#this is async so to know status we have to check the reply avp
|
|
xlog("L_DBG","saa_return code (for scscf_save on register) is $avp(s:saa_return_code)\n");
|
|
switch ($avp(s:saa_return_code)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "SAR success - 200 response sent from module\n");
|
|
isc_match_filter_reg("0","location");
|
|
exit;
|
|
case -1: #failure
|
|
xlog("L_ERR", "SAR failure - error response sent from module\n");
|
|
break;
|
|
case -2: #error
|
|
xlog("L_ERR", "SAR error - error response sent from module\n");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from SAR, value is [$avp(s:saa_return_code)]\n");
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
route[REG_SAR_REPLY]
|
|
{
|
|
xlog("L_DBG","saa_return code is $avp(s:saa_return_code)\n");
|
|
#this is async so to know status we have to check the reply avp
|
|
xlog("L_DBG","saa_return code (for scscf_save on register) is $avp(s:saa_return_code)\n");
|
|
switch ($avp(s:saa_return_code)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "SAR success - 200 response sent from module\n");
|
|
exit;
|
|
case -1: #failure
|
|
xlog("L_ERR", "SAR failure - error response sent from module\n");
|
|
break;
|
|
case -2: #error
|
|
xlog("L_ERR", "SAR error - error response sent from module\n");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from SAR, value is [$avp(s:saa_return_code)]\n");
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
route[REG_RESYNC_REPLY]
|
|
{
|
|
xdbg("ALGORITHM was [$aa] and now [$avp(alg)]\n");
|
|
ims_www_challenge("REG_MAR_REPLY", "$td", "$avp(alg)");
|
|
}
|
|
|
|
######################################################################
|
|
# Apply privacy, if requested
|
|
######################################################################
|
|
route[apply_privacy]
|
|
{
|
|
if (is_present_hf("Privacy") && ($hdr(Privacy)=="id")) {
|
|
remove_hf("P-Asserted-Identity");
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# Originating, Intial Requests
|
|
######################################################################
|
|
route[orig]
|
|
{
|
|
xlog("L_DBG","Enter orig route\n");
|
|
set_dlg_profile("orig");
|
|
|
|
# we MAYBE need something like this to check if a user is barred
|
|
# if (S_originating_barred()){
|
|
# sl_send_reply("403","Forbidden - Originating Public Identity barred");
|
|
# exit;
|
|
# }
|
|
|
|
if (is_method("INVITE|SUBSCRIBE")) {
|
|
$avp(RR_CUSTOM_USER_AVP)="mo";
|
|
record_route();
|
|
}
|
|
|
|
# Start new transaction:
|
|
t_newtran();
|
|
|
|
# check if dialog saved as fwded to AS
|
|
if (isc_match_filter("orig", "location")) {
|
|
t_on_failure("isc_orig_failure");
|
|
xlog("Orig - msg was fwded to AS\n");
|
|
exit;
|
|
}
|
|
|
|
if (!isc_from_as("orig")) {
|
|
remove_hf("P-Asserted-Identity");
|
|
append_hf("P-Asserted-Identity: <sip:$fU@$fd>\r\n");
|
|
}
|
|
|
|
#!ifdef WITH_RO
|
|
# before we allow call - lets check credit
|
|
if (is_method("INVITE")) {
|
|
xlog("L_DBG","Sending initial CCR Request for call\n");
|
|
$var(cc_ret) = Ro_CCR("CHARGING_CCR_ORIG_REPLY", "orig", 30, "0", "0");
|
|
if ($var(cc_ret) < 0) {
|
|
xlog("L_ERR","CCR Request failure\n");
|
|
sl_send_reply("402","Payment required");
|
|
exit;
|
|
}
|
|
xlog("L_DBG","CCR Request success\n");
|
|
exit;
|
|
}
|
|
#!endif
|
|
route(FINAL_ORIG);
|
|
}
|
|
|
|
route[FINAL_ORIG]
|
|
{
|
|
# Check for PSTN destinations:
|
|
if (is_method("INVITE")) {
|
|
route(PSTN_handling);
|
|
}
|
|
|
|
t_on_reply("orig_reply");
|
|
|
|
t_relay();
|
|
}
|
|
|
|
route[CHARGING_CCR_ORIG_REPLY]
|
|
{
|
|
xlog("L_DBG","cca_return code is $avp(s:cca_return_code)\n");
|
|
|
|
switch ($avp(s:cca_return_code)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "CCR success - will route message\n");
|
|
route(FINAL_ORIG);
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "CCR failure - error response sent from module\n");
|
|
switch ($avp(s:cca_result_code)) {
|
|
case 5030:
|
|
send_reply("403", "Charging User not found");
|
|
break;
|
|
case 5031:
|
|
send_reply("403", "Rating failed");
|
|
break;
|
|
case 4010:
|
|
send_reply("402", "Payment required - Unsufficient funds");
|
|
break;
|
|
case 5006:
|
|
send_reply("486", "Line limit exceeded");
|
|
break;
|
|
default:
|
|
send_reply("402","Payment required ($avp(s:cca_result_code))");
|
|
break;
|
|
}
|
|
case -2: #error
|
|
xlog("L_ERR", "CCR error - error response sent from module\n");
|
|
send_reply("500", "Charging Error");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from CCR: [$avp(s:cca_return_code)] \n");
|
|
send_reply("500", "Charging Error");
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
|
|
######################################################################
|
|
# Replies to the Initial Requests
|
|
######################################################################
|
|
onreply_route[orig_reply]
|
|
{
|
|
xlog("L_DBG","Orig reply\n");
|
|
|
|
route(apply_privacy);
|
|
break;
|
|
}
|
|
|
|
######################################################################
|
|
# Originating, subsequent requests
|
|
######################################################################
|
|
route[orig_subsequent]
|
|
{
|
|
xlog("L_DBG","Orig_Subsequent\n");
|
|
|
|
if (!is_method("ACK")) {
|
|
t_on_reply("orig_subsequent_reply");
|
|
}
|
|
t_relay();
|
|
}
|
|
|
|
######################################################################
|
|
# Replies for originating, subsequent requests
|
|
######################################################################
|
|
onreply_route[orig_subsequent_reply]
|
|
{
|
|
xlog("L_DBG","Orig_Subsequent_reply\n");
|
|
route(apply_privacy);
|
|
break;
|
|
}
|
|
|
|
######################################################################
|
|
# Failure-Route for Requests to an AS
|
|
######################################################################
|
|
failure_route[isc_orig_failure]
|
|
{
|
|
xlog("L_DBG","ISC_Orig_failure\n");
|
|
|
|
if (t_check_status("(408)|(5..)")){
|
|
t_on_failure("isc_orig_failure");
|
|
if (isc_match_filter("orig","location")){
|
|
xlog("L_DBG","ISC_Orig_failure - msg was fwded to AS\n");
|
|
exit;
|
|
}
|
|
|
|
if (isc_from_as("origfail")) {
|
|
remove_hf("P-Asserted-Identity");
|
|
append_hf("P-Asserted-Identity: <sip:$fU@$fd>\r\n");
|
|
}
|
|
|
|
t_on_reply("orig_reply");
|
|
|
|
t_relay();
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# Terminating requests
|
|
######################################################################
|
|
route[term]
|
|
{
|
|
xlog("L_DBG","Term\n");
|
|
|
|
set_dlg_profile("term");
|
|
|
|
#we need something like this to check if a user is barred
|
|
# if (S_terminating_barred()){
|
|
# sl_send_reply("404","Not Found - Terminating user barred");
|
|
# exit;
|
|
# }
|
|
|
|
if (is_method("INVITE|SUBSCRIBE")) {
|
|
$avp(RR_CUSTOM_USER_AVP)="mt";
|
|
$avp(i:20)="mt";
|
|
record_route();
|
|
}
|
|
|
|
# check if dialog saved as fwded to AS
|
|
if (isc_match_filter("term","location")){
|
|
t_on_failure("isc_term_failure");
|
|
xlog("L_DBG","Term - msg was fwded to AS\n");
|
|
exit;
|
|
}
|
|
|
|
#!ifdef WITH_RO_TERM
|
|
# before we allow call - lets check credit
|
|
if (is_method("INVITE")) {
|
|
xlog("L_DBG","Sending initial CCR Request for call\n");
|
|
$var(cc_ret) = Ro_CCR("CHARGING_CCR_TERM_REPLY", "term", 30, "0", "0");
|
|
if ($var(cc_ret) < 0) {
|
|
xlog("L_ERR","CCR Request failure\n");
|
|
sl_send_reply("402","Payment required");
|
|
exit;
|
|
}
|
|
xlog("L_DBG","CCR Request success\n");
|
|
exit;
|
|
}
|
|
#!endif
|
|
route(FINAL_TERM);
|
|
}
|
|
|
|
route[FINAL_TERM] {
|
|
if (lookup("location")) {
|
|
if (uri==myself) {
|
|
if (!t_newtran()) {
|
|
sl_reply_error();
|
|
exit;
|
|
}
|
|
t_reply("404","Not Found - destination user not found on this S-CSCF");
|
|
exit;
|
|
}
|
|
} else {
|
|
# User not registered? Reply with 404.
|
|
if (!t_newtran()) {
|
|
sl_reply_error();
|
|
exit;
|
|
}
|
|
t_reply("404","Not Found - destination user not found on this S-CSCF");
|
|
exit;
|
|
}
|
|
route(apply_privacy);
|
|
|
|
t_relay();
|
|
}
|
|
|
|
|
|
route[CHARGING_CCR_TERM_REPLY]
|
|
{
|
|
xlog("L_DBG","cca_return code is $avp(s:cca_return_code)\n");
|
|
|
|
switch ($avp(s:cca_return_code)) {
|
|
case 1: #success
|
|
xlog("L_DBG", "CCR success - will route message\n");
|
|
route(FINAL_TERM);
|
|
break;
|
|
case -1: #failure
|
|
xlog("L_ERR", "CCR failure - error response sent from module\n");
|
|
switch ($avp(s:cca_result_code)) {
|
|
case 5030:
|
|
send_reply("403", "Charging User not found");
|
|
break;
|
|
case 5031:
|
|
send_reply("403", "Rating failed");
|
|
break;
|
|
case 4010:
|
|
send_reply("402", "Payment required - Unsufficient funds");
|
|
break;
|
|
case 5006:
|
|
send_reply("486", "Line limit exceeded");
|
|
break;
|
|
default:
|
|
send_reply("402","Payment required ($avp(s:cca_result_code))");
|
|
break;
|
|
}
|
|
case -2: #error
|
|
xlog("L_ERR", "CCR error - error response sent from module\n");
|
|
send_reply("500", "Charging Error");
|
|
break;
|
|
default:
|
|
xlog("L_ERR", "Unknown return code from CCR: [$avp(s:cca_return_code)] \n");
|
|
send_reply("500", "Charging Error");
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
|
|
######################################################################
|
|
# Failure Route for Terminating requests
|
|
######################################################################
|
|
failure_route[isc_term_failure]
|
|
{
|
|
xlog("L_DBG","ISC_term_failure\n");
|
|
|
|
if (t_check_status("(408)|(5..)")){
|
|
t_on_failure("isc_term_failure");
|
|
if (isc_match_filter("term","location")){
|
|
xlog("L_DBG","Term - msg was fwded to AS\n");
|
|
exit;
|
|
}
|
|
|
|
if (lookup("location")) {
|
|
if (uri==myself) {
|
|
t_reply("404","Not Found - destination user not found on this S-CSCF");
|
|
exit;
|
|
}
|
|
} else {
|
|
t_reply("404","Not Found - destination user not found on this S-CSCF");
|
|
exit;
|
|
}
|
|
t_relay();
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# Terminating, subsequent requests
|
|
######################################################################
|
|
route[term_subsequent]
|
|
{
|
|
xlog("L_DBG","term_subsequent\n");
|
|
route(apply_privacy);
|
|
t_relay();
|
|
}
|
|
|
|
######################################################################
|
|
# Check for PSTN destinations:
|
|
######################################################################
|
|
route[PSTN_handling]
|
|
{
|
|
# First, we translate "tel:"-URI's to SIP-URI's:
|
|
# $ru: tel:+(34)-999-888-777
|
|
# $fu: sip:test@foo.com
|
|
# becomes $ru: sip:+34999888777@foo.com;user=phone
|
|
if (tel2sip2("$ru", "$fd", "$ru") < 0)
|
|
xlog("L_WARN","Failed to convert $ru to a sip:-URI - M=$rm R=$ru F=$fu T=$tu IP=$si:$sp ID=$ci\n\n");
|
|
|
|
if ($rU =~ "\+[0-9]+") {
|
|
# Now let's check, if the number can be found in ENUM:
|
|
if(!enum_query()) {
|
|
# ENUM failed, send it to the PSTN-Gateway:
|
|
route(PSTN);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# Send calls to the PSTN-Gateways:
|
|
######################################################################
|
|
route[PSTN]
|
|
{
|
|
$var(has_trf) = 0;
|
|
if (is_present_hf("Feature-Caps")) {
|
|
xlog("Feature-Caps: $hdr(Feature-Caps) => $(hdr(Feature-Caps){param.value,+g.3gpp.trf}{nameaddr.uri}{uri.host})\n");
|
|
if ($(hdr(Feature-Caps){param.value,+g.3gpp.trf}) != $null) {
|
|
$rd = $(hdr(Feature-Caps){param.value,+g.3gpp.trf}{nameaddr.uri}{uri.host});
|
|
if (!strempty($(ou{uri.params}))) {
|
|
$ru = $ru+";"+$(ou{uri.params});
|
|
}
|
|
|
|
t_on_failure("TRF_failure");
|
|
if (t_relay_to("0x02")) {
|
|
$var(has_trf) = 1;
|
|
} else {
|
|
xlog("Relay to $du failed.\n");
|
|
$du = $null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($var(has_trf) == 0) {
|
|
if (!ds_select_domain("1", "4")) {
|
|
xlog("L_WARN","No PSTN-Gateways available - M=$rm R=$ru F=$fu T=$tu IP=$si:$sp ID=$ci\n\n");
|
|
send_reply("503", "Service not available");
|
|
exit;
|
|
}
|
|
if (!strempty($(ou{uri.params}))) {
|
|
$ru = $ru+";"+$(ou{uri.params});
|
|
}
|
|
t_relay();
|
|
}
|
|
# Relay the request:
|
|
t_on_failure("PSTN_failure");
|
|
|
|
exit;
|
|
}
|
|
|
|
######################################################################
|
|
# manage failure routing cases, perform failover
|
|
######################################################################
|
|
failure_route[TRF_failure] {
|
|
xlog("TRF_failure\n");
|
|
# Choose another gateway, in case we
|
|
# - get a local generated "408"
|
|
# - receive a 5xx or 6xx reply from the proxy.
|
|
if (t_branch_timeout() || t_check_status("[5-6]..")) {
|
|
$du = $null;
|
|
if (!ds_select_domain("1", "4")) {
|
|
xlog("L_WARN","No PSTN-Gateways available - M=$rm R=$ru F=$fu T=$tu IP=$si:$sp ID=$ci\n\n");
|
|
send_reply("503", "Service not available");
|
|
exit;
|
|
}
|
|
if (!strempty($(ou{uri.params}))) {
|
|
$ru = $ru+";"+$(ou{uri.params});
|
|
}
|
|
# Relay the request:
|
|
t_on_failure("PSTN_failure");
|
|
|
|
t_relay();
|
|
exit;
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# manage failure routing cases, perform failover
|
|
######################################################################
|
|
failure_route[PSTN_failure] {
|
|
# Choose another gateway, in case we
|
|
# - get a local generated "408"
|
|
# - receive a 5xx or 6xx reply from the proxy.
|
|
if (t_branch_timeout() || t_check_status("[5-6]..")) {
|
|
if (ds_next_domain()) {
|
|
if (!strempty($(ou{uri.params}))) {
|
|
$ru = $ru+";"+$(ou{uri.params});
|
|
}
|
|
# Do Failover in case problems:
|
|
t_on_failure("PSTN_failure");
|
|
t_relay();
|
|
} else {
|
|
# Add a header, to indicate the phone should try again in 30 seconds.
|
|
append_hf("Retry-After: 30\r\n");
|
|
send_reply("503", "Service not available");
|
|
}
|
|
exit;
|
|
}
|
|
}
|