<?xml version="1.0" encoding='ISO-8859-1'?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [

<!-- Include general documentation entities -->
<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
%docentities;

]>
<!-- Module User's Guide -->

<chapter>
	
	<title>&adminguide;</title>
	
	<section>
	<title>Overview</title>
	<para>This module provides C-API functions to enable &kamailio; to be
	used as an outbound Edge Proxy (see RFC 5626 section 5).</para>
	<para>The <emphasis>path</emphasis> and <emphasis>rr</emphasis> will
	bind to this module if it is loaded before they are.</para>
	<section>
		<title>Edge Proxy Keep-Alives (STUN)</title>
		<para>Outbound Edge Proxies MUST support STUN NAT keep-alives
		on their SIP UDP ports. &kamailio; supports this as a
		compile-time option that is disabled by default.</para>
		<example>
		<title>Compiling &kamailio; with STUN support</title>
		<programlisting><![CDATA[
make FLAVOUR=kamailio cfg STUN=1
make all
]]></programlisting>
		</example>
	</section>
	<section>
		<title>Flow Timer</title>
		<para>The maximum interval at which a User Agent must send a
		keep-alive may be specified by the Registrar using the
		Flow-Timer: header in 2xx responses to REGISTERs.</para>
		<para>When using TCP or TLS as the SIP transport care should
		be taken to set the <quote>tcp_connection_lifetime</quote>
		on the Edge Proxy to a value slightly larger than the interval
		the Registrar is using for flow timer. Setting
		<quote>tcp_connection_lifetime</quote> to less than the
		interval could cause connections to be lost, and setting it
		to a value much larger than the interval will keep connections
		open far longer than is required (which is wasteful).</para>
		<para>Application-layer keep-alives are optional when the
		underlying transport already has a keep-alive mechanism. The
		WebSocket transport has a transport-layer keep-alive. When
		using the WebSocket transport the
		<quote>keepalive_timeout</quote> should be set to a value
		a little greater than the Registrar flow timer interval and a
		little less than the <quote>tcp_connection_lifetime</quote>.
		</para>
	</section>
	<example>
	<title>Edge Proxy Configuration</title>
	<programlisting><![CDATA[
...
#!define FLOW_TIMER	20
...
tcp_connection_lifetime=FLOW_TIMER+10
...
loadmodule "websocket.so"
loadmodule "outbound.so"
loadmodule "rr.so"
loadmodule "path.so"
...
modparam("websocket", "keepalive_timeout", FLOW_TIMER+5)
...
route {
	route(REQINIT);
	...
	t_check_trans();

	if (is_method("INVITE|SUBSCRIBE")) {
		record_route();

		if ($rU==$null) {
			sl_send_reply("484", "Address Incomplete");
			exit;
		}

		if (!loose_route()) {
			switch($rc) {
			case -2:
				# Flow-token has been tampered with
				sl_send_reply("403", "Forbidden");
				exit;
			case -1:
				# Handle -1 here if all dialog forming requests
				# must be outbound routed
			}
		}

		t_on_failure("FAIL_OUTBOUND");
		route(RELAY);
	} else if (is_method("REGISTER")) {
		add_path();
		if (!t_relay("### Registrar ###")) {
			sl_reply_error();
		}
		exit;
	}
}

route[RELAY] {
	if (!t_relay()) {
		sl_send_reply("430", "Flow Failed");
	}
	exit;
}
...
route[WITHINDLG] {
	if (has_totag()) {
		if (!loose_route()) {
			switch($rc) {
			case -2:
				sl_send_reply("403", "Forbidden");
				exit;
			case -1:
				if (is_method("ACK")) {
					if (t_check_trans()) {
						t_relay();
						exit;
					} else {
						exit;
					}
				}
				sl_send_reply("404", "Not Found");
			}
		} else {
			route(RELAY);
		}
		exit;
	}
}
...
onreply_route {
	if (!t_check_trans()) {
		drop;
	}

	if ($rm == "REGISTER" && $rs >= 200 && $rs <= 299)
	{
		if ($(hdr(Require)[*])=~"outbound")
			insert_hf("Flow-Timer: FLOW_TIMER\r\n", "Call-ID");
	}

...
}

failure_route[FAIL_OUTBOUND] {
	if (t_branch_timeout() || !t_branch_replied()) {
		send_reply("430", "Flow Failed");
	}
}
...
]]></programlisting>
	</example>
	<example>
	<title>Registrar Configuration</title>
	<programlisting><![CDATA[
...
loadmodule "tm.so"
...
loadmodule "registrar.so"
...
modparam("tm", "contacts_avp", "tm_contacts")
modparam("tm", "contact_flows_avp", "tm_contact_flows")
...
modparam("registrar", "use_path", 1)
modparam("registrar", "path_mode", 2)
modparam("registrar", "outbound_mode", 2)
...
route[LOCATION] {
...
	if (!lookup("location")) {
		$var(rc) = $rc;
		route(TOVOICEMAIL);
		t_newtran();
		switch ($var(rc)) {
			case -1:
			case -3:
				send_reply("404", "Not Found");
				exit;
			case -2:
				send_reply("405", "Method Not Allowed");
				exit;
		}
	}

	if (!t_load_contacts()) {
		send_reply("500", "Server Internal Error");
		exit;
	}

	if (!t_next_contacts()) {
		send_reply("500", "Server Internal Error");
		exit;
	}

	t_on_failure("FAIL_OUTBOUND");
...
}
...
failure_route[FAIL_OUTBOUND] {
	if (t_check_status("408|430")) {
		if (!t_next_contact_flows() && !t_next_contacts()) {
			send_reply("500", "Server Internal Error");
			exit;
		}
	} else if (!t_next_contacts()) {
		send_reply("500", "Server Internal Error");
		exit;
	}

	t_on_failure("FAIL_OUTBOUND");
	route(RELAY);
}
...
]]></programlisting>
	</example>
	</section>

	<section>
	<title>Dependencies</title>
	<section>
		<title>&kamailio; Modules</title>
		<para>
		The following modules must be loaded before this module:
		<itemizedlist>
		<listitem>
		<para><emphasis>None</emphasis></para>
		</listitem>
		</itemizedlist>
		</para>
	</section>

	<section>
		<title>External Libraries or Applications</title>
		<para>
		The following libraries must be installed before running
		&kamailio; with this module loaded:
		<itemizedlist>
		<listitem>
		<para><emphasis>OpenSSL</emphasis>.</para>
		</listitem>
		</itemizedlist>
		</para>
	</section>
	</section>


	<section>
	<title>Parameters</title>
	<section>
		<title><varname>force_outbound_flag</varname> (integer)</title>
		<para>A flag which, if set for a request, will force
		<emphasis>path</emphasis> and <emphasis>rr</emphasis> to add
		flow tokens to Path: and Record-Route: headers regardless of
		the request contents.</para>
		<para><emphasis>Default value is -1.</emphasis></para>
		<example>
		<title>Set <varname>force_outbound_flag</varname> parameter
		</title>
		<programlisting format="linespecific">
...
modparam("outbound", "force_outbound_flag", 1)
...
</programlisting>
		</example>
	</section>
	</section>

	<section>
	<title>Functions</title>
	<para><emphasis>None</emphasis></para>
	</section>

	<section>
	<title>MI Commands</title>
	<para><emphasis>None</emphasis></para>
	</section>

</chapter>