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

<chapter>

	<title>&adminguide;</title>

	<section id="overview" xreflabel="Overview">
	<title>Overview</title>
	<para>
	The module contains SIP REGISTER request processing logic, per RFC
	3261.  On top of this support, several extensions are available:
	</para>

	&supported_rfc;

	</section>


	<section id="dependencies" xreflabel="Dependencies">
	<title>Dependencies</title>
	<section>
		<title>&osips; Modules</title>
		<para>
		The following modules must be loaded before this module:
			<itemizedlist>
			<listitem>
			<para>
				<emphasis>usrloc - User Location Module</emphasis>.
			</para>
			</listitem>
			<listitem>
			<para>
				<emphasis>signaling - Signaling module</emphasis>.
			</para>
			</listitem>
			<listitem>
			<para>
				<emphasis>event_routing</emphasis>,
				if <xref linkend="param_pn_enable"/> is set to <emphasis>true</emphasis>.
			</para>
			</listitem>
			</itemizedlist>
		</para>
	</section>
	<section>
		<title>External Libraries or Applications</title>
		<para>
		The following libraries or applications must be installed before
		running &osips; with this module loaded:
			<itemizedlist>
			<listitem>
			<para>
				<emphasis>None</emphasis>.
			</para>
			</listitem>
			</itemizedlist>
		</para>
	</section>
	</section>
	<section id="exported_parameters" xreflabel="Exported Parameters">
	<title>Exported Parameters</title>
	<section id="param_default_expires" xreflabel="default_expires">
		<title><varname>default_expires</varname> (integer)</title>
		<para>
		If the processed message contains neither Expires
		<acronym>HFs</acronym> nor expires contact parameters, this value
		will be used for newly created usrloc records. The parameter contains
		number of second to expire (for example use 3600 for one hour).
		</para>
		<para>
		<emphasis>
			Default value is 3600.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>default_expires</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "default_expires", 1800)
...
</programlisting>
		</example>
	</section>
	<section id="param_min_expires" xreflabel="min_expires">
		<title><varname>min_expires</varname> (integer)</title>
		<para>
		The minimum expires value of a Contact, values lower than this
		minimum will be automatically set to the minimum. Value 0 disables
		the checking.
		</para>
		<para>
		<emphasis>
			Default value is 60.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>min_expires</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "min_expires", 60)
...
</programlisting>
		</example>
	</section>
	<section id="param_max_expires" xreflabel="max_expires">
		<title><varname>max_expires</varname> (integer)</title>
		<para>
		The maximum expires value of a Contact, values higher than this
		maximum will be automatically set to the maximum. Value 0 disables
		the checking.
		</para>
		<para>
		<emphasis>
			Default value is 0.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>max_expires</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "max_expires", 120)
...
</programlisting>
		</example>
	</section>

	<section id="param_default_q" xreflabel="default_q">
		<title><varname>default_q</varname> (integer)</title>
		<para>
		The parameter represents default q value for new contacts. Because
		&osips; doesn't support float parameter types, the value in the parameter
		is divided by 1000 and stored as float. For example, if you want
		default_q to be 0.38, use value 380 here.
		</para>
		<para>
		<emphasis>
			Default value is 0.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>default_q</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "default_q", 1000)
...
</programlisting>
		</example>
	</section>

	<section id="param_tcp_persistent_flag" xreflabel="tcp_persistent_flag">
		<title><varname>tcp_persistent_flag</varname> (string)</title>
		<para>
		The parameter specifies the message flag to be used to control the
		module behaviour regarding TCP connections. If the flag is set for a
		REGISTER via TCP containing a TCP contact, the module, via the
		<quote>save()</quote> function, will set the lifetime of the TCP
		connection to the contact expire value. By doing this, the TCP
		connection will stay on as long as the contact is valid.
		</para>
		<para>
		<emphasis>
			Default value is -1 (disabled).
		</emphasis>
		</para>
		<example>
		<title>Set <varname>tcp_persistent_flag</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "tcp_persistent_flag", "TCP_PERSIST_DURATION")
...
</programlisting>
		</example>
	</section>

	<section id="param_realm_prefix" xreflabel="realm_prefix">
		<title><varname>realm_prefix</varname> (string)</title>
		<para>
		 Prefix to be automatically strip from realm. As an alternative to
		 SRV records (not all SIP clients support SRV lookup), a subdomain of
		 the master domain can be defined for SIP purposes (like
		 sip.mydomain.net pointing to same IP address as the SRV record for
		 mydomain.net). By ignoring the realm_prefix "sip.", at registration,
		 sip.mydomain.net will be equivalent to mydomain.net .
		</para>
		<para>
		<emphasis>
			Default value is NULL (none).
		</emphasis>
		</para>
		<example>
		<title>Set <varname>realm_prefix</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "realm_prefix", "sip.")
...
</programlisting>
		</example>
	</section>


	<section id="param_case_sensitive" xreflabel="case_sensitive">
		<title><varname>case_sensitive</varname> (integer)</title>
		<para>
		If set to 1 then <acronym>AOR</acronym> comparison will be case
		sensitive (as RFC3261 instructs), if set to 0 then
		<acronym>AOR</acronym> comparison will be case insensitive.
		</para>
		<para>
		<emphasis>
			Default value is 1.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>case_sensitive</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "case_sensitive", 0)
...
</programlisting>
		</example>
	</section>

	<section id="param_received_avp" xreflabel="received_avp">
		<title><varname>received_avp</varname> (str)</title>
		<para>
		Registrar will store the value of the AVP configured by this
		parameter in the received column in the user location database.
		It will leave the column empty if the AVP is empty. The AVP should
		contain a SIP URI consisting of the source IP, port,
		and protocol of the REGISTER message being processed.
		</para>
		<note>
		<para>
			The value of this parameter should be the same as the value of
			corresponding parameter of nathelper module.
		</para>
		</note>
		<para>
		<emphasis>
			Default value is "NULL" (disabled).
		</emphasis>
		</para>
		<example>
		<title>Set <varname>received_avp</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "received_avp", "$avp(rcv)")
...
</programlisting>
		</example>
	</section>

	<section id="param_received_param" xreflabel="received_param">
		<title><varname>received_param</varname> (string)</title>
		<para>
		The name of the parameter that will be appended to Contacts of
		200 OK when the received URI was set by nathelper module.
		</para>
		<para>
		<emphasis>
			Default value is "received".
		</emphasis>
		</para>
		<example>
		<title>Set <varname>received_param</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "received_param", "rcv")
...
</programlisting>
		</example>
	</section>

	&reg_modparams;

	<section id="param_retry_after" xreflabel="retry_after">
		<title><varname>retry_after</varname> (integer)</title>
		<para>
		The registrar can generate 5xx reply to REGISTER in various
		situations. It can, for example, happen when the
		<varname>max_contacts</varname> parameter is set and the
		processing of REGISTER request would exceed the limit. In this case
		the registrar would generate "503 Service Unavailable" response.
		</para>
		<para>
		If you want to add the Retry-After header field in 5xx replies, set
		this parameter to a value grater than zero (0 means do not add the
		header field). See section 20.33 of RFC3261 for more details.
		</para>
		<para>
		<emphasis>
			Default value is 0 (disabled).
		</emphasis>
		</para>
		<example>
		<title>Set <varname>retry_after</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "retry_after", 30)
...
		</programlisting>
		</example>
	</section>

	<section id="param_sock_hdr_name" xreflabel="sock_hdr_name">
		<title><varname>sock_hdr_name</varname> (string)</title>
		<para>
		Header which contains a socket description (proto:IP:port) to override
		the received socket info. The header will be search and used only if
		the flag 's' (Socket header) is set at "save()" time.
		</para>
		<para>
		This makes sense only in multiple replicated servers scenarios.
		</para>
		<para>
		<emphasis>
			Default value is NULL.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>sock_hdr_namer</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "sock_hdr_name", "Sock-Info")
...
		</programlisting>
		</example>
	</section>

	<section id="param_mcontact_avp" xreflabel="mcontact_avp">
		<title><varname>mcontact_avp</varname> (string)</title>
		<para>
		AVP to store the modified binding/contact that is set during cached
		registrations scenario (when REGISTER is forwarded to another
		registrar).  The AVP will be used to extract the "expires" value
		returned in the 200 OK by the main registrar.
		</para>
		<para>
		This makes sense only in cached registrations scenario, where your
		OpenSIPS is caching registrations before forwarding them to the main
		registrar.
		</para>
		<para>
		<emphasis>
			Default value is NULL.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>mcontact_avp</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "mcontact_avp", "$avp(orig_ct)")
...
route {
   ...
   # before forwarding the REGISTER request, save the outgoing contact.
   # Be SURE to do it after all the possible changes over the contact,
   # like fix_nated_contact()
   $avp(orig_ct) = $ct.fields(uri);
   t_on_reply("do_save");
   t_relay("udp:ip:port");
   ...
}
...
onreply_route[do_save] {
	if ($rs=="200")
		save("location");
}
...
		</programlisting>
		</example>
	</section>
	<section id="param_attr_avp" xreflabel="attr_avp">
		<title><varname>attr_avp</varname> (string)</title>
		<para>
		AVP to store specific additional information for each registration.
		This information is read from the AVP and stored (in memory, db or both)
		at every registrar 'save'. When a registrar 'lookup' or 'is_registered'
		function is called, the <emphasis>attr_avp</emphasis> is populated with
		the value saved at [re]registration.
		</para>
		<para>
		When doing call forking, the avp will hold multiple values. The position of
		the corresponding attribute information in <emphasis>attr_avp</emphasis> is
		equal to the branch index. An example scenario is given below.
		</para>
		<para>
		<emphasis>
			Default value is NULL.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>attr_avp</varname> parameter</title>
		<programlisting format="linespecific">
# reading attributes from the attr_pvar when doing parallel forking
...
modparam("registrar", "attr_avp", "$avp(attr)")

...
if (is_method("REGISTER")) {
	$avp(attr) = "contact_info";
	save("location");
	exit;
}
...
lookup("location");
t_on_branch("parallel_fork");
...
branch_route [parallel_fork] {
	xlog("Attributes for branch $T_branch_idx: $(avp(attr)[$T_branch_idx])\n");
}

		</programlisting>
		</example>
	</section>
	<section id="param_gruu_secret" xreflabel="gruu_secret">
		<title><varname>gruu_secret</varname> (string)</title>
		<para>
		The string that will be used in XORing when generating
		temporary GRUUs.
		</para>
		<para>
		<emphasis>
			If not set, 'OpenSIPS' is the default secret.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>gruu_secret</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "gruu_secret", "top_secret")
...
		</programlisting>
		</example>
	</section>
	<section id="param_disable_gruu" xreflabel="disable_gruu">
		<title><varname>disable_gruu</varname> (int)</title>
		<para>
			Globally disable GRUU handling
		</para>
		<para>
		<emphasis>
			Default value is 1 ( GRUU will not be handled ).
		</emphasis>
		</para>
		<example>
		<title>Set <varname>gruu_secret</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("registrar", "disable_gruu", 0)
...
		</programlisting>
		</example>
	</section>

	&pn_modparams;

	</section>

	<section id="exported_functions" xreflabel="exported_functions">
	<title>Exported Functions</title>
	<section id="func_save" xreflabel="save()">
		<title>
		<function moreinfo="none">save(domain[, flags[, aor[, ownership_tag]]])</function>
		</title>
		<para>
		The function processes a REGISTER message. It can add, remove or
		modify usrloc records depending on Contact and Expires HFs in the
		REGISTER message. On success, 200 OK will be returned listing all
		contacts that are currently in usrloc. On an error, error message
		will be send with a short description in reason phrase.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
			<emphasis>domain (static string)</emphasis> - Logical domain within
			registrar. If database is used then this must be name of the table which
			stores the contacts.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>flags (string, optional)</emphasis> - string composed of
				one or more of the following flags, comma-separated:
			</para>
			<itemizedlist>
				&save_common_flags;
				<listitem>
					<para><emphasis>'socket-header'</emphasis> - (old
					<emphasis>s</emphasis> flag) look into REGISTER request
					for a header which contains a socket
					description (proto:IP:port). This socket info will be
					stored by register instead of the received socket info.
					</para>
				</listitem>
				<listitem>
					<para><emphasis>'min-expires=[int]'</emphasis> - (old
					<emphasis>e</emphasis> flag) this
					flag can be used to set minimum register expiration time.
					Values lower than this minimum will be automatically set
					to the minimum. Value 0 disables the checking.
					This parameter overrides the global
					<xref linkend="param_min_expires"/> module parameter.
					</para>
				</listitem>
				<listitem>
					<para><emphasis>'max-expires=[int]'</emphasis> - (old
					<emphasis>E</emphasis> flag) this
					flag can be used to set maximum register expiration time.
					Values higher than this maximum will be automatically set
					to the maximum. Value 0 disables the checking.
					This parameter overrides the global
					<xref linkend="param_max_expires"/> module parameter.
					</para>
				</listitem>
			</itemizedlist>
			<para>This parameter is a string composed of a set of flags.</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>aor (string, optional)</emphasis> - a custom AOR; if missing,
			the AOR will be taken from the default place - the TO header URI.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>ownership_tag (string, optional)</emphasis> - a cluster-shared
			tag (see the clusterer module documentation for more details) which
			will be attached to each contact saved from the current request.
			This tag is only relevant in clustered user location scenarios and
			helps determine the current logical owner node of a contact.  This,
			in turn, is useful in order to restrict nodes which are not
			currently responsible for this contact from performing certain
			actions (for example: incorrectly originating pings from a
			non-owned virtual IP address in highly-available setups).
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
		</para>
		<para>
		If you plan to use the <quote>save()</quote> function in reply route,
		please refer to <xref linkend="param_mcontact_avp"/> module parameter.
		</para>
		<example>
		<title><function>save</function> usage</title>
		<programlisting format="linespecific">
...
# save into 'location', no flags, use default AOR (TO URI)
save("location");
...
# save into 'location', do not update DB, max 5 contacts per AOR,
# use default AOR (TO URI)
save("location","memory-only, max-contacts=5");
...
# save into 'location', no flags, use as AOR the FROM URI
save("location","",$fu);
...
# save into 'location', no DB update, force registration, take AOR from AVP
save("location","memory-only, no-reply", $avp(aor));
...
# save into 'location', mark the contacts with the "vip" ownership tag and
# replicate these contacts to the backup node, which does not currently own "vip"
save("location", , , "vip");
...
</programlisting>
		</example>
	</section>

	<section id="func_remove" xreflabel="remove()">
		<title>
		<function moreinfo="none">remove(domain, AOR[, [contact][, [next_hop][, [sip_instance], [bflag]]]])</function>
		</title>
		<para>
		Explicitly remove contacts behind a given address-of-record.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
			<emphasis>domain (static string</emphasis> - Logical domain within the registrar.
			If a database is used, then this must be name of the table which
			stores the contacts.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>AOR (string)</emphasis> - address-of-record to be searched (SIP URI)
			</para>
		</listitem>
		<listitem>
			<para>
				<emphasis>contact (string, optional)</emphasis> - SIP URI filter
				for the contact to be removed. This must be the full SIP URI
				as used during registered.
			</para>
		</listitem>
		<listitem>
			<para>
				<emphasis>next_hop (string, optional)</emphasis> - the next
				SIP IP address/hostname on the way back to this contact. See
				the section below for details on how the next hop is
				computed. Hostnames are resolved before matching.
			</para>
		</listitem>
		<listitem>
			<para>
				<emphasis>sip_instance (string, optional)</emphasis> - a
				"+sip.instance" value to be used for filtering purposes.
			</para>
		</listitem>
		<listitem>
			<para>
				<emphasis>blfag (string, optional)</emphasis> - a
				Branch Flag to be used for filtering purposes.
			</para>
		</listitem>
		</itemizedlist>
		<para>
			<emphasis role='bold'>IMPORTANT: </emphasis>the IP address of each
			contact (for matching purposes) is computed as follows:
			<itemizedlist>
			<listitem>
				<para>
					a. if a Path header is present, the hostname part of the
					Path URI will be resolved as the contact's IP address.
				</para>
			</listitem>
			<listitem>
				<para>
					b. otherwise, if by using nathelper, the "Received" value
					(source IP of the next hop) is set for a contact, this
					becomes the chosen hostname to be resolved as the contact's
					IP address.
				</para>
			</listitem>
			<listitem>
				<para>
					c. otherwise, the "hostname" part of the Contact header
					field URI is chosen to be resolved as the contact's IP
					address.
				</para>
			</listitem>
			</itemizedlist>
		</para>
		<para>
		This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
		</para>
		<example>
		<title><function>remove</function> usage</title>
		<programlisting format="linespecific">
...
# remove all contacts belonging to the "bob" AOR
remove("location", "sip:bob@atlanta.com");
...
# remove only bob's home phone contact
remove("location", "sip:bob@atlanta.com", "sip:bob@46.50.64.78");
...
# remove all bob's phones which are behind "50.60.50.60"
# note that "contact" parameter has to be specified with NULL value even though not used
$var(next_hop) = "50.60.50.60"
remove("location", "sip:bob@atlanta.com", , $var(next_hop));
...
# remove bob's phone with contact "sip:bob@46.50.64.78" that is behind "50.60.50.60"
remove("location", "sip:bob@atlanta.com", "sip:bob@46.50.64.78", "50.60.50.60");
...
# remove all contacts behind bob's mobile device X
remove("location", "sip:bob@atlanta.com", , , "&lt;urn:uuid:e5e68d40-f08a-4600-b82e-ff4d5d8c1a8f&gt;")
</programlisting>
		</example>
	</section>

	<section id="func_remove_ip_port" xreflabel="remove_ip_port()">
		<title>
		<function moreinfo="none">remove_ip_port(IP,Port, domain, [AOR])</function>
		</title>
		<para>
		Remove all contacts behind a specific IP and Port, optionally filtering by AOR.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
				<emphasis>IP (string)</emphasis> - IP of the Contact to be removed
			</para>
		</listitem>
		<listitem>
			<para>
				<emphasis>Port (integer)</emphasis> - Port of the Contact to be removed
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>domain (static string</emphasis> - Logical domain within the registrar.
			If a database is used, then this must be name of the table which
			stores the contacts.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>AOR (string, optional)</emphasis> - address-of-record to be searched (SIP URI)
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from ALL ROUTES.
		</para>
		<example>
		<title><function>remove_ip_port</function> usage</title>
		<programlisting format="linespecific">
...
# remove all contacts behind 8.8.8.8 port 43213
remove_ip_port("8.8.8.8",43213,"location");
...
# remove only bob's contacts behind the 8.8.8.8:43213 host
remove_ip_port("8.8.8.8",43213,"location","sip:bob@atlanta.com");
...
</programlisting>
		</example>
	</section>

	<section id="func_lookup" xreflabel="lookup()">
		<title>
		<function moreinfo="none">lookup(domain [, flags [, aor]])</function>
		</title>
		<para>
		The functions extracts username from Request-URI and tries to find
		all contacts for the username in usrloc. If there are no such
		contacts, -1 will be returned.  If there are such contacts,
		Request-URI will be overwritten with the contact that has
		the highest q value and optionally the rest will be appended to
		the message (depending on append_branches parameter value).
		</para>
		<para>
		If the method_filtering option is enabled, the lookup function
		will return only the contacts that support the method of the
		processed request.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
			<emphasis>domain (static string)</emphasis> - Name of table that
			should be used for the lookup.
			</para>
		</listitem>
		<listitem>
			&lookup_flags;
		</listitem>
		<listitem>
			<para>
			<emphasis>AOR (string, optional)</emphasis> - AOR to lookup for; if
			missing, the RURI is used as AOR;
			</para>
		</listitem>
		</itemizedlist>

		&lookup_retcodes;

		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
		</para>
		<example>
		<title><function>lookup</function> usage</title>
		<programlisting format="linespecific">
...
lookup("location");  # simple lookup
   #or
lookup("location", "method-filtering"); # lookup with method filtering
   #or
lookup("location", "branch"); # lookup with aor branch search;
						# all contacts except the first one shall be put
						# in the branches
   #or
lookup("location", "ua-filtering=/phone/i"); # lookup with user-agent filtering
   #or
lookup("location", "", $var(aor)); # simple lookup with AOR from var
switch ($retcode) {
    case -1:
    case -3:
        sl_send_reply(404, "Not Found");
        exit;
    case -2:
        sl_send_reply(405, "Not Found");
        exit;
};
...
</programlisting>
		</example>
	</section>

	<section id="func_is_registered" xreflabel="is_registered()">
		<title>
		<function moreinfo="none">is_registered(domain ,[AOR])</function>
		</title>
		<para>
		The function returns true if an AOR is registered, false otherwise.
		The function does not modify the message being process.
		</para>
		<para>
		NOTE: if called for a reply (from onreply_route), you must pass an
		AOR (as parameter), otherwise the function will fail.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
			<emphasis>domain (static string)</emphasis> - Name of table that
			should be used for the lookup.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>AOR (string, optional)</emphasis> - AOR to lookup for; if
			missing, the source if the AOR is the "To" header for REGISTER
			request, "From" header for any other sip request.
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
			BRANCH_ROUTE, ONREPLY_ROUTE, LOCAL_ROUTE.
		</para>
		<example>
		<title><function>is_registered</function> usage</title>
		<programlisting format="linespecific">
...
/**/
if (is_method("REGISTER")) {
	/* automatically uses the URI from the To header */
	if (is_registered("location")) {
		xlog("this AOR is registered\n")
		...
	}
};
/* check the From uri whether this aor is registered or not */
if (is_registered("location",$fu)) {
	xlog("caller is registered\n");
}
...
</programlisting>
		</example>
	</section>


	<section id="func_is_contact_registered" xreflabel="is_contact_registered()">
		<title>
		<function moreinfo="none">is_contact_registered(domain ,[AOR],[contact],[callid])</function>
		</title>
		<para>
			The function returns true if a contact and/or a callid from a certain AOR is registered, false otherwise.
		The function does not modify the message being process.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
			<emphasis>domain (static string)</emphasis> - Name of table that should be
			used for the lookup.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>AOR (string, optional)</emphasis> - AOR to lookup for; if
			missing, the source if the AOR is the "To" header for REGISTER
			request, "From" header for any other sip request.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>contact (contact, optional)</emphasis> (optional)- SIP
			URI to check if there is a registration with this URI as cotact
			(this may help you to make distinction between multiple 
			registrations for the same user/AOR).
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>callid (string, optional)</emphasis> - callid to check if a
			contact if registered with this callid (this may help you to
			make distinction between newly registered contact (callid
			not registered so far) and re-registration (callid already
			registered).
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
			BRANCH_ROUTE, ONREPLY_ROUTE, LOCAL_ROUTE.
		</para>
		<example>
		<title><function>is_contact_registered</function> usage</title>
		<programlisting format="linespecific">
...
/* block users which are not registered... */
if (is_method("INVITE")) {
	if (!is_contact_registered("location")) {
		sl_send_reply(401, "Unauthorized");
		...
	}
}

/* ... or check whether the 2nd Contact URI is registered or not */
if (is_method("INVITE")) {
	if (is_contact_registered("location", $fu, $(ct.fields(uri)[1])))
		xlog("caller is registered\n");
}
...
</programlisting>
		</example>
	</section>

	<section id="func_is_ip_registered" xreflabel="is_ip_registered()">
		<title>
		<function moreinfo="none">is_ip_registered(domain ,[AOR],IPvar,[PORTvar])</function>
		</title>
		<para>
			The function returns true if there is at least one contact that has
			been registered from the IP in the IPvar variable ( and from the optional
			PORTvar variable ). 
			The IP is matched against the received host, if it exists, or the contact host otherwise.
			This function does not modify the message being process. This function
		replaces the old "is_other_contact" function.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
			<emphasis>domain (static string)</emphasis> - Name of table that should be
			used for the lookup.
			</para>
		</listitem>
		<listitem>
			<para>
			<emphasis>AOR (string, optional)</emphasis> - AOR to lookup for; if
			missing, the source if the AOR is the "To" header for REGISTER
			request, "From" header for any other sip request.
			</para>
		</listitem>
		<listitem>
			<para>
				<emphasis>IPvar (var)</emphasis> - the variable containing the IP matched against
				the contact host or the received host (see above). If the
				<emphasis>IPvar</emphasis> is an AVP containing multiple values/IPs,
				then all the values are checked.
			</para>
		</listitem>
		<listitem>
			<para>
				<emphasis>PORTvar (var, optional)</emphasis> - the variable containing the port to be
			       	matched against the contact host or the received host (see above). If the
				<emphasis>IPvar</emphasis> is an AVP containing multiple values/IPs, then the PORTvar
				is expected to contain the same number of entries, and all the values are checked.
			</para>
		</listitem>

		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
			BRANCH_ROUTE, ONREPLY_ROUTE, LOCAL_ROUTE.
		</para>
		<example>
		<title><function>is_ip_registered</function> usage</title>
		<programlisting format="linespecific">
...
/* check the source ip  whether it is already registered */
if (is_method("REGISTER")) {
	if (is_ip_registered("location",$tu,$si)) {
		xlog("already registered from this ip\n");
		...
	}
};
...
</programlisting>
		</example>
	</section>



	<section id="func_add_sock_hdr" xreflabel="add_sock_hdr()">
		<title>
		<function moreinfo="none">add_sock_hdr(hdr_name)</function>
		</title>
		<para>
		Adds to the current REGISTER request a new header with
		<quote>hdr_name</quote> which contains the description of the
		received socket (proto:ip:port)
		</para>
		<para>
		This makes sense only in multiple replicated servers scenarios.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para>
			<emphasis>hdr_name (string)</emphasis> - header name to be used.
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title><function>add_sock_hdr</function> usage</title>
		<programlisting format="linespecific">
...
add_sock_hdr("Sock-Info");
...
</programlisting>
		</example>
	</section>
	</section>


	<section>
	<title>Exported Asynchronous Functions</title>

	&pn_async_func;

	</section>


<section>
	<title>Exported Statistics</title>
	<section id="max_expires_stat" xreflabel="max_expires_stat">
		<title><varname>max_expires</varname></title>
		<para>
		Value of max_expires parameter.
		</para>
	</section>
	<section id="max_contacts_stat" xreflabel="max_contacts_stat">
		<title><varname>max_contacts</varname></title>
		<para>
		The value of max_contacts parameter.
		</para>
	</section>
	<section id="defaults_expires" xreflabel="defaults_expires">
		<title><varname>defaults_expires</varname></title>
		<para>
		The value of default_expires parameter.
		</para>
	</section>
	<section id="accepted_regs" xreflabel="accepted_regs">
		<title><varname>accepted_regs</varname></title>
		<para>
		Number of accepted registrations.
		</para>
	</section>
	<section id="rejected_regs" xreflabel="rejected_regs">
		<title><varname>rejected_regs</varname></title>
		<para>
		Number of rejected registrations.
		</para>
	</section>

</section>

</chapter>

