#!KAMAILIO
#
# Kamailio SIP Server v5.2 - default configuration script
#     - web: https://www.kamailio.org
#     - git: https://github.com/kamailio/kamailio
#
# Direct your questions about this file to: <sr-users@lists.kamailio.org>
#
# Refer to the Core CookBook at https://www.kamailio.org/wiki/
# for an explanation of possible statements, functions and parameters.
#

####### Defined Values #########

# the specific address for this node
#!define IPADDR_THISNODE "192.168.178.75"
#!subst "/IPADDR_THISNODE/192.168.178.75/"

# the specific address of the pair node in the anycast deployment
#!define IPADDR_PAIRNODE "192.168.178.74"
#!subst "/IPADDR_PAIRNODE/192.168.178.74/"

# the anycast address
#!define IPADDR_ANYCAST  "192.168.178.80"
#!subst "/IPADDR_ANYCAST/192.168.178.80/"

# the address of the main sip server where to route requests to
# [UA1] <===> [ANYCASTNODE] <===> [MAINSRV] <===> [ANYCASTNODE] <===> [UA2]
#!define IPADDR_MAINSRV  "192.168.178.40"
#!subst "/IPADDR_MAINSRV/192.168.178.40/"

#!define MULTIDOMAIN 0

# - flags
#   FLT_ - per transaction (message) flags
#	FLB_ - per branch flags
#!define FLT_ACC 1
#!define FLT_ACCMISSED 2
#!define FLT_ACCFAILED 3
#!define FLT_NATS 5

#!define FLB_NATB 6
#!define FLB_NATSIPPING 7

####### Global Parameters #########

### LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR
#!ifdef WITH_DEBUG
debug=4
log_stderror=yes
#!else
debug=2
log_stderror=no
#!endif

memdbg=5
memlog=5

log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "

/* number of SIP routing processes */
children=8

server_id = 10
xavp_via_params = "via"

/* uncomment the next line to disable TCP (default on) */
# disable_tcp=yes

/* uncomment the next line to disable the auto discovery of local aliases
 * based on reverse DNS on IPs (default on) */
# auto_aliases=no

/* add local domain aliases */
# alias="sip.mydomain.com"

/* listen on local and anycast addresses */
listen=udp:IPADDR_THISNODE:5060
# listen=udp:IPADDR_ANYCAST:5060


####### Custom Parameters #########

/* These parameters can be modified runtime via RPC interface
 * - see the documentation of 'cfg_rpc' module.
 *
 * Format: group.id = value 'desc' description
 * Access: $sel(cfg_get.group.id) or @cfg_get.group.id */

####### Modules Section ########

/* set paths to location of modules */
loadmodule "jsonrpcs.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
loadmodule "acc.so"
loadmodule "counters.so"

# ----------------- setting module-specific parameters ---------------


# ----- jsonrpcs params -----
modparam("jsonrpcs", "pretty_format", 1)
/* set the path to RPC fifo control file */
# modparam("jsonrpcs", "fifo_name", "/run/kamailio/kamailio_rpc.fifo")
/* set the path to RPC unix socket control file */
# modparam("jsonrpcs", "dgram_socket", "/run/kamailio/kamailio_rpc.sock")

# ----- ctl params -----
/* set the path to RPC unix socket control file */
# modparam("ctl", "binrpc", "unix:/run/kamailio/kamailio_ctl")

# ----- tm params -----
# auto-discard branches from previous serial forking leg
modparam("tm", "failure_reply_mode", 3)
# default retransmission timeout: 30sec
modparam("tm", "fr_timer", 30000)
# default invite retransmission timeout after 1xx: 120sec
modparam("tm", "fr_inv_timer", 120000)

# ----- rr params -----
# set next param to 1 to add value to ;lr param (helps with some UAs)
modparam("rr", "enable_full_lr", 0)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)

# ----- acc params -----
/* what special events should be accounted ? */
modparam("acc", "early_media", 0)
modparam("acc", "report_ack", 0)
modparam("acc", "report_cancels", 0)
/* by default ww do not adjust the direct of the sequential requests.
 * if you enable this parameter, be sure the enable "append_fromtag"
 * in "rr" module */
modparam("acc", "detect_direction", 0)
/* account triggers (flags) */
modparam("acc", "log_flag", FLT_ACC)
modparam("acc", "log_missed_flag", FLT_ACCMISSED)
modparam("acc", "log_extra",
	"src_user=$fU;src_domain=$fd;src_ip=$si;"
	"dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)

####### Routing Logic ########


/* Main SIP request routing logic
 * - processing of any incoming SIP request starts with this route
 * - note: this is the same as route { ... } */
request_route {

	# per request initial checks
	route(REQINIT);

	# CANCEL processing
	if (is_method("CANCEL")) {
		if (t_check_trans()) {
			route(RELAY);
		}
		exit;
	}

	# handle retransmissions
	if (!is_method("ACK")) {
		if(t_precheck_trans()) {
			t_check_trans();
			exit;
		}
		t_check_trans();
	}

	# handle requests within SIP dialogs
	route(WITHINDLG);

	### only initial requests (no To tag)

	# record routing for dialog forming requests (in case they are routed)
	# - remove preloaded route headers
	remove_hf("Route");
	if (is_method("INVITE|SUBSCRIBE")) {
		record_route();
	}

	# account only INVITEs
	if (is_method("INVITE")) {
		setflag(FLT_ACC); # do accounting
	}

	if ($rU==$null) {
		# request with no Username in RURI
		sl_send_reply("484","Address Incomplete");
		exit;
	}

	if($si != IPADDR_MAINSRV) {
		# received from client - send to main sip server
		$du = "sip:" + IPADDR_MAINSRV;
		route(RELAY);
		exit;
	}

	# received from main server - send to client
	# add via tokens for anycast handling
	via_add_srvid("1");
	$xavp(via=>node) = IPADDR_THISNODE;
	via_add_xavp_params("1");
	route(RELAY);
	exit;
}

# Wrapper for relaying requests
route[RELAY] {

	# enable additional event routes for forwarded requests
	# - serial forking, RTP relaying handling, a.s.o.
	if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
		if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
	}
	if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
		if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
	}
	if (is_method("INVITE")) {
		if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
	}

	if (!t_relay()) {
		sl_reply_error();
	}
	exit;
}

# Per SIP request initial checks
route[REQINIT] {
	if($ua =~ "friendly-scanner|sipcli|VaxSIPUserAgent") {
		# silent drop for scanners - uncomment next line if want to reply
		# sl_send_reply("200", "OK");
		exit;
	}

	if (!mf_process_maxfwd_header("10")) {
		sl_send_reply("483","Too Many Hops");
		exit;
	}

	if(is_method("OPTIONS") && uri==myself && $rU==$null) {
		sl_send_reply("200","Keepalive");
		exit;
	}

	if(!sanity_check("1511", "7")) {
		xlog("Malformed SIP message from $si:$sp\n");
		exit;
	}
}

# Handle requests within SIP dialogs
route[WITHINDLG] {
	if (!has_totag()) return;

	# sequential request withing a dialog should
	# take the path determined by record-routing
	if (loose_route()) {
		if (is_method("BYE")) {
			setflag(FLT_ACC); # do accounting ...
			setflag(FLT_ACCFAILED); # ... even if the transaction fails
		} else if ( is_method("NOTIFY") ) {
			# Add Record-Route for in-dialog NOTIFY as per RFC 6665.
			record_route();
		}
		route(RELAY);
		exit;
	}

	if ( is_method("ACK") ) {
		if ( t_check_trans() ) {
			# no loose-route, but stateful ACK;
			# must be an ACK after a 487
			# or e.g. 404 from upstream server
			route(RELAY);
			exit;
		} else {
			# ACK without matching transaction ... ignore and discard
			exit;
		}
	}
	sl_send_reply("404","Not here");
	exit;
}

# TM manage for outgoing branches
branch_route[MANAGE_BRANCH] {
	xdbg("new branch [$T_branch_idx] to $ru\n");
}

# TM manage for incoming replies
onreply_route[MANAGE_REPLY] {
	xdbg("incoming reply\n");
}

# TM manage for failure routing cases
failure_route[MANAGE_FAILURE] {
	if (t_is_canceled()) exit;
}

# Core handling for incoming replies
reply_route {
	if($si != IPADDR_MAINSRV) {
		if($si == IPADDR_PAIRNODE) {
			# receiving a transparent proxied request from pair server
			if(is_present_hf("X-Src-Addr")) {
				# set the original source IP address
				xinfo("setting source address: $hdr(X-Src-Addr)\n");
				set_source_address("$hdr(X-Src-Addr)");
				remove_hf("X-Src-Addr");
			}
			# switch received socket to anycast address
			set_recv_socket("udp:IPADDR_ANYCAST:5060");
		} else {
			# receiving response from client
			# response belongs to a transaction?
			#	- yes: route it, request was handled here
			#	- no: send to pair server
			if(!t_check_trans()) {
				append_hf("X-Src-Addr: $su\r\n");
				# $var(vd) = $(hdr(Via){s.select, ,-1}{param.value,node});
				$var(vd) = $sel(via.params["node"]);
				xinfo("via param domain: $var(vd)\n");
				sendx("sip:$var(vd)", "udp:IPADDR_THISNODE:5060", "$mbu");
				drop();
			}
		}
	}
	# from now on, the usual sip response processing
}
