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

<chapter>
	<chapterinfo>
	<revhistory>
		<revision>
		<revnumber>$Revision: 2241 $</revnumber>
		<date>$Date: 2007-05-17 19:48:49 +0300 (Thu, 17 May 2007) $</date>
		</revision>
	</revhistory>
	</chapterinfo>
	<title>User's Guide</title>
	
	<section>
	<title>Overview</title>
	<para>
		Least cost routing (LCR) module implements two related capabilities:
	</para>
	<para>
		<itemizedlist>
			<listitem>
			<para>
				sequential forwarding of a request to one or more gateways
				(functions load_gws and next_gw)
			</para>
			</listitem>
			<listitem>
			<para>
				sequential forwarding to contacts if they don't share the
				the same qvalue (functions load_contacts and next_contacts).
			</para>
			</listitem>
		</itemizedlist>
	</para>
	<para>
	Gateway selection is based on caller's RPID URI (if available in
	caller's RPID AVP after authentication) or From URI and user part of
	Request-URI (telephone number).  A gateway matches a request if user
	part of Request-URI and "From" URI match the prefix and From pattern
	of the gateway.  Matching gateways are then ordered for forwarding
	purpose (1) according to longest user part match, (2) according to
	gateway's priority, and (3) randomly.
	</para>
	<para>
	Each gateway belongs to a gateway group either alone or among other
	gateways.  All gateways in a group share the same priority.
	</para>
	<para>
	Gateway and routing information is kept in two tables: gw and lcr.
	</para>
	<para>
	When a gateway is selected, the Request-URI user part is stripped by 
	the number of digits specified in the strip parameter. Subsequently,
	the Request-URI is rewritten with information from gw table:
	URI scheme, prefix, IP address, port, and transport protocol.  Valid
	URI scheme values are NULL = sip, 1 = sip and 2 = sips.  Prefix is
	appended in front of Request-URI user part. Currently valid transport
	protocol values are NULL = none, 1 = udp, 2 = tcp, and 3 = tls.
	</para>
	<para>
	Table lcr contains prefix of user part of Request-URI, From URI,
	gateway group id, and priority.  From URI is a regular
	expression.  Empty From URI pattern matches any From
	URI.  Smaller priority value means higher priority (highest
	priority value being 0).
	</para>
	<para>
	In addition to gw and lcr tables there is third table gw_grp that is
	used to associate names with gateway group ids.
	</para>
	</section>

	<section>
	<title>Dependencies</title>
	<section>
	<title>&ser; modules</title>
	<para>
		The following modules must be loaded before this module:
		<itemizedlist>
		<listitem>
		<para>
			<emphasis>TM module</emphasis>
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>A database module like mysql, postgres or 
			dbtext</emphasis>.
		</para>
		</listitem>
		</itemizedlist>
	</para>
	</section>
	<section>
	<title>External libraries or applications</title>
	<para>
		The following libraries or applications must be installed before
		running &ser; with this module:
			<itemizedlist>
			<listitem>
			<para>
				<emphasis>none</emphasis>.
			</para>
			</listitem>
			</itemizedlist>
	</para>
	</section>
	</section>

	<section>
	<title>Exported Parameters</title>
	<section>
		<title><varname>db_url</varname> (string)</title>
		<para>
		&url; of the database table to be used.
		</para>
		<para>
		<emphasis>
			Default value is 
			<quote>mysql://openserro:openserro@localhost/openser</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>db_url</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","db_url","mysql://muser:pwd@localhost/openser")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>gw_table</varname> (string)</title>
		<para>
		Name of the table holding the gateways definitions.
		</para>
		<para>
		<emphasis>
			Default value is <quote>gw</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>gw_table</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","gw_table","gw")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>gw_name_column</varname> (string)</title>
		<para>
		Name of the column holding the gateway name.
		</para>
		<para>
		<emphasis>
			Default value is <quote>gw_name</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>gw_name_column</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","gw_name_column","gw_name")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>ip_addr_column</varname> (string)</title>
		<para>
		Name of the column holding the IP address of the gateway.
		</para>
		<para>
		<emphasis>
			Default value is <quote>ip_addr</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>ip_addr_column</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","ip_addr_column","ip_addr")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>port_column</varname> (string)</title>
		<para>
		Name of the column holding the port number of the gateway.
		</para>
		<para>
		<emphasis>
			Default value is <quote>port</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>port_column</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","port_column","port")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>uri_scheme_column</varname> (string)</title>
		<para>
		Name of the column holding the uri scheme of the gateway.
		</para>
		<para>
		<emphasis>
			Default value is <quote>uri_scheme</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>uri_scheme_column</varname> module 
		parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","uri_scheme_column","scheme")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>transport_column</varname> (string)</title>
		<para>
		Name of the column holding the transport type to be used for 
		the gateway.
		</para>
		<para>
		<emphasis>
			Default value is <quote>transport</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>transport_column</varname> module 
		parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","transport_column","transport")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>grp_id_column</varname> (string)</title>
		<para>
		Name of the column holding the group ID.
		</para>
		<para>
		<emphasis>
			Default value is <quote>grp_id</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>grp_id_column</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","grp_id_column","grp_id")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>lcr_table</varname> (string)</title>
		<para>
		Name of the table holding the LCR rules.
		</para>
		<para>
		<emphasis>
			Default value is <quote>lcr</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>lcr_table</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","lcr_table","lcr")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>strip_column</varname> (string)</title>
		<para>
		Name of the column holding the number of digits to strip from the RURI before applying the prefix.
		</para>
		<para>
		<emphasis>
			Default value is <quote>strip</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>strip_column</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","strip_column","strip")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>prefix_column</varname> (string)</title>
		<para>
		Name of the column holding the RURI(destination) prefix.
		</para>
		<para>
		<emphasis>
			Default value is <quote>prefix</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>prefix_column</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","prefix_column","prefix")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>from_uri_column</varname> (string)</title>
		<para>
		Name of the column holding the FROM (source) URI.
		</para>
		<para>
		<emphasis>
			Default value is <quote>from_uri</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>from_uri_column</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","from_uri_column","from_uri")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>priority_column</varname> (string)</title>
		<para>
		Name of the column holding the priority of the rule.
		</para>
		<para>
		<emphasis>
			Default value is <quote>priority</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>priority_column</varname> module parameter
			</title>
		<programlisting format="linespecific">
...
modparam("lcr","priority_column","priority")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>gw_uri_avp</varname> (string)</title>
		<para>
   Overrides the name of the AVP containing URI scheme, host, port, and
   transport of a gateway.  If the string name of the AVP contains only
   digits, the name of the AVP is integer value of the string.
		</para>
		<para>
		<emphasis>
			Default value is <quote>1400</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>gw_uri_avp</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","gw_uri_avp","1400")
...
</programlisting>
		</example>
	</section>
<section>
		<title><varname>ruri_user_avp</varname> (string)</title>
		<para>
   Overrides the name of the AVP containing user part of Request-URI
   after the first next_gw() call.  If the string
   name of the AVP contains only digits, the name of the AVP is integer
   value of the string.
		</para>
		<para>
		<emphasis>
			Default value is <quote>1402</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>ruri_user_avp</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","ruri_user_avp","500")
...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>contact_avp</varname> (string)</title>
		<para>
		Overrides the name of the AVP containing the contact. If the string 
		name of the AVP contains only digits, the name of the AVP is integer 
		value of the string.
		</para>
		<para>
		<emphasis>
			Default value is <quote>1401</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>contact_avp</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","contact_avp","1401")

...
</programlisting>
		</example>
	</section>

<section>
		<title><varname>fr_inv_timer_avp</varname> (string)</title>
		<para>
		Overrides the name of the AVP carrying the Final Response timeout 
		for INVITEs.
		</para>
		<para>
		<emphasis>
			Default value is <quote>fr_inv_timer_avp</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>fr_inv_timer_avp</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","fr_inv_timer_avp","fr_inv_timer_avp")
...
</programlisting>
		</example>
	</section>

	<section>
		<title><varname>fr_inv_timer</varname> (integer)</title>
		<para>
		Sets the value of the fist INVITE's Final Response timeout to be used 
		during sequential forwarding:
		</para>
		<para>
		<emphasis>
			Default value is 90.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>fr_inv_timer</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","fr_inv_timer",90)
...
</programlisting>
		</example>
	</section>

	<section>
		<title><varname>fr_inv_timer_next</varname> (integer)</title>
		<para>
		Sets the value of the next INVITE's Final Response timeouts to be used 
		during sequential forwarding:
		</para>
		<para>
		Function next_contacts() sets tm fr_inv_timer to fr_inv_timer_next
		value if, after next contacts, there are still lower qvalue
		contacts available, and to fr_inv_timer value if next contacts are
		the last ones left.
		</para>
		<para>
		<emphasis>
			Default value is 30.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>fr_inv_timer_next</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","fr_inv_timer_next",30)
...
</programlisting>
		</example>
	</section>

	<section>
		<title><varname>rpid_avp</varname> (string)</title>
		<para>
		Sets the string name of the AVP containing the RPID.
		</para>
		<para>
		<emphasis>
			Default value is <quote>rpid</quote>.
		</emphasis>
		</para>
		<example>
		<title>Setting <varname>rpid_avp</varname> module parameter</title>
		<programlisting format="linespecific">
...
modparam("lcr","rpid_avp","rpid")
...
</programlisting>
		</example>
	</section>
	</section>

	<section>
	<title>Exported Functions</title>
	<section>
		<title>
		<function moreinfo="none">load_gws([group-id])</function>
		</title>
		<para>
		Loads URI schemes, addresses, ports, and transports of gateways
		that match user part of Request-URI to gw_uri_avp AVPs (see Overview
		section). If an optional group-id is specified, only gateways belonging
		to this group are loaded.
		Returns 1 or -1 depending on success.
		</para>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title><function>load_gws</function> usage</title>
		<programlisting format="linespecific">
...
if (!load_gws()) {
	sl_send_reply("500", "Server Internal Error - Cannot load gateways");
	exit;
};
...
</programlisting>
		</example>
		<example>
		<title><function>load_gws</function> usage with group-id</title>
		<programlisting format="linespecific">
...
if (!load_gws("1")) {
	sl_send_reply("500", "Server Internal Error - Cannot load gateways from group 1");
	exit;
};
...
</programlisting>
		</example>
	</section>
	<section>
		<title>
		<function moreinfo="none">next_gw()</function>
		</title>	
		<para>
		If called from a route block, replaces URI scheme, host, port, and
		transport of Request-URI by the values stored in first gw_uri_avp AVP
		and destroys that AVP.  Saves user part of Request-URI into
		ruri_user_avp AVP for use in subsequent next_gw() calls.
		</para>
		<para>
		If called from a failure route block, appends a new branch to
		request, where  URI scheme, host, port, and transport of Request-URI
		is replaced by the values stored in the first gw_uri_avp AVP and
		destroys that AVP.  Request-URI user is taken from ruri_user_avp
		AVP.
		</para>
		<para>
		Returns 1 on success and -1 if there were no gateways left or if an
		error occurred (see syslog).
		</para>
		<para>
		Must be preceded by successful load_gws() call.
		</para>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
		</para>
		<example>
		<title><function>next_gw</function> usage from a route block</title>
		<programlisting format="linespecific">
...
if (!next_gw()) {
	sl_send_reply("503", "Service not available - No gateways");
	exit;
};
...
</programlisting>
		</example>
		<example>
		<title><function>next_gw</function> usage from a failure route block
			</title>
		<programlisting format="linespecific">
...
if (!next_gw()) {
	t_reply("503", "Service not available - No more gateways");
	exit;
};
...
</programlisting>
		</example>
	</section>
	<section>
		<title>
		<function moreinfo="none">from_gw([group-id])</function>
		</title>
		<para>
			Checks if request came from IP address of a gateway. If an
			optional group-id is given, only gateways belonging to this
			group are checked.
		</para>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
		ONREPLY_ROUTE.
		</para>
		<example>
		<title><function>from_gw</function> usage</title>
		<programlisting format="linespecific">
...
if (from_gw()) {
	...
	exit;
};
...
</programlisting>
		</example>
		<example>
		<title><function>from_gw</function> usage with group-id</title>
		<programlisting format="linespecific">
...
if (from_gw("1")) {
	...
	exit;
};
...
</programlisting>
		</example>
		</section>
		<section>
		<title>
		<function moreinfo="none">to_gw([group-id])</function>
		</title>
		<para>
			Checks if in-dialog request goes to a gateway. If an optional
			group-id is given, only gateways belonging to this group
			are checked.
		</para>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
		</para>
		<example>
		<title><function>to_gw</function> usage</title>
		<programlisting format = "linespecific">
...
if (to_gw()) {
	...
	exit;
};
...
</programlisting>
		</example>
		<example>
		<title><function>to_gw</function> usage with group-id</title>
		<programlisting format = "linespecific">
...
if (to_gw("1")) {
	...
	exit;
};
...
</programlisting>
		</example>
	</section>
	<section>
		<title>
		<function moreinfo="none">load_contacts()</function>
		</title>
		<para>
		Loads contacts in destination set in increasing qvalue order as
		values of lcr_contact AVP.  If all contacts in the destination set
		have the same qvalue, load_contacts() does not do anything thus
		minimizing performance impact of sequential forking capability when
		it is not needed.  Returns 1 if loading of contacts succeeded or
		there was nothing to do.  Returns -1 on error (see syslog).
		</para>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title><function>load_contacts</function> usage</title>
		<programlisting format = "linespecific">
...
if (!load_contacts()) {
	sl_send_reply("500", "Server Internal Error - Cannot load contacts");
	exit;
};
...
</programlisting>
		</example>
	</section>
	<section>
		<title>
		<function moreinfo="none">next_contacts()</function>
		</title>
		<para>
		If called from a route block, replaces Request-URI with the first
		lcr_contact AVP value, adds the remaining lcr_contact AVP values 
		with the same qvalue as branches, and destroys those AVPs. It does
		nothing if there are no lcr_contact AVPs.  Returns 1 if there were 
		no errors and -1 if an error occurred (see syslog).
		</para>
		<para>
		If called from a failure route block, adds the first lcr_contact 
		AVP value and all following lcr_contact AVP values with the same 
		qvalue as new branches to request and destroys those AVPs. 
		Returns 1 if new branches were successfully added and -1 on error 
		(see syslog) or if there were no more lcr_contact AVPs.
		</para>
		<para>
		Must be preceded by successful load_contacts() call.
		</para>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
		</para>
		<example>
		<title><function>next_contacts</function> usage from route block
		</title>
		<programlisting format = "linespecific">
...
if (!next_contacts()) {
	sl_send_reply("500", "Server Internal Error");
	exit;
} else {
	t_relay();
};
...
</programlisting>
		</example>
		<example>
		<title><function>next_contacts</function> usage from 
			failure route block
		</title>
		<programlisting format = "linespecific">
if (next_contacts()) {
	t_relay();
};
</programlisting>
		</example>
		</section>
	</section>

	<section>
	<title>Exported MI Commands</title>
		<section>
		<title><function>lcr_reload</function></title>
		<para>
			Causes lcr module to re-read the contents of gateway table
			into memory.
		</para>
		<para>
		Name: <emphasis>lcr_reload</emphasis>
		</para>
		<para>Parameters: <emphasis>none</emphasis></para>
 		<para>
		MI FIFO Command Format:
		</para>
        <programlisting  format="linespecific">
		:lcr_reload:_reply_fifo_file_
		_empty_line_
		</programlisting>
		
		</section>
		
		<section>
		<title><function>lcr_dump</function></title>
		<para>
			Causes lcr module to dump the contents of its in-memory gateway
			table. 
		</para>
		<para>
		Name: <emphasis>lcr_dump</emphasis>
		</para>
		<para>Parameters: <emphasis>none</emphasis></para>
 		<para>
		MI FIFO Command Format:
		</para>
        <programlisting  format="linespecific">
		:lcr_dump:_reply_fifo_file_
		_empty_line_
		</programlisting>
		
		</section>
	</section>
	<section>
	<title>Known Limitations</title>
	<para>
		There is an unlikely race condition on lcr reload. If a process uses
		in memory gw table, which is reloaded at the same time twice through
		FIFO, the second reload will delete the original table still in use
		by the process.
	</para>
	</section>

	<section>
	<title>TODO</title>
	<para>
		Function load_gws() currently makes an SQL query for the matching
		gateways.  In order to avoid the query, also lcr table should be
		read into memory and the corresponding query should be rewritten in
		C.
	</para>
	</section>
</chapter>

<!-- Keep this element at the end of the file
Local Variables:
sgml-parent-document: ("lcr.sgml" "Book" "chapter")
End:
-->
