<?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 "../../../../doc/docbook/entities.xml">
%docentities;

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

<chapter>
	<title>&adminguide;</title>

	<section>
	<title>Overview</title>
	<para>
	The DMQ module implements a distributed message queue on top of Kamailio
	in order to facilitate data propagation and replication between multiple
	instances, referred as "nodes" (or "peers").
	</para>
	<para>
	The DMQ data flow between nodes is grouped in a logical entity referred as
	"channel" (or "bus"), many flows (channels) can be active at the same time.
	</para>
	<para>
	The communication between the nodes is done using SIP messages, after all
	Kamailio's best ability is routing SIP traffic, therefore reusing the same
	protocol empowers DMQ cluster with flexible routing policies, advanced
	authorization and security policies, a.s.o. DMQ sends SIP requests using the
	<emphasis>KDMQ</emphasis> request method (a custom method type specific to
	Kamailio, compliant with SIP specifications RFC3261). Data can be sent to
	all the other active nodes (aka "broadcast") or to a specific single node
	(aka "unicast").
	</para>
	<para>
	The nodes can utilize the DMQ channels to pass messages between them to
	distribute data for various services (e.g., cached items, location records,
	active calls, ...). This grouping of messages on channels (per service)
	is similar to the topic concept in a typical pub/sub system. The channel name
	appears in the R-URI username part of KDMQ requests.
	</para>
	<para>
	The DMQ cluster transparently deals with node discovery, availability,
	consistency, retransmissions, etc. A new node can join the DMQ cluster by
	sending an availability notification to an existing node in the clusters.
	Nodes that are not responding to KDMQ reguests are removed the from local
	list of active nodes, no longer being considered to be part of the KDMQ cluster.
	</para>
	<para>
	IMPORTANT: DMQ must be used only between Kamailio instances having same
	major version. Internal structures can be incompatible between different
	major versions and can lead to crashes or unexpected behaviour.
	</para>
	<section>
		<title>KDMQ Request</title>
		<para>
		KDMQ messages can have different format and content for R-URI username, headers
		and body, being specific to each component that leverages DMQ to replicate
		data, such as <emphasis>htable</emphasis>, <emphasis>dialog</emphasis>
		or <emphasis>usrloc</emphasis> modules.
		</para>
		<para>
		Next request is generated by DMQ module for peers availability notifications.
		</para>
	<example>
		<title>KDMQ Request Example</title>
            <programlisting format="linespecific">
...

KDMQ sip:notification_peer@192.168.40.15:5090 SIP/2.0
Via: SIP/2.0/UDP 192.168.40.15;branch=z9hG4bK55e5.423d95110000
To: &lt;sip:notification_peer@192.168.40.15:5090&gt;
From: &lt;sip:notification_peer@192.168.40.15:5060&gt;;tag=2cdb7a33a7f21abb98fd3a44968e3ffd-5b01
CSeq: 10 KDMQ
Call-ID: 1fe138e07b5d0a7a-50419@192.168.40.15
Content-Length: 116
User-Agent: kamailio (4.3.0 (x86_64/linneaus))
Max-Forwards: 1
Content-Type: text/plain

sip:192.168.40.16:5060;status=active
sip:192.168.40.15:5060;status=disabled
sip:192.168.40.17:5060;status=active

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

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

	<section>
		<title>External Libraries or Applications</title>
		<itemizedlist>
			<listitem>
			<para>
				<emphasis>
				The DMQ module itself has no external dependencies. However,
				each peer may need to use its own (de)serialization mechanism,
				like JSON (via jannson module), XML (via xmlops) or string
				operations with transformations.
				</emphasis>.
			</para>
			</listitem>
		</itemizedlist>
	</section>
	</section>

	<section>
	<title>Parameters</title>
	<section id="dmq.p.server_address">
		<title><varname>server_address</varname>(str)</title>
		<para>
			The local server address. This is the address with which the local DMQ
			node joins the servers group to send/receive messages.
		</para>
		<para>
			Note: if server_socket is not set, then this address has to match a
			local socket, which will be used to send/receive messages.
		</para>
		<para>
		<emphasis>Default value is <quote>NULL</quote>.</emphasis>
		</para>
		<example>
		<title>Set <varname>server_address</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("dmq", "server_address", "sip:10.0.0.20:5060")
...
modparam("dmq", "server_address", "sip:10.0.0.20:5061;transport=tls")
...
</programlisting>
		</example>
	</section>
	<section id="dmq.p.server_socket">
		<title><varname>server_socket</varname>(str)</title>
		<para>
			The local listen address. This is the interface over which the DMQ
			engine will send/receive messages.
		</para>
		<para>
			Note: if this parameter is not set, the socket to send/receive
			messages is built from server_address parameter.
		</para>
		<para>
		<emphasis>Default value is <quote>NULL</quote>.</emphasis>
		</para>
		<example>
		<title>Set <varname>server_socket</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("dmq", "server_socket", "udp:10.0.0.20:5060")
...
</programlisting>
		</example>
	</section>
	<section id="dmq.p.notification_address">
		<title><varname>notification_address</varname>(str)</title>
		<para>
		The address of another DMQ node from which the local node should retrieve initial information about all other nodes.
		This parameter can be specified multiple times in the configuration, to configure multiple notification servers.
		If you configure multiple notification servers, the <emphasis>multi_notify</emphasis> parameter needs to be
		disabled.
		</para>
		<para>
		<emphasis>Default value is <quote>NULL</quote>.</emphasis>
		</para>
		<example>
		<title>Set <varname>notification_address</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("dmq", "notification_address", "sip:10.0.0.21:5060")
...
modparam("dmq", "notification_address", "sip:10.0.0.21:5061;transport=tls")
...
</programlisting>
		</example>
	</section>
	<section id="dmq.p.notification_channel">
		<title><varname>notification_channel</varname>(str)</title>
		<para>
		The name of the channel for notifications about peers availability.
		</para>
		<para>
		<emphasis>Default value is <quote>notification_peer</quote>.</emphasis>
		</para>
		<example>
		<title>Set <varname>notification_channel</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("dmq", "notification_channel", "peers")
...
</programlisting>
		</example>
	</section>
	<section id="dmq.p.multi_notify">
		<title><varname>multi_notify</varname>(int)</title>
		<para>
		Enables the ability to resolve multiple IPv4/IPv6 addresses for
		a single notification address. Please note that this mode is not
		supported if you specify multiple notification address parameter.
		</para>
		<para>
		A value of zero resolves to the first IP address found.
		A non-zero value resolves to all IP addresses associated with the host.
		This includes addresses from DNS SRV records, A and AAAA records.
		</para>
		<para>
		<emphasis>Default value is <quote>0</quote>.</emphasis>
		</para>
		<example>
		<title>Set <varname>multi_notify</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("dmq", "multi_notify", 1)
...
</programlisting>
		</example>
	</section>
        <section id="dmq.p.num_workers">
                <title><varname>num_workers</varname>(int)</title>
                <para>
                The number of worker threads for sending/receiving messages.
                </para>
                <para>
                <emphasis>Default value is <quote>2</quote>.</emphasis>
                </para>
                <example>
                <title>Set <varname>num_workers</varname> parameter</title>
                <programlisting format="linespecific">
...
modparam("dmq", "num_workers", 4)
...
</programlisting>
                </example>
        </section>
	<section id="dmq.p.worker_usleep">
		<title><varname>worker_usleep</varname>(int)</title>
		<para>
		The default locking/synchronisation mechanism between producer/consumer
		threads is the optimum for most environments. On some systems (e.g. FreeBSD)
		it can cause high CPU load and in such cases, it can be useful to disable
		locking and switch to polling for tasks at set intervals instead - putting
		the thread to sleep in-between and taking it out of process during that time.
		</para>
		<para>
		A value >0 will disable the default locking and set the polling interval
		(in microseconds), which can be tuned to suit the specific environment.
		</para>
		<para>
		<emphasis>Default value is 0 (recommended for most systems).</emphasis>
		</para>
		<example>
		<title>Set <varname>worker_usleep</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("dmq", "worker_usleep", 1000)
...
</programlisting>
		</example>
	</section>
        <section id="dmq.p.ping_interval">
                <title><varname>ping_interval</varname>(int)</title>
                <para>
                The number of seconds between node pings (for checking status of other nodes).
                </para>
                <para>
                <emphasis>Minimum value is <quote>60</quote> (default).</emphasis>
                </para>
                <example>
                <title>Set <varname>ping_interval</varname> parameter</title>
                <programlisting format="linespecific">
...
modparam("dmq", "ping_interval", 90)
...
</programlisting>
                </example>
        </section>
	</section>

	<section>
        <title>Functions</title>
        <section id="dmq.f.dmq_handle_message">
                <title>
                <function moreinfo="none">dmq_handle_message([continue])</function>
                </title>
                <para>
                Handles a DMQ message by passing it to the appropriate local peer (module).
		The peer is identified by the user part of the To header.
                </para>
                <para>Meaning of parameters:</para>
                <itemizedlist>
                        <listitem>
                                <para>
                                <emphasis>continue</emphasis> - by default, dmq_handle_message() will end
                                execution of routing script. If this optional parameter is set to "1", dmq_handle_message()
                                will continue executing the routing script after it's been called.
                                </para>
                        </listitem>
                </itemizedlist>
                <para>
                This function can be used from REQUEST_ROUTE.
                </para>

                <example>
                <title><function>dmq_handle_message</function> usage</title>
                <programlisting format="linespecific">
...
    if(is_method("KDMQ")) {
        dmq_handle_message();
    }
...
</programlisting>
                </example>
        </section>
        <section id="dmq.f.dmq_process_message">
                <title>
                <function moreinfo="none">dmq_process_message([continue])</function>
                </title>
                <para>
					Similar to dmq_handle_message, but the processing is happening
					immediately, no longer cloning the request in shared memory
					to be passed to a DMQ worker process.
                </para>
                <para>Meaning of parameters:</para>
                <itemizedlist>
                    <listitem>
                    <para>
                    <emphasis>continue</emphasis> - by default, dmq_process_message() will end
					execution of routing script by returning 0. If this optional parameter
					is set to "1", dmq_process_message() will continue executing the routing
					script after it is been executed, returning 1.
                    </para>
                    </listitem>
                </itemizedlist>
                <para>
                This function can be used from REQUEST_ROUTE.
                </para>

                <example>
                <title><function>dmq_process_message</function> usage</title>
                <programlisting format="linespecific">
...
    if(is_method("KDMQ")) {
        dmq_process_message();
    }
...
</programlisting>
                </example>
        </section>
        <section id="dmq.f.dmq_send_message">
                <title>
               	<function moreinfo="none">dmq_send_message(channel, node, body, content_type)</function>
                </title>
                <para>
                Sends a DMQ message directly from config file to a single node.
                </para>
		<para>Meaning of parameters:</para>
                <itemizedlist>
	                <listitem>
        	                <para>
               	        	<emphasis>channel</emphasis> - name of the channel that should handle the message.
                        	</para>
	                </listitem>
        	        <listitem>
                	        <para>
                       		<emphasis>node</emphasis> - the SIP address of the node to which the message should be sent.
	                        </para>
        	        </listitem>
                	<listitem>
                        	<para>
	                        <emphasis>body</emphasis> - the message body.
	                        </para>
	                </listitem>
                	<listitem>
                        	<para>
	                        <emphasis>content_type</emphasis> - the MIME type of the message body.
	                        </para>
	                </listitem>
		</itemizedlist>
                <para>
                This function can be used from any route.
                </para>

                <example>
                <title><function>dmq_send_message</function> usage</title>
                <programlisting format="linespecific">
...
	dmq_send_message("channel1", "sip:10.0.0.21:5060", "Message body...", "text/plain");
...
</programlisting>
                </example>
        </section>
        <section id="dmq.f.dmq_bcast_message">
                <title>
                <function moreinfo="none">dmq_bcast_message(channel, body, content_type)</function>
                </title>
                <para>
				Broadcasts a DMQ message from config file to all active nodes (except self) on the
				specific channel.
                </para>
                <para>Meaning of parameters:</para>
                <itemizedlist>
                        <listitem>
                                <para>
                                <emphasis>channel</emphasis> - name of the channel that should handle the message.
                                </para>
                        </listitem>
                        <listitem>
                                <para>
                                <emphasis>body</emphasis> - the message body.
                                </para>
                        </listitem>
                        <listitem>
                                <para>
                                <emphasis>content_type</emphasis> - the MIME type of the message body.
                                </para>
                        </listitem>
                </itemizedlist>
                <para>
                This function can be used from any route.
                </para>

                <example>
                <title><function>dmq_bcast_message</function> usage</title>
                <programlisting format="linespecific">
...
    dmq_bcast_message("channel1", "Message body...", "text/plain");
...
</programlisting>
                </example>
        </section>
        <section id="dmq.f.dmq_t_replicate">
                <title>
                <function moreinfo="none">dmq_t_replicate([skip_loop_test])</function>
                </title>
                <para>
					Replicates the current SIP message to all active nodes (except self).
					Useful for replicating REGISTER, PUBLISH etc. in a clustered environment.
                </para>
                <para>Meaning of parameters:</para>
                <itemizedlist>
                        <listitem>
                        <para>
				<emphasis>skip_loop_test</emphasis> - by default, DMQ checks the source IP of the
				message prior to replication, to ensure it has not been sent by another DMQ node
				(to avoid infinite loops). If this optional parameter is set to "1", the loop test
				is not performed. This makes sense, from a performance perspective, if you have
				already performed the necessary checks in the config script (see dmq_is_from_node()).
                        </para>
                        </listitem>
                </itemizedlist>
                <para>
                This function can be used from REQUEST_ROUTE only.
                </para>

                <example>
                <title><function>dmq_t_replicate</function> usage</title>
                <programlisting format="linespecific">
...
    dmq_t_replicate();
...
		</programlisting>
                </example>
        </section>
        <section id="dmq.f.dmq_is_from_node">
                <title>
                <function moreinfo="none">dmq_is_from_node()</function>
                </title>
                <para>
				Checks whether the current message has been sent by another active
				DMQ node in the cluster.
                </para>
                <para>
                This function can be used from REQUEST_ROUTE only.
                </para>

                <example>
                <title><function>dmq_is_from_node</function> usage</title>
                <programlisting format="linespecific">
...
	# basic example for REGISTER replication
    if(is_method("REGISTER")) {
        if (dmq_is_from_node()) {
            # coming from a DMQ node - already authenticated there
            # now just save contact, etc...
        } else {
            # coming from end point - authenticate, save contact, etc...
            dmq_t_replicate("1"); # source address checked, skip the loop test
        }
    }
...
                </programlisting>
                </example>
        </section>

	</section>

	<section>
        <title>RPC Commands</title>
        <section id="dmq.r.list_nodes">
            <title>dmq.list_nodes</title>
			<para>
				List the DMQ nodes. It has no parameters.
			</para>
               <example>
                <title>dmq.list_nodes usage</title>
                <programlisting format="linespecific">
...
&kamcmd; dmq.list_nodes
...
                </programlisting>
                </example>
        </section>
        <section id="dmq.r.remove">
            <title>dmq.remove</title>
			<para>
				Remove a DMQ node by address.
			</para>
			<para>Parameters:</para>
			<itemizedlist>
					<listitem>
					<para>
						<emphasis>address</emphasis> - the SIP address
						of the DMQ node to remove.
					</para>
					</listitem>
			</itemizedlist>

               <example>
                <title>dmq.remove usage</title>
                <programlisting format="linespecific">
...
&kamctl; rpc dmq.remove sip:1.2.3.4:5060
...
                </programlisting>
                </example>
        </section>
	</section>
</chapter>

