<?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 Admin Guide -->

<chapter xmlns:xi="http://www.w3.org/2001/XInclude">
	<title>&adminguide;</title>

	<section>
		<title>Overview</title>
		<para>
			This module was designed to act as a mechanism to limit call duration based on credit information parameters.
			After getting the credit information of the call being set up, you can instruct the module to start monitoring
			the consumed credit to shutdown a single call or a group of calls in case of credit exhaustion.
		</para>
		<para>
			Every call is associated to an unique client/customer identifier. If a credit event occurs, all calls hooked
			to this identifier are automatically shutdown.
		</para>
		<para>
			Cnxcc is dialog-aware so there's no need to explicitly allocate/deallocate the monitoring.
			The <emphasis>dlg_manage()</emphasis> function must be called in the configuration file for the dialog to be tracked.
		</para>
		<para>
			The credit discount rate is proportional to the number of calls grouped inside an identifier. Once the setup
			of the first call is done, the information remains while the call is active. If the customer starts a new call with
			the same routing criteria, it will land in the same monitoring bag and it will consume the same pool of credit in
			rates that are equal to the cost per second of both calls.
		</para>
		<para>
			If your accounting program does not maintain the state of the call in real time, this module can provide you
			with that ability.
		</para>
		<para>
			Cnxcc can also provide more common means of monitoring, i.e., by time limit or by maximum simultaneous calls.
		</para>


	</section>

	<section>
		<title>Dependencies</title>
		<section>
			<title>Modules</title>
			<para>
				The following module must be loaded before this module:
				<itemizedlist>
					<listitem>
						<para>
							<emphasis>dialog</emphasis>
						</para>
					</listitem>
				</itemizedlist>
			</para>
		</section>
		<section>
			<title>Libraries</title>
			<para>
				The following module must be loaded before this module:
				<itemizedlist>
					<listitem>
						<para>
							<emphasis> hiredis-devel >= 0.11.0 </emphasis>
						</para>
					</listitem>
					<listitem>
						<para>
							<emphasis> libevent-devel >= 2.0.18-2 </emphasis>
						</para>
					</listitem>

				</itemizedlist>
			</para>
		</section>

	</section>

	<section>
		<title>Parameters</title>
		<section id="cnxcc.p.redis">
			<title><varname>redis</varname> (integer)</title>
			<para>
				Redis datasource connection information
			</para>
			<example>
				<title>redis parameter</title>
				<programlisting format="linespecific">
...
modparam("cnxcc", "redis", "addr=127.0.0.1;port=6379;db=1")
...
</programlisting>
			</example>
		</section>

		<section id="cnxcc.p.credit_check_period">
			<title><varname>credit_check_period</varname> (integer)</title>
			<para>
				Indicates how often the credit checking function should be called. It is directly related to the precision of the
				module. The maximum precision is 1, which means that every call is checked every one second.

			</para>
			<para>
				Values greater than 1 leads to precision lost but less CPU consumption.
			</para>
			<example>
				<title>credit_check_period parameter</title>
				<programlisting format="linespecific">
...
modparam("cnxcc", "credit_check_period", 1)
...
</programlisting>
			</example>
		</section>
	</section>

	<section>
		<title>Functions</title>
		<section id="cnxcc.f.set_max_credit">
			<title>
				<function moreinfo="none">cnxcc_set_max_credit(customer, maxcredit, connect, cps, ipulse, fpulse)</function>
			</title>
			<note>
				The <emphasis>dlg_manage()</emphasis> function must be called in the configuration file to ensure
				dialog is tracked.
			</note>
			<para>
				Associates the call with a customer id and sets the max credit,
				connect cost, cost per second, initial pulse and final pulse. The discount
				is calculated in pulses (1/1, 60/1, etc) and subtracted from the pool
				of credit.
			</para>
			<para>
				The customer value can be provided as a string or a variable holding
				a string. This value identifies all calls from the same customer.
			</para>
			<para>
				The maxcredit (float) value is the maximum credit available for the current call.
			</para>
			<para>
				The connect (float) value is the connect cost for the current call.
			</para>
			<para>
				The cps (float) value is the cost per second for the current call.
			</para>
			<para>
				The ipuse (integer) value is the initial pulse and establishes the minimum
				time to be charged. For example, value 1 establishes a charge per second
				and value 60 sets a charge per minute. If it is taken as value 60, even
				if the duration is 5 seconds, 1 minute will be charged.
			</para>
			<para>
				The fpulse (integer) value is the final pulse and establishes, from the initial
				pulse, the time range to be charged. For example, the value 1 establishes a charge
				per second, 5 sets a charge in blocks of 5 seconds, 60 sets a full minute charge.
			</para>
			<para>
				1/1 will make a charge per seconds for the entire call. 60/1 will make a
				charge per seconds with the first full minute. 60/60 always perform
				a full minute charge.
			</para>
			<para>
				<emphasis>Return code:</emphasis>
				<itemizedlist>
					<listitem>
						<para>
							<emphasis>1 - successful</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-1 - failed, error logged</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-4 - call-id already present for this client</emphasis>
						</para>
					</listitem>
				</itemizedlist>
			</para>
			<example>
				<title>cnxcc_set_max_credit()</title>
				<programlisting format="linespecific">
...
cnxcc_set_max_credit("john-doe", "100", "3.0", "0.5", 60, 1);
...
$var(customer)  = "john-doe"; # customer id
$var(credit)    = "100";      # max credit for all calls with the same
                              # customer id
$var(connect)   = "3.0";      # connect cost or initial cost for the call
$var(cps)       = "0.5";      # cost per second
$var(initial_p) = 60;         # initial pulse (60 = the first minute will be
                              # charged even if the call is shorter)
$var(final_p)   = 1;          # final pulse (after the first minute, it will
                              # be charge in ranges of 1 second)
cnxcc_set_max_credit("$var(customer)", "$var(credit)", "$var(connect)",
        "$var(cps)", "$var(initial_p)", "$var(final_p)");
...
</programlisting>
			</example>
		</section>

		<section id="cnxcc.f.set_max_time">
			<title>
				<function moreinfo="none">cnxcc_set_max_time(customer, maxtime)</function>
			</title>
			<note>
				The <emphasis>dlg_manage()</emphasis> function must be called in the configuration file to ensure
				dialog is tracked.
			</note>
			<para>
				Specifies the amount of time the call should last at most.
			</para>
			<para>
				The customer value can be provided as a string or a variable holding
				a string.
			</para>
			<para>
				The maxtime value is an integer values, it can be also given
				via a variable holding an integer.
			</para>
			<para>
				<emphasis>Return code:</emphasis>
				<itemizedlist>
					<listitem>
						<para>
							<emphasis>1 - successful</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-1 - failed, error logged</emphasis>
						</para>
					</listitem>
					<listitem>
						<para>
							<emphasis>-4 - call-id already present for this client</emphasis>
						</para>
					</listitem>
				</itemizedlist>
			</para>
			<example>
				<title>cnxcc_set_max_time()</title>
				<programlisting format="linespecific">
...
$var(customer) = "john-doe-basic";
$var(max_time) = 120;
cnxcc_set_max_time("$var(customer)", "$var(max_time)");
...
</programlisting>
			</example>
		</section>

		<section id="cnxcc.f.update_max_time">
			<title>
				<function moreinfo="none">cnxcc_update_max_time(customer, maxtime)</function>
			</title>
			<note>
				The <emphasis>dlg_manage()</emphasis> function must be called in the configuration file to ensure
				dialog is tracked.
			</note>
			<para>
				Updates max-time of an established and monitored call. This can
				be used to grant minimum values and to update them every short
				periods on time as a mean to prevent frauds and/or to mimic
				requested/granted units of time of Credit Control Application
				behavior.
			</para>
			<para>
				The customer value can be provided as a string or a variable holding
				a string.
			</para>
			<para>
				The maxtime value is an integer values, it can be also given
				via a variable holding an integer.
			</para>
			<para>
				<emphasis>Return code:</emphasis>
				<itemizedlist>
					<listitem>
						<para>
							<emphasis>1 - successful</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-1 - failed, error logged</emphasis>
						</para>
					</listitem>
				</itemizedlist>
			</para>
			<example>
				<title>cnxcc_update_max_time()</title>
				<programlisting format="linespecific">
...
$var(client)       = "john-doe-basic";
$var(update_time)  = 5;

if (!cnxcc_update_max_time("$var(client)", "$var(update_time)")) {
	xlog("Error updating max-time");
	return;
	}
...
</programlisting>
			</example>
		</section>


		<section id="cnxcc.f.set_max_channel">
			<title>
				<function moreinfo="none">cnxcc_set_max_channel(customer, maxchan)</function>
			</title>
			<note>
				The <emphasis>dlg_manage()</emphasis> function must be called in the configuration file to ensure
				dialog is tracked.
			</note>
			<para>
				Specifies a limit for the number of simultaneous calls.
			</para>
			<para>
				The customer value can be provided as a string or a variable holding
				a string.
			</para>
			<para>
				The maxchan value is an integer values, it can be also given
				via a variable holding an integer.
			</para>
			<para>
				<emphasis>Return code:</emphasis>
				<itemizedlist>
					<listitem>
						<para>
							<emphasis>1 - successful</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-1 - failed, error logged</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-2 - failed, calls established plus calls
								being established result in more than the limit
								you specified</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-3 - failed, number of calls established
								is more than the limit you specified</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-4 - call-id already present for this client</emphasis>
						</para>
					</listitem>
				</itemizedlist>
			</para>
			<example>
				<title>cnxcc_set_max_channels()</title>
				<programlisting format="linespecific">
...
$var(customer)  = "john-doe-123-basic";
$var(max_chan)  = 2;
$var(retcode)   = cnxcc_set_max_channels("$var(customer)", "$var(max_chan)");

if ($var(retcode) == -1) {
	xlog("Error setting up credit control");
	return;
}

if ($var(retcode) &lt; -1) {
	xlog("Too many channels for customer");
	sl_send_reply(403, "Forbidden");

	if (!cnxcc_terminate_all("$var(customer)")) {
		xlog("Error terminating customer's calls");
	}

	exit;
}
...
</programlisting>
			</example>
		</section>

		<section id="cnxcc.f.terminate_all">
			<title>
				<function moreinfo="none">cnxcc_terminate_all(customer)</function>
			</title>
			<para>
				Terminates all calls of the specified customer/profile.
			</para>
			<para>
				The customer value can be provided as a string or a variable holding
				a string.
			</para>
			<para>
				<emphasis>Return code:</emphasis>
				<itemizedlist>
					<listitem>
						<para>
							<emphasis>1 - successful</emphasis>
						</para>
					</listitem>

					<listitem>
						<para>
							<emphasis>-1 - failed, error logged</emphasis>
						</para>
					</listitem>
				</itemizedlist>
			</para>
			<example>
				<title>cnxcc_set_max_time()</title>
				<programlisting format="linespecific">
...
$var(customer)  = "john-doe-123-basic";

if (!cnxcc_terminate_all("$var(customer)")) {
	xlog("Error terminating customer's calls");
}
...
</programlisting>
			</example>
		</section>
	</section>

	<section>
		<title>RPC Commands</title>

		<section id="cnxcc.rpc.active_clients">
			<title>cnxcc.active_clients</title>
			<para>
				Retrieves all calls grouped by their identifiers.
			</para>
			<para>
				Parameters: <emphasis>none</emphasis>
			</para>
			<para>
				Example:
			</para>
			<programlisting format="linespecific">
...
&sercmd; cnxcc.active_clients
...
</programlisting>
		</section>

		<section id="cnxcc.rpc.check_client">
			<title>cnxcc.check_client</title>
			<para>
				Retrieves all calls from a particular identifier.
			</para>
			<para>
				Parameters: <emphasis>client/customer identifier</emphasis>
			</para>
			<para>
				Example:
			</para>
			<programlisting format="linespecific">
...
&sercmd; cnxcc.check_client john-doe-premium
...
</programlisting>
		</section>

		<section id="cnxcc.rpc.kill_call">
			<title>cnxcc.kill_call</title>
			<para>
				Kills an active call using its call ID.
			</para>
			<para>
				Parameters: <emphasis>Call-ID</emphasis>
			</para>
			<para>
				Example:
			</para>
			<programlisting format="linespecific">
....
&sercmd; cnxcc.kill_call test@carlosrdcnx-laptop.site
...
</programlisting>
		</section>
		<section id="cnxcc.rpc.stats">
			<title>cnxcc.stats</title>
			<para>
				List credit control stats.
			</para>
			<para>
				Parameters: <emphasis>none</emphasis>
			</para>
			<para>
				Example:
			</para>
			<programlisting format="linespecific">
...
&sercmd; cnxcc.stats
...
</programlisting>
		</section>

	</section>

	<section id="cnxcc.evr.callshutdown">
		<title>Events</title>

		<para>
			When a call is forced to end an event route is automatically invoked. This route is suited with a fake OPTIONS
			message containing the call ID, ftag and ttag of the original call so it can be located somehow in the accounting
			database.
		</para>
		<para>
			Example:
		</para>
		<programlisting format="linespecific">
...
event_route[cnxcc:call-shutdown]
{
	xlog("L_INFO", "[$ci]: call killed");

	# perform some kind of notification, database update, email sending, etc.
}
...
</programlisting>

	</section>
	<section>
		<title>Web Interface</title>

		<para>
			The module contains a web management interface completely optional. With it, you can review your calls in real time
			and hang them up if necessary.
		</para>
		<para>
			Link: https://github.com/caruizdiaz/cnxcc-web
		</para>
	</section>

	<section>
		<title>Sample Config</title>
		<example>
			<title>kamailio-cnxcc.cfg</title>
			<programlisting format="linespecific">
...
route[CNXCC]
{
	$var(client)              = "test-client";
	$var(credit)              = "50";
	$var(connect_cost)        = "3.0";
	$var(cost_per_sec)        = "0.5";
	$var(i_pulse)             = 30;
	$var(f_pulse)             = 6;


	cnxcc_set_max_credit("$var(client)",
			"$var(credit)",
			"$var(connect_cost)",
			"$var(cost_per_sec)",
			"$var(i_pulse)",
			"$var(f_pulse)");

	switch ($?) {
		case -1:
			xerr("Error setting up credit control");
			sl_send_reply("503", "Internal Server Error");
		case -4:
			xwarn("$ci already present for client $var(client)");
	};
}

event_route[cnxcc:call-shutdown]
{
	xlog("L_INFO", "[$ci]: call killed");
}
...
</programlisting>
		</example>
	</section>

</chapter>
