#!KAMAILIO

# ----------------- Error-Logging ---------------
debug=2
log_stderror=no
#configure the /etc/syslog.conf for this feature
#log_facility=LOG_LOCAL1

# ----------------- Basic-Settings ---------------
fork=yes
children=2
check_via=no
dns=no
rev_dns=no
listen=127.0.0.1

port=5060

sip_warning=0

############################
# TCP-Support
############################
disable_tcp=yes

disable_core_dump=yes
auto_aliases=no
tos=0x80

# ------------------ module loading ----------------------------------
mpath="sip-router/modules_k:sip-router/modules"
# To Check/modufy the maximum forwards
loadmodule "maxfwd.so"
# Transaction-Module
loadmodule "tm.so"
# For Stateless replies
loadmodule "sl.so"
# Extended Logging
loadmodule "xlog.so"
# Record-/Loose-Routing-Module (RFC3261)
loadmodule "rr.so"
# NAT-Traversal
loadmodule "nathelper.so"
loadmodule "rtpproxy.so"
# Generic Utilities (formerly options.so and uri.so)
loadmodule "siputils.so"
# MI-FIFO-Wrapper
loadmodule "mi_fifo.so"
# MI-XML-RPC-Wrapper
loadmodule "mi_rpc.so"
loadmodule "mi_xmlrpc.so"

# Module for Pseudo-Variables
loadmodule "pv.so"
# Module for Dialog 
loadmodule "dialog.so"
# Sanity: Check if request is ok by syntax
loadmodule "sanity.so"
# Textops provides the method "is_method"
loadmodule "textops.so"
# UAC provides the method "uac_replace_from"
loadmodule "uac.so"
loadmodule "kex.so"
loadmodule "tmx.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"

# ----------------- Settings for Nathelper ---------------
# Nathelper: RTP-Proxy-List
modparam("rtpproxy", "rtpproxy_sock", "udp:localhost:22222")
# Nathelper: RTP-Proxy Timeout
modparam("rtpproxy", "rtpproxy_tout", 3)
modparam("rtpproxy", "timeout_socket", "xmlrpc:http://localhost:8000/RPC2")

# ----------------- Settings for max-fwd ---------------
# Max-Forward-Module: Set the maximum to 20
modparam("maxfwd", "max_limit", 20)

# ----------------- Settings for rr ---------------
# RR Module: Enable the From-Tag in RR-Header
modparam("rr", "append_fromtag", 1)

# ----------------- Settings for mi_fifo-Wrapper ---------------
modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")

# ----------------- Settings for mi_XML_RPC ---------------
# The Port for incoming XML-RPC requests
modparam("mi_xmlrpc", "port", 8000)
# Method-Response: A single string parameter should be replied.
# See: http://www.kamailio.org/docs/modules/1.2.x/mi_xmlrpc.html#AEN102
modparam("mi_xmlrpc", "reply_option", 1)
# The size of the Buffer used to create the XML-RPC-Request-Node
modparam("mi_xmlrpc", "buffer_size",  8192)
# The logfile for the xml-rpc server 
# #modparam("mi_xmlrpc", "log_file", "/tmp/kamailio_xmlrpc")

# ----------------- Settings for Dialog-Module ---------------
# The Name of the Tag in the RR-Route-Header (default "did")
modparam("dialog", "rr_param", "rtp")
# Flag to be used for marking if a dialog should be constructed for the current request (make sense only for initial requests).
modparam("dialog", "dlg_flag", 1)
# The default dialog timeout (in seconds) if no custom one is set. Default value is "43200 (12 hours)".
modparam("dialog", "default_timeout", 7230)

# How the seqential requests should be matched against the known dialogs.
# The modes are a combination between matching based on a cookie (DID) stored as cookie in Record-Route header and the matching based on SIP elements (as in RFC3261).
# The supported modes are:
# 0 - DID_ONLY - the match is done exclusivly based on DID (default);
# 1 - DID_FALLBACK - the match is first tried based on DID and if not present, it will fallback to SIP matching;
# 2 - DID_NONE - the match is done exclusivly based on SIP elements; no DID information is added in RR.
modparam("dialog", "dlg_match_mode", 1)
# Describe how to push into the DB the dialogs' information from memory.
# The supported modes are:
# 0 - NO_DB - the memory content is not flushed into DB;
# 1 - REALTIME - any dialog information changes will be reflected into the database immediatly.
# 2 - DELAYED - the dialog information changes will be flushed into DB periodically, based on a timre routine.
modparam("dialog", "db_mode", 0)
# The interval (seconds) at which to update dialogs' information if you chose to store the dialogs' info at a given interval.
# A too short interval will generate intensiv database operations, a too large one will not notice short dialogs.
# Default value is "60".
# modparam("dialog", "db_update_period", 100)
# The number of dialogs to be fetched per loop
#modparam("dialog", "db_fetch_rows", 120)

modparam("registrar", "max_expires", 10);
modparam("registrar", "received_avp", "$avp(i:100)");
modparam("nathelper", "received_avp", "$avp(i:100)");

route {
	if (!is_method("REGISTER"))
		xlog("L_ERR", "$rm from $fU to $rU ($ci)\n");
	route(1);
	
	##################################################################################################################
	# Subsequential requests
	###############################################################################################################
	if (has_totag() && !is_method("REGISTER")) {
		route(2);
	}

	##################################################################################################################
	# Record-Route, damit alle Nachrichten ueber diesen SIP-Proxy laufen
	###############################################################################################################
	if (!is_method("REGISTER|MESSAGE")) record_route();

	if (loose_route()) {
		# This is not from a proxy, decline the request. This is not allowed.
		log(1, "Preloaded Route, not to ourselfs\n");
		if (!is_method("ACK")) send_reply("403", "Preload Route denied");
		exit;
	}

	##################################################################################################################
	# BYE and ACK Requests should always have an To-Tag, if they follow RFC
	###############################################################################################################
	if (is_method("BYE")) {
		send_reply("400", "Missing to-tag");
		exit;
	}
	if (is_method("ACK")) {
		exit;		
	}

	##################################################################################################################
	# We only allow INVITE's towards the Class IV, no other methods allowed:
	# RFC: 21.4.6 405 Method Not Allowed
	# The method specified in the Request-Line is understood, but not allowed for the address identified by the Request-URI.
	###############################################################################################################
	if (is_method("REGISTER")) {
		fix_nated_register();
		save("location");
		exit;
	}


	##################################################################################################################
	# We only allow INVITE's towards the Class IV, no other methods allowed:
	# RFC: 21.4.6 405 Method Not Allowed
	# The method specified in the Request-Line is understood, but not allowed for the address identified by the Request-URI.
	###############################################################################################################
	if (!is_method("INVITE")) {
		send_reply("405", "Method Not Allowed");
		exit;
	}
	fix_nated_contact();

	if (!lookup("location")) {
		send_reply("404", "Not found");
		exit;
	}

	##################################################################################################################
	# The dialog module should be aware of this dialog:
	###############################################################################################################
	setflag(1);

	##################################################################################################################
	# Use RTP-Proxy
	###############################################################################################################
	if (!rtpproxy_offer("arf")) {
		sl_send_reply("503", "No RTP-Relay available");
		exit;
	}
	t_on_reply("1");

	# Relay this statefully
	t_relay();

	exit;	
}

##################################################################################################################
# Route for standard-checks (e. g. too many hops, re-transmits, CANCEL without a transaction)
###############################################################################################################
route[1] {
	##################################################################################################################
	# Sanity: Check if the syntax of the request is ok
	# The following checks are available:
	#
	# * ruri sip version - (1) - checks if the SIP version in the request URI is supported, currently only 2.0.
	# * ruri scheme - (2) - checks if the URI scheme of the request URI is supported (sip[s]|tel[s]) by Kamailio.
	# * required headers - (4) -checks if the minimum set of required headers to, from, cseq, callid and via is 
	#	present in the request.
	# * via sip version - (8) - not working because parser fails already when another version then 2.0 is present.
	# * via protocol - (16) - not working because parser fails already if an unsupported transport is present.
	# * cseq method - (32) - checks if the method from the cseq header is equal to the request method.
	# * cseq value - (64) - checks if the number in the cseq header is a valid unsigend integer.
	# * content length - (128) - checks if the size of the body matches with the value from the content length header.
	# * expires value - (256) - checks if the value of the expires header is a valid unsigned integer.
	# * proxy require - (512) - checks if all items of the proxy require header are present in the list of the
	#	extensions from the module parameter proxy_require.
	# * parse uri's - (1024) - checks if the specified URIs are present and parseable by the Kamailio parsers
	# * digest credentials (2048) Check all instances of digest credentials in a message. The test checks whether
	#	there are all required digest parameters and have meaningful values. 
	###############################################################################################################
	if (is_method("INVITE")) {
		# Checks: 1, 2, 4, 32, 64, 128, 1024 (with all URI's)
		if (!sanity_check("1255")) {
			xlog("malformed message from $si:$sp ($rm)\n");
			exit;
		}	
	} else if (is_method("REGISTER")) {
		# Checks: 1, 2, 4, 32, 64, 256, 1024 (with all URI's)
		if (!sanity_check("1383")) {
			xlog("malformed message from $si:$sp ($rm)\n");
			exit;
		}	
	}

	##################################################################################################################
	# Check for too many hops
	###############################################################################################################
	if (!mf_process_maxfwd_header("20")) {
	 	if (!is_method("ACK")) send_reply("483","To Many Hops");
	 	exit;
	};
	
	##################################################################################################################
	# Standard-Options-Requests beantworten
	###############################################################################################################
	# xlog("L_ERR", "$rm $ru ($rU)\n");
	if (is_method("OPTIONS")) {
		# xlog("L_ERR", "$$rU not set or ping: $rU\n");
		options_reply();
		exit;
	}	

	##################################################################################################################
	# Check for Re-Transmissions (nicht bei ACK/CANCEL)
	###############################################################################################################
	if (!is_method("CANCEL|ACK|PRACK")) {
		if (t_check_trans()) {
			# log(1, "Re-Transmission detected, message dropped.\n");
			# Drop the message silently.
			exit;
		}
	}

	##################################################################################################################
	# CANCEL without Transaction? Drop it. Otherwise: relay them.
	###############################################################################################################
	if (is_method("CANCEL")) {
		# In case the INVITE is not finally processed (and so no TA is available), the SIP-UA must re-transmit.
		if (!t_check_trans()) {
			# No according transaction exists, just relay the cancel.
			if (!forward()) {
				xlog("L_ERR", "Unable to forward $rm $ru\n"); 
			}
			exit;
		}
		# There is a Transaction for this CANCEL
		if (!t_relay()) {
			exit;
		}
		exit;
	}
}

##################################################################################################################
# Route processing subsequential requests
###############################################################################################################
route[2] {
	##################################################################################################################
	# Record-Route, damit alle Nachrichten �ber diesen SIP-Proxy laufen
	###############################################################################################################
	if (!is_method("MESSAGE")) record_route();
	
	##################################################################################################################
	# Loose-Routing (RFC3261)
	###############################################################################################################
	# Record-Route-Header entfernen
	if (!loose_route()) {
		##################################################################################################################
		# Non loose, but stateful ACK: Relay.
		###############################################################################################################
		if (is_method("ACK") && (!t_check_trans())) {
			forward();
			exit;
		}
	}
		
	##################################################################################################################
	# Retrieve NAT-Information from URI
	# + NAT-Handling
	###############################################################################################################
	t_on_reply("1");

	# This is a BYE? Tear down session on the RTP-Proxy.
	if (is_method("BYE")) {
		xlog("L_ERR", "RTP-Statistic: $rtpstat\n");
		unforce_rtp_proxy();
	}

	# Relay this statefully
	t_relay();
	# Exit here.
	exit;	
}

##################################################################################################################
# Antwort-Route (Nathelper/RTP-Proxy)
###############################################################################################################
onreply_route[1] {	
	# A Transaction from a NATed Client to a NATed Client? Use the RTP-Proxy!
	if (status=~"(180)|(183)|(2[0-9][0-9])") {
		fix_nated_contact();
		# Content-Length prüfen
		if (!search("^Content-Length:[ ]*0")) {
			rtpproxy_answer("arf");
                }
        }
}

#route[XMLRPC]{
#	if search("^User-Agent:.*xmlrpclib"))
#		set_reply_close();
#	set_reply_no_connect(); # optional
#	dispatch_rpc();
#}
