123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- <?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 id="call_control.overview">
- <title>Overview</title>
- <para>
- This module allows one to limit the duration of calls and automatically
- end them when they exceed the imposed limit. Its main use case is to
- implement a prepaid system, but it can also be used to impose a global
- limit on all calls processed by the proxy.
- </para>
- </section>
-
- <section>
- <title>Description</title>
- <para>
- Callcontrol consists of 3 components:
- <itemizedlist>
- <listitem>
- <para>The &kamailio; call_control module</para>
- </listitem>
- <listitem>
- <para>
- An external application called callcontrol which keeps track of
- the calls that have a time limit and automatically ends them when
- they exceed it. This application receives requests from &kamailio;
- and makes requests to a rating engine (see below) to find out if
- a call needs to be limited or not. When a call ends (or is ended)
- it will also instruct the rating engine to debit the balance for
- the caller with the consumed amount. The callcontrol application
- is available from http://callcontrol.ag-projects.com/
- </para>
- </listitem>
- <listitem>
- <para>
- A rating engine that is used to calculate the time limit based on
- the caller's credit and the destination price and to debit the
- caller's balance after a call ends. This is available as part of
- CDRTool from http://cdrtool.ag-projects.com/
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The callcontrol application runs on the same machine as &kamailio; and they
- communicate over a filesystem socket, while the rating engine can run on
- a different host and communicates with the callcontrol application using
- a TCP connection.
- </para>
- <para>
- Callcontrol is invoked by calling the call_control() function for the
- initial INVITE of every call we want to apply a limit to. This will end
- up as a request to the callcontrol application, which will interogate
- the rating engine for a time limit for the given caller and destination.
- The rating engine will determine if the destination has any associated
- cost and if the caller has any credit limit and if so will return the
- amount of time he is allowed to call that destination. Otherwise it will
- indicate that there is no limit associated with the call. If there is a
- limit, the callcontrol application will retain the session and attach
- a timer to it that will expire after the given time causing it to call
- back to &kamailio; with a request to end the dialog. If the rating engine
- returns that there is no limit for the call, the session is discarded
- by the callcontrol application and it will allow it to go proceed any
- limit. An appropriate response is returned to the call_control module
- that is then returned by the call_control() function call and allows
- the script to make a decision based on the answer.
- </para>
- </section>
- <section>
- <title>Features</title>
- <para>
- <itemizedlist>
- <listitem>
- <para>
- Very simple API consisting of a single function that needs to be
- called once for the first INVITE of every call. The rest is done
- automatically in the background using dialog callbacks.
- </para>
- </listitem>
- <listitem>
- <para>
- Gracefully end dialogs when they exceed their time by triggering
- a dlg_end_dlg request into the dialog module, that will generate
- two BYE messages towards each endpoint, ending the call cleanly.
- </para>
- </listitem>
- <listitem>
- <para>
- Allow parallel sessions using one balance per subscriber
- </para>
- </listitem>
- <listitem>
- <para>
- Integrates with mediaproxy's ability to detect when a call does
- timeout sending media and is closed. In this case the dlg_end_dlg
- that is triggered by mediaproxy will end the callcontrol session
- before it reaches the limit and consumes all the credit for a call
- that died and didn't actually take place. For this mediaproxy has
- to be used and it has to be started by engage_media_proxy() to be
- able to keep track of the call's dialog and end it on timeout.
- </para>
- <para>
- Even when mediaproxy is unable to end the dialog because it was
- not started with engage_media_proxy(), the callcantrol application
- is still able to detect calls that did timeout sending media, by
- looking in the radius accounting records for entries recorded by
- mediaproxy for calls that did timeout. These calls will also be
- ended gracefully by the callcontrol application itself.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- <section>
- <title>Dependencies</title>
- <section>
- <title>&kamailio; Modules</title>
- <para>
- The following modules must be loaded before this module:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>dialog</emphasis> module
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- <section>
- <title>External Libraries or Applications</title>
- <para>
- The following libraries or applications must be installed before
- running &kamailio; with this module loaded:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>None</emphasis>.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- </section>
-
- <section>
- <title>Exported parameters</title>
- <section id="call_control.p.disable">
- <title><varname>disable</varname> (int)</title>
- <para>
- Boolean flag that specifies if callcontrol should be disabled. This
- is useful when you want to use the same &kamailio; configuration in
- two different contexts, one using callcontrol, the other not. In the
- case callcontrol is disabled, calls to the call_control() function
- will return a code indicating that there is no limit associated with
- the call, allowing the use of the same configuration without changes.
- </para>
- <para>
- <emphasis>
- Default value is <quote>0</quote>.
- </emphasis>
- </para>
- <example>
- <title>Setting the <varname>disable</varname> parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("call_control", "disable", 1)
- ...
- </programlisting>
- </example>
- </section>
- <section id="call_control.p.socket_name">
- <title><varname>socket_name</varname> (string)</title>
- <para>
- The path to the filesystem socket where the callcontrol
- application listens for commands from the module.
- </para>
- <para>
- <emphasis>
- Default value is
- <quote>/var/run/callcontrol/socket</quote>.
- </emphasis>
- </para>
- <example>
- <title>Setting the <varname>socket_name</varname> parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("call_control", "socket_name", "/var/run/callcontrol/socket")
- ...
- </programlisting>
- </example>
- </section>
- <section id="call_control.p.socket_time">
- <title><varname>socket_timeout</varname> (int)</title>
- <para>
- How long time (in milliseconds) to wait for an answer from the
- callcontrol application.
- </para>
- <para>
- <emphasis>
- Default value is <quote>500</quote> ms.
- </emphasis>
- </para>
- <example>
- <title>Setting the <varname>socket_timeout</varname> parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("call_control", "socket_timeout", 500)
- ...
- </programlisting>
- </example>
- </section>
- <section id="call_control.p.signaling_ip_avp">
- <title><varname>signaling_ip_avp</varname> (string)</title>
- <para>
- Specification of the AVP which holds the IP address from where
- the SIP signaling originated. If this AVP is set it will be used
- to get the signaling IP address, else the source IP address
- from where the SIP message was received will be used.
- This AVP is meant to be used in cases where there are more than
- one proxy in the call setup path and the proxy that actually
- starts callcontrol doesn't receive the SIP messages directly
- from the UA and it cannot determine the NAT IP address from
- where the signaling originated. In such a case attaching a
- SIP header at the first proxy and then copying that header's
- value into the signaling_ip_avp on the proxy that starts
- callcontrol will allow it to get the correct NAT IP address
- from where the SIP signaling originated.
- </para>
-
- <para>
- This is used by the rating engine which finds the rates to apply to a
- call based on caller's SIP URI, caller's SIP domain or caller's IP
- address (whichever yields a rate forst, in this order).
- </para>
- <para>
- <emphasis>
- Default value is <quote>$avp(s:signaling_ip)</quote>.
- </emphasis>
- </para>
- <example>
- <title>Setting the <varname>signaling_ip_avp</varname> parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("call_control", "signaling_ip_avp", "$avp(s:signaling_ip)")
- ...
- </programlisting>
- </example>
- </section>
- <section id="call_control.p.canonical_uri_avp">
- <title><varname>canonical_uri_avp</varname> (string)</title>
- <para>
- Specification of the AVP which holds an optional application defined
- canonical request URI. When this is set, it will be used as the
- destination when computing the call price, otherwise the request URI
- will be used. This is useful when the username of the ruri needs to
- have a different, canonical form in the rating engine computation
- than it has in the ruri.
- </para>
- <para>
- <emphasis>
- Default value is <quote>$avp(s:can_uri)</quote>.
- </emphasis>
- </para>
- <example>
- <title>Setting the <varname>canonical_uri_avp</varname> parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("call_control", "canonical_uri_avp", "$avp(s:can_uri)")
- ...
- </programlisting>
- </example>
- </section>
- <section id="call_control.p.diverter_avp_id">
- <title><varname>diverter_avp_id</varname> (string)</title>
- <para>
- Specification of the id of an integer AVP which holds an optional
- application defined diverter SIP URI. When this is set, it will be
- used by the rating engine as the billing party when finding the rates
- to apply to a given call, otherwise, the caller's URI taken from the
- From field will be used. When set, this AVP should contain a value in
- the form <quote>user@domain</quote> (no sip: prefix should be used).
- </para>
- <para>
- This is useful when a destination diverts a call, thus becoming the
- new caller. In this case the billing party is the diverter and this
- AVP should be set to it, to allow the rating engine to pick the right
- rates for the call. For example, if A calls B and B diverts all its
- calls unconditionally to C, then the diverter AVP should the set to
- B's URI, because B is the billing party in the call not A after the
- call was diverted.
- </para>
- <para>
- <emphasis>
- Default value is <quote>805</quote>.
- </emphasis>
- </para>
- <example>
- <title>Setting the <varname>diverter_avp_id</varname> parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("call_control", "diverter_avp_id", 805)
- route {
- ...
- # [email protected] is paying for this call
- $avp(i:805) = "sip:[email protected]";
- ...
- }
- ...
- </programlisting>
- </example>
- </section>
- </section>
- <section>
- <title>Functions</title>
- <section id="call_control.f.call_control">
- <title><function moreinfo="none">call_control()</function></title>
- <para>
- Trigger the use of callcontrol for the dialog started by the INVITE
- for which this function is called (the function should only be called
- for the first INVITE of a call). Further in-dialog requests will be
- processed automatically using internal bindings into the dialog state
- machine, allowing callcontrol to update its internal state as the
- dialog progresses, without any other intervention from the script.
- </para>
- <para>
- This function should be called right before the message is sent out
- using t_relay(), when all the request uri modifications are over and
- a final destination has been determined.
- </para>
- <para>This function has the following return codes:</para>
- <para>
- <itemizedlist>
- <listitem><para>
- +2 - call has no limit
- </para></listitem>
- <listitem><para>
- +1 - call has limit and is traced by callcontrol
- </para></listitem>
- <listitem><para>
- -1 - not enough credit to make the call
- </para></listitem>
- <listitem><para>
- -2 - call is locked by another call in progress
- </para></listitem>
- <listitem><para>
- -5 - internal error (message parsing, communication, ...)
- </para></listitem>
- </itemizedlist>
- </para>
- <para>
- This function can be used from REQUEST_ROUTE.
- </para>
- <example>
- <title>Using the <function>call_control</function> function</title>
- <programlisting format="linespecific">
- ...
- if (is_avp_set("$avp(i:805)")) {
- # the diverter AVP is set, use it as billing party
- $avp(s:billing_party_domain) = $(avp(i:805){uri.domain});
- } else {
- $avp(s:billing_party_domain) = $fd;
- }
- if (method==INVITE && !has_totag() &&
- is_domain_local("$avp(s:billing_party_domain)")) {
- call_control();
- switch ($retcode) {
- case 2:
- # Call with no limit
- case 1:
- # Call has limit and is under callcontrol management
- break;
- case -1:
- # Not enough credit (prepaid call)
- sl_send_reply("402", "Not enough credit");
- exit;
- break;
- case -2:
- # Locked by another call in progress (prepaid call)
- sl_send_reply("403", "Call locked by another call in progress");
- exit;
- break;
- default:
- # Internal error (message parsing, communication, ...)
- if (PREPAID_ACCOUNT) {
- xlog("Call control: internal server error\n");
- sl_send_reply("500", "Internal server error");
- exit;
- } else {
- xlog("L_WARN", "Cannot set time limit for postpaid call\n");
- }
- }
- }
- t_relay();
- ...
- </programlisting>
- </example>
- </section>
- </section>
- </chapter>
|