mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
809 lines
28 KiB
809 lines
28 KiB
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
|
|
|
<section id="application_writing" xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
<sectioninfo>
|
|
<revhistory>
|
|
<revision>
|
|
<revnumber>$Revision$</revnumber>
|
|
<date>$Date$</date>
|
|
</revision>
|
|
</revhistory>
|
|
</sectioninfo>
|
|
|
|
<title>Application Writing</title>
|
|
<para>
|
|
<application>ser</application> offers several
|
|
ways to couple its functionality with applications. The coupling
|
|
is bidirectional: <application>ser</application>
|
|
can utilize external applications and external applications can
|
|
utilize <application>ser</application>.
|
|
An example of the former direction would be an external program
|
|
determining a least-cost route for a called destination using
|
|
a pricing table. An example of the latter case
|
|
is a web application for server provisioning.
|
|
Such an application may want to send instant
|
|
messages, query all current user's locations and monitor server
|
|
health. An existing web interface to <application>ser</application>,
|
|
<application>serweb</application>, actually
|
|
does all of it.
|
|
</para>
|
|
<para>
|
|
The easiest, language-independent way of using external logic
|
|
from <application>ser</application> is provided
|
|
by exec module. exec module allows <application>ser</application>
|
|
to start external programs on receipt of a request. The
|
|
programs can execute arbitrary logic and/or affect routing of SIP
|
|
requests. A great benefit of this programming method is it
|
|
is language-independent. Programmers may use programming languages
|
|
that are effective or with which they are best familiar.
|
|
<xref linkend="usingexec"/> gives additional examples illustrating
|
|
use of the exec module.
|
|
</para>
|
|
<para>
|
|
Another method for extending <application>ser</application>
|
|
capabilities is to write new modules in C. This method takes
|
|
deeper understanding of <application>ser</application>
|
|
internals but gains the highest flexibility. Modules can implement
|
|
arbitrary brand-new commands upon which <application>ser</application>
|
|
scripts can rely on. Guidelines on module programming can be
|
|
found in <application>ser</application>
|
|
programmer's handbook available from iptel.org website.
|
|
</para>
|
|
<para>
|
|
To address needs of applications wishing to leverage
|
|
<application>ser</application>,
|
|
<application>ser</application> exports
|
|
parts of its functionality via its built-in
|
|
"Application FIFO server". This is a simple textual
|
|
interface that allows any external applications
|
|
to communicate with the server. It can be used to
|
|
send instant messages, manipulate user contacts,
|
|
watch server health, etc. Programs written in any
|
|
language (PHP, shell scripts, Perl, C, etc.) can
|
|
utilize this feature. How to use it is shown in
|
|
<xref linkend="fifoserver"/>.
|
|
</para>
|
|
|
|
<section id="usingexec">
|
|
<title>Using exec Module</title>
|
|
<para>
|
|
|
|
The easiest way is to couple <application>ser</application>
|
|
with external applications via the <emphasis>exec</emphasis>
|
|
module. This module allows execution of logic and URI manipulation
|
|
by external applications on request receipt. While very
|
|
simple, many useful services can be
|
|
implemented this way. External applications can be written in
|
|
any programming language and do not be aware of SIP at all.
|
|
<application>ser</application> interacts with
|
|
the application via standard input/output and environment
|
|
variables.
|
|
</para>
|
|
<para>
|
|
For example, an external shell script
|
|
may send an email whenever a request for a user arrives.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Using exec: Step 1</title>
|
|
<programlisting>
|
|
# send email if a request for user "jiri" arrives
|
|
if (uri=~"^sip:jiri@") {
|
|
exec_msg("echo 'body: call arrived'|mail -s 'call for you' jiri");
|
|
}
|
|
</programlisting>
|
|
</example> <!-- step 1 -->
|
|
<para>
|
|
In this example, the <command>exec_msg</command>
|
|
action starts an external shell. It passes a received SIP request
|
|
to shell's input. In the shell, <command>mail</command> command
|
|
is called to send a notification by e-mail.
|
|
The script however features several simplifications:
|
|
<orderedlist inheritnum="ignore" continuation="restarts">
|
|
<listitem>
|
|
<para>
|
|
The email notification does not tell who was calling.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The logic is not general: it only supports one well-known user (jiri).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The logic is stateless. It will be executed on
|
|
every retransmission.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
It is a script fragment not explaining the
|
|
context. This particular example may be for
|
|
example used to report on missed calls.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
All of these simplifications are addressed step-by-step
|
|
in the following examples.
|
|
</para>
|
|
<example> <!-- step 2: who called me -->
|
|
<title>Using exec: Step 2, Who Called Me</title>
|
|
<para>
|
|
This example shows how to display caller's address
|
|
in email notification. The trick is easy: process
|
|
request received on shell program's input
|
|
and grep From header field.
|
|
</para>
|
|
<programlisting>
|
|
<xi:include href="../../examples/exec_s2.cfg" parse="text"/>
|
|
</programlisting>
|
|
<para>
|
|
The following two figures show an example SIP request and
|
|
email notification generated on its receipt.
|
|
<screen>
|
|
|
|
<![CDATA[
|
|
INVITE sip:jiri@iptel.org SIP/2.0
|
|
Via: SIP/2.0/UDP 195.37.77.100:5040
|
|
Max-Forwards: 10
|
|
From: "alice" <sip:alice@iptel.org>;tag=76ff7a07-c091-4192-84a0-d56e91fe104f
|
|
To: <sip:jiri@iptel.org>
|
|
Call-ID: d10815e0-bf17-4afa-8412-d9130a793d96@213.20.128.35
|
|
CSeq: 2 INVITE
|
|
Contact: <sip:123.20.128.35:9315>
|
|
Content-Type: application/sdp
|
|
Content-Length: 451
|
|
|
|
--- SDP payload snipped ---
|
|
]]>
|
|
</screen>
|
|
|
|
email received:
|
|
|
|
<screen>
|
|
<![CDATA[
|
|
Date: Thu, 12 Dec 2002 14:25:02 +0100
|
|
From: root <root@cat.iptel.org>
|
|
To: jiri@cat.iptel.org
|
|
Subject: request for you
|
|
|
|
From: "alice" <sip:alice@iptel.org>;tag=76ff7a07-c091-4192-84a0-d56e91fe104f
|
|
request received
|
|
]]>
|
|
</screen>
|
|
</para>
|
|
<para>
|
|
There is another way to learn values of request
|
|
header fields, simpler than use of <command>grep</command>.
|
|
<application>ser</application>
|
|
parses header fields and passes their values in
|
|
environment variables. Their names correspond
|
|
to header field names prefixed with "SIP_HF_".
|
|
<programlisting>
|
|
# send email if a request for "jiri" arrives
|
|
if (uri=~"^sip:jiri@") {
|
|
exec_msg("echo request received from $SIP_HF_FROM | mail -s 'request for you' jiri");
|
|
};
|
|
</programlisting>
|
|
Moreover, several other values are passed in environment
|
|
variables. <varname>SIP_TID</varname> is a token uniquely identifying
|
|
transaction, to which the request belongs. <varname>SIP_DID</varname>
|
|
includes to-tag, and is empty in requests creating a dialog.
|
|
<varname>SIP_SRCIP</varname> includes IP address, from which the
|
|
request was sent. <varname>SIP_RURI</varname> and <varname>SIP_ORURI</varname>
|
|
include current request-uri and original request-uri respectively,
|
|
<varname>SIP_USER</varname> and <varname>SIP_OUSER</varname> username
|
|
parts of these. The following listing shows environment variables
|
|
passed to a shell script on receipt of the previous message:
|
|
<programlisting>
|
|
<![CDATA[
|
|
SIP_HF_MAX_FORWARDS=10
|
|
SIP_HF_VIA=SIP/2.0/UDP 195.37.77.100:5040
|
|
SIP_HF_CSEQ=2 INVITE
|
|
SIP_HF_FROM="alice" <sip:alice@iptel.org>;tag=76ff7a07-c091-4192-84a0-d56e91fe104f
|
|
SIP_ORUI=sip:jiri@iptel.org
|
|
SIP_HF_CONTENT_LENGTH=451
|
|
SIP_TID=3b6b8295db0835815847b1f35f3b29b8
|
|
SIP_DID=
|
|
SIP_RURI=iptel.org
|
|
SIP_HF_TO=<sip:jiri@iptel.org>
|
|
SIP_OUSER=jiri
|
|
SIP_HF_CALLID=d10815e0-bf17-4afa-8412-d9130a793d96@213.20.128.35
|
|
SIP_SRCIP=195.37.77.100
|
|
SIP_HF_CONTENT_TYPE=application/sdp
|
|
SIP_HF_CONTACT=<sip:123.20.128.35:9315>
|
|
]]>
|
|
</programlisting>
|
|
|
|
</para>
|
|
</example> <!-- step 2, who called me -->
|
|
|
|
|
|
<example> <!-- step 3, make the script work for anyone -->
|
|
<title>Using exec: step 3, Make The Script Work For Anyone</title>
|
|
<para>
|
|
A drawback of the previous example is it works only
|
|
for one well-known user: request URI is matched against
|
|
his SIP address and notification is sent to his hard-wired email
|
|
address. In real scenarios, one would like
|
|
to enable such a service for all users without enumerating
|
|
their addresses in the script. The missing piece
|
|
is translation of user's SIP name to his email address.
|
|
This information is maintained in subscriber profiles,
|
|
stored in MySQL by <application>ser</application>.
|
|
To translate the username to email address, the executed script
|
|
needs to query the MySQL database. That is what this example
|
|
shows. First, an SQL query is constructed which looks up
|
|
email address of user, for whom a request arrived. If the
|
|
query does not return a valid email address, the script
|
|
returns with an error status and <application>ser</application>
|
|
script replies with "user does not exist". Otherwise
|
|
an email notification is sent.
|
|
|
|
<programlisting>
|
|
<xi:include href="../../examples/exec_s3.cfg" parse="text"/>
|
|
</programlisting>
|
|
</para>
|
|
</example> <!-- step 3 make the script work for anyone -->
|
|
<example> <!-- step 4, stateful processing -->
|
|
<title>Adding Stateful Processing</title>
|
|
<para>
|
|
The previously improved example still features a shortcoming.
|
|
When a message retransmission arrives due to a network
|
|
mistake such as lost reply, the email notification is
|
|
executed again and again. That happens because the script
|
|
is stateless, i.e., no track of current transactions is
|
|
kept. The script does not know whether a request is
|
|
a new or a retransmitted one. Transaction management may
|
|
be introduced by use of tm module as described in
|
|
<xref linkend="statefulua"/>. In the script,
|
|
<command>t_newtran</command> is first
|
|
called to absorb requests retransmission -- if they
|
|
occur, script does not continue. Then, as in the previous
|
|
example, an exec module action is called. Eventually,
|
|
a reply is sent statefully.
|
|
<note>
|
|
<para>
|
|
Note carefully: it is important that the stateful
|
|
reply processing (<command>t_reply</command>)
|
|
is used as opposed to using stateless replies
|
|
(<command>sl_send_reply</command>).
|
|
Otherwise, the outgoing reply would not affect
|
|
transactional context and would not be resent on
|
|
receipt of a request retransmission.
|
|
</para>
|
|
</note>
|
|
<programlisting>
|
|
<xi:include href="../../examples/exec_s4.cfg" parse="text"/>
|
|
</programlisting>
|
|
|
|
</para>
|
|
</example> <!-- step 4, stateful processing -->
|
|
<example> <!-- step 5, full exec use -->
|
|
<title>Full Example of exec Use</title>
|
|
<para>
|
|
The last example iteration shows how to integrate the
|
|
email notification on missed calls with the default
|
|
<application>ser</application> script
|
|
(see <xref linkend="defaultscript"/>). It generates an
|
|
email for every call invitation to an off-line user.
|
|
<programlisting>
|
|
<xi:include href="../../examples/exec_s5.cfg" parse="text"/>
|
|
</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Production "missed calls" services may want to
|
|
report on calls missed for other reasons than
|
|
being off-line too. Particularly, users may wish to be
|
|
reported calls missed due to call cancellation,
|
|
busy status or a downstream failure. Such missed
|
|
calls can be easily reported to syslog or mysql
|
|
using the acc module (see <xref linkend="missedcalls"/>).
|
|
The other, more general way, is to return to request
|
|
processing on receipt of a negative reply.
|
|
(see <xref linkend="replyprocessingsection"/>). Before
|
|
a request is forwarded, it is labeled to be
|
|
re-processed in a <command>failure_route</command>
|
|
on receipt of a negative reply -- this is what
|
|
<command>t_on_failure</command> action
|
|
is used for. It does not matter what caused the transaction
|
|
to fail -- it may be unresponsive downstream server,
|
|
server responding with 6xx, or server sending a 487
|
|
reply, because an INVITE was canceled. When any such
|
|
circumstances occur (i.e., transaction does not complete
|
|
with a 2xx status code), <command>failure_route</command>
|
|
is entered.
|
|
</para>
|
|
<para>
|
|
The following <application>ser</application>
|
|
script reports missed calls in all possible cases.
|
|
It reports them when a user is off-line as well as when
|
|
a user is on-line, but INVITE transaction does not complete
|
|
successfully.
|
|
<programlisting>
|
|
<xi:include href="../../examples/exec_s5b.cfg" parse="text"/>
|
|
</programlisting>
|
|
</para>
|
|
|
|
</example> <!-- step 5, full exec use -->
|
|
|
|
</section> <!-- using exec -->
|
|
|
|
<section id="fifoserver">
|
|
<title>Application FIFO Server</title>
|
|
|
|
<para>
|
|
Application FIFO server is a very powerful method to program
|
|
SIP services. The most valuable benefit
|
|
is it works with SIP-unaware applications
|
|
written in any programming language. Textual nature of the
|
|
FIFO interface allows for easy integration with a lot of
|
|
existing programs. Today, <application>ser</application>'s
|
|
complementary web-interface, <application>serweb</application>,
|
|
written in PHP, leverages the FIFO interface when displaying
|
|
and changing user location records stored in server's memory.
|
|
It uses this interface to send instant messages too, without
|
|
any knowledge of underlying <acronym>SIP</acronym> stack.
|
|
Another application relying on the FIFO interface is
|
|
<application>serctl</application>, <application>ser</application>
|
|
management utility. The command-line utility can browse
|
|
server's in-memory user-location database, display
|
|
running processes and operational statistics.
|
|
</para>
|
|
<para>
|
|
The way the FIFO server works is similar to how
|
|
<filename>/proc</filename> filesystem works
|
|
on some operating systems. It provides a human-readable way
|
|
to access <application>ser</application>'s
|
|
internals. Applications dump their requests into the FIFO
|
|
server and receive a status report when request processing
|
|
completes. <application>ser</application>
|
|
exports a lot of its functionality located in both the
|
|
core and external modules through the FIFO server.
|
|
</para>
|
|
<para>
|
|
FIFO requests are formed easily. They begin with a command
|
|
enclosed in colons and followed by name of file or pipe (relative
|
|
to <filename>/tmp/</filename> path), to which
|
|
a reply should be printed. The first request line may be
|
|
followed by additional lines with command-specific
|
|
parameters. For example, the <command>t_uac_dlg</command>
|
|
FIFO command for initiating a transaction allows
|
|
to pass additional header fields and message body to
|
|
a newly created transaction. Each request is terminated by
|
|
an empty line. Whole requests must be sent by applications
|
|
atomically in a single batch to avoid mixing with
|
|
requests from other applications. Requests are sent to
|
|
pipe at which <application>ser</application>
|
|
listens (filename configured by the <varname>fifo</varname> config
|
|
file option).
|
|
</para>
|
|
<para>
|
|
An easy way to use the FIFO interface is via the
|
|
<application>serctl</application>
|
|
command-line tool. When called along with "fifo",
|
|
FIFO command name, and optional parameters, the tool
|
|
generates a FIFO request and prints request result.
|
|
The following example shows use of this tool with
|
|
the <command>uptime</command> and
|
|
<command>which</command> commands.
|
|
<command>uptime</command> returns
|
|
server's running time, <command>which</command>
|
|
returns list of available FIFO commands. Note that only
|
|
the built-in FIFO command set is displayed as no modules
|
|
were loaded in this example.
|
|
<example>
|
|
<title>Use of <application>serctl</application>
|
|
to Access FIFO Server</title>
|
|
<programlisting>
|
|
[jiri@cat test]$ serctl fifo uptime
|
|
Now: Fri Dec 6 17:56:10 2002
|
|
Up Since: Fri Dec 6 17:56:07 2002
|
|
Up time: 3 [sec]
|
|
|
|
[jiri@cat test]$ serctl fifo which
|
|
ps
|
|
which
|
|
version
|
|
uptime
|
|
print
|
|
</programlisting>
|
|
</example>
|
|
The request which the <application>serctl</application>
|
|
command-line tool sent to FIFO server looked like this:
|
|
<example>
|
|
<title><command>uptime</command> FIFO Request</title>
|
|
<programlisting>
|
|
:uptime:ser_receiver_1114
|
|
</programlisting>
|
|
</example>
|
|
This request contains no parameters and consists only of
|
|
command name enclosed in colons and name of file, to which
|
|
a reply should be printed. FIFO replies consist of a status
|
|
line followed by optional parameters. The status line consists,
|
|
similarly to <acronym>SIP</acronym> reply status, of
|
|
a three-digit status code and a reason phrase. Status codes
|
|
with leading digit 2 (200..299) are considered positive,
|
|
any other values indicate an error. For example, FIFO server
|
|
returns "500" if execution of a non-existing FIFO command is
|
|
requested.
|
|
<example>
|
|
<title>FIFO Errors</title>
|
|
<programlisting>
|
|
[jiri@cat sip_router]$ serctl fifo foobar
|
|
500 command 'foobar' not available
|
|
</programlisting>
|
|
</example>
|
|
|
|
<example>
|
|
<title>Showing User Contacts Using serctl</title>
|
|
<para>
|
|
Another example of use of FIFO is accessing server's
|
|
in-memory user location database. That's a very powerful
|
|
feature: web applications and other tools can use it
|
|
to gain users access to the database. They can add new
|
|
contacts (like permanent gateway destinations), remove
|
|
and review users' whereabouts. The example here utilizes
|
|
FIFO command <command>ul_show_contact</command> to
|
|
retrieve current whereabouts of user "jiri".
|
|
<programlisting>
|
|
<![CDATA[
|
|
[jiri@fox ser]$ serctl fifo ul_show_contact location jiri
|
|
<sip:195.37.78.160:14519>;q=0.00;expires=1012
|
|
]]>
|
|
</programlisting>
|
|
</para>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The user location example demonstrates an essential feature
|
|
of the FIFO server: extensibility. It is able to export new
|
|
commands implemented in new modules.
|
|
Currently, usrloc module exports FIFO
|
|
commands for maintaining in-memory user location
|
|
database and tm module exports FIFO commands for
|
|
management of SIP transactions. See the
|
|
example in
|
|
<filename>examples/web_im/send_im.php</filename>
|
|
for how to initiate a SIP transaction
|
|
(instant message)
|
|
from a PHP script via the FIFO server. This example
|
|
uses FIFO command
|
|
<command>t_uac_dlg</command>. The command
|
|
is followed by parameters: header fields and
|
|
message body. The same FIFO command can be used from
|
|
other environments to send instant messages too. The
|
|
following example shows how to send instant messages
|
|
from a shell script.
|
|
<example>
|
|
<title>Sending IM From Shell Script</title>
|
|
<programlisting>
|
|
#!/bin/sh
|
|
#
|
|
# call this script to send an instant message; script parameters
|
|
# will be displayed in message body
|
|
#
|
|
# parameters mean: message type, request-URI, outbound server is
|
|
# left blank ("."), required header fields From and To follow,
|
|
# then optional header fields terminated by dot and optional
|
|
# dot-terminated body
|
|
|
|
cat > /tmp/ser_fifo <<EOF
|
|
:t_uac_dlg:hh
|
|
NOTIFY
|
|
sip:receiver@127.0.0.1
|
|
.
|
|
From: sip:originator@foo.bar
|
|
To: sip:receiver@127.0.0.1
|
|
foo: bar_special_header
|
|
x: y
|
|
p_header: p_value
|
|
Contact: <sip:devnull@192.168.0.100:9>
|
|
Content-Type: text/plain; charset=UTF-8
|
|
.
|
|
Hello world!!!! $@
|
|
.
|
|
EOF
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<example>
|
|
<title>Manipulation of User Contacts</title>
|
|
<para>
|
|
The following example shows use of FIFO server to change
|
|
user's contacts. This may be very practical, if for example
|
|
a user wishes to set up his cell phone number as his temporary
|
|
contact. The cell phone, which is behind a PSTN gateway, cannot
|
|
register automatically using SIP. The user needs to set
|
|
forwarding manually through some convenient web interface.
|
|
The web interface needs to have the ability to upload new user's
|
|
contacts to <application>ser</application>.
|
|
This is what the <command>ul_add</command> FIFO
|
|
command is good for. Parameterized by user's name, table name,
|
|
expiration time and weight, it allows external applications to
|
|
introduce new contacts to server's in-memory user location table.
|
|
</para>
|
|
<para>
|
|
The example is borrowed from <application>serweb</application>,
|
|
<application>ser</application>'s web
|
|
PHP-written interface.
|
|
It consists of a short "stub" function which carries out
|
|
all mechanics of FIFO communication and of forming the FIFO
|
|
request.
|
|
</para>
|
|
<programlisting>
|
|
<![CDATA[
|
|
|
|
/* construct and send a FIFO command; the command parameters $sip_address,
|
|
$expires are PHP variables originating from an HTML form
|
|
*/
|
|
$fifo_cmd=":ul_add:".$config->reply_fifo_filename."\n".
|
|
$config->ul_table."\n". //table
|
|
$user_id."\n". //username
|
|
$sip_address."\n". //contact
|
|
$expires."\n". //expires
|
|
$config->ul_priority."\n\n"; //priority
|
|
$message=write2fifo($fifo_cmd, $errors, $status);
|
|
|
|
/* .......... snip .................. */
|
|
|
|
/* this is the stub function for communicating with FIFO server.
|
|
it dumps a request to FIFO server, opens a reply FIFO and
|
|
reads server's reply from it
|
|
*/
|
|
function write2fifo($fifo_cmd, &$errors, &$status){
|
|
global $config;
|
|
|
|
/* open fifo now */
|
|
$fifo_handle=fopen( $config->fifo_server, "w" );
|
|
if (!$fifo_handle) {
|
|
$errors[]="sorry -- cannot open fifo"; return;
|
|
}
|
|
|
|
/* create fifo for replies */
|
|
@system("mkfifo -m 666 ".$config->reply_fifo_path );
|
|
|
|
/* add command separator */
|
|
$fifo_cmd=$fifo_cmd."\n";
|
|
|
|
/* write fifo command */
|
|
if (fwrite( $fifo_handle, $fifo_cmd)==-1) {
|
|
@unlink($config->reply_fifo_path);
|
|
@fclose($fifo_handle);
|
|
$errors[]="sorry -- fifo writing error"; return;
|
|
}
|
|
@fclose($fifo_handle);
|
|
|
|
/* read output now */
|
|
@$fp = fopen( $config->reply_fifo_path, "r");
|
|
if (!$fp) {
|
|
@unlink($config->reply_fifo_path);
|
|
$errors[]="sorry -- fifo reading error"; return;
|
|
}
|
|
|
|
$status=fgetS($fp,256);
|
|
if (!$status) {
|
|
@unlink($config->reply_fifo_path);
|
|
$errors[]="sorry -- fifo reading error"; return;
|
|
}
|
|
|
|
$rd=fread($fp,8192);
|
|
@unlink($config->reply_fifo_path);
|
|
|
|
return $rd;
|
|
}
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
See
|
|
<xref linkend="fiforeference"/> for a complete listing
|
|
of FIFO commands available with current
|
|
<application>ser</application>
|
|
distribution.
|
|
</para>
|
|
<section>
|
|
<title>Advanced Example: Click-To-Dial</title>
|
|
<para>
|
|
A very useful SIP application is phonebook with
|
|
"click-to-dial" feature. It allows users to keep their
|
|
phonebooks on the web and dial by clicking on an entry.
|
|
The great advantage is that you can use the phonebook
|
|
alone with any phone you have. If you temporarily use
|
|
another phone, upgrade it permanently with another make,
|
|
or use multiple phones in parallel, your phonebook will
|
|
stay with you on the web. You just need to click an entry
|
|
to initiate a call. Other scenario using "click-to-dial"
|
|
feature includes "click to be connected with our
|
|
sales representative".
|
|
</para>
|
|
<para>
|
|
There are basically two ways how to build such a feature:
|
|
distributed and centralized. We prefer the distributed
|
|
approach since it is very robust and light-weighted.
|
|
The "click-to-dial" application just needs to instruct
|
|
the calling user to call a destination and that's it.
|
|
(That's done using "REFER" method.)
|
|
Then, the calling user takes over whereas the initiating
|
|
application disappears from signaling and
|
|
is no longer involved in subsequent communication. Which
|
|
is good because such a simple design scales well.
|
|
</para>
|
|
<para>
|
|
The other design alternative is use of a B2BUA
|
|
<footnote>
|
|
<para>
|
|
See <filename>
|
|
draft-ietf-sipping-3pcc-02.txt
|
|
</filename> for more details.
|
|
</para>
|
|
</footnote>
|
|
which acts as a "middleman" involved in signaling during the
|
|
whole session. It is complex: ringing needs to be achieved
|
|
using a media server, it introduces session state,
|
|
mangling of SIP payloads, complexity when QoS reservation
|
|
is used and possibly other threats which result from
|
|
e2e-unfriendly design. The only benefit
|
|
is it works even for poor phones which do not support
|
|
REFER -- which should not matter because you do not wish
|
|
to buy such.
|
|
</para>
|
|
<para>
|
|
So how does "distributed click-to-dial" application
|
|
work? It is simple. The core piece is sending a REFER
|
|
request to the calling party. REFER method is typically
|
|
used for call transfer and it means "set up a call
|
|
to someone else".
|
|
</para>
|
|
<para>
|
|
There is an issue -- most phones
|
|
don't accept unsolicited REFER. If a malicious
|
|
user made your phone to call thirty destinations without
|
|
your agreement, you would certainly not appreciate it.
|
|
The workaround is that first of all the click-to-dial
|
|
application gives you a "wrapper call". If you accept it,
|
|
the application will send a REFER which will be considered
|
|
by the phone as a part of approved communication and
|
|
granted. Be aware that without cryptography,
|
|
security is still weak. Anyone who saw an INVITE can
|
|
generate an acceptable REFER.
|
|
<note>
|
|
<para>
|
|
The wrapper INVITE may or may not be used
|
|
in future. The Internet draft
|
|
draft-ietf-sipping-service-examples
|
|
mentions the click-to-dial application
|
|
without use of the dummy INVITE. As of
|
|
today, most telephones do need it.
|
|
</para>
|
|
</note>
|
|
<example>
|
|
<title>Call-Flow for Click-To-Dial Using REFER</title>
|
|
|
|
<programlisting>
|
|
|
|
CTD Caller Callee
|
|
#1 INVITE
|
|
----------------->
|
|
...
|
|
caller answers
|
|
#2 200
|
|
<-----------------
|
|
#3 ACK
|
|
----------------->
|
|
#4 REFER
|
|
----------------->
|
|
#5 202
|
|
<-----------------
|
|
#6 BYE
|
|
----------------->
|
|
#7 200
|
|
<-----------------
|
|
#8 INVITE
|
|
------------------>
|
|
#9 180 ringing
|
|
<------------------
|
|
|
|
|
|
#1 click-to-dial (CTD) is started and the "wrapper call" is initiated
|
|
INVITE caller
|
|
From: controller
|
|
To: caller
|
|
SDP: on hold
|
|
|
|
#2 calling user answers
|
|
200 OK
|
|
From: controller
|
|
To: caller
|
|
|
|
#3 CTD acknowledges
|
|
ACK caller
|
|
From controller
|
|
To: caller
|
|
|
|
#4 CTD initiates a transfer
|
|
REFER caller
|
|
From: controller
|
|
To: caller
|
|
Refer-To: callee
|
|
Refered-By: controller
|
|
|
|
#5 caller confirms delivery of REFER
|
|
202 Accepted
|
|
From: controller
|
|
To: caller
|
|
|
|
#6 CTD terminates the wrapper call -- it is no longer needed
|
|
BYE caller
|
|
From: controller
|
|
To: caller
|
|
|
|
#7 BYE is confirmed
|
|
200 Ok
|
|
From: controller
|
|
To: caller
|
|
|
|
#8 caller initates transaction solicited through REFER
|
|
INVITE callee
|
|
From: caller
|
|
To: callee
|
|
Referred-By: controller
|
|
|
|
#9 that's it -- it is now up to callee to answer the INVITE
|
|
180 ringing
|
|
From: caller
|
|
To: callee
|
|
</programlisting>
|
|
|
|
</example>
|
|
</para>
|
|
<para>
|
|
Implementation of this scenario is quite
|
|
straight-forward: you initiate INVITE, BYE and
|
|
REFER transaction.
|
|
|
|
|
|
|
|
Source code of the example written in Bourne shell
|
|
is available in source distrubtion, in
|
|
<filename>examples/ctd.sh</filename>.
|
|
A PHP implementation exists as well as a part of
|
|
<application>serweb</application>.
|
|
</para>
|
|
<example>
|
|
<title>Running the CTD Example</title>
|
|
<programlisting>
|
|
[jiri@cat examples]$ ./ctd.sh
|
|
destination unspecified -- taking default value sip:23@192.168.2.16
|
|
caller unspecified -- taking default value sip:113311@192.168.2.16
|
|
invitation succeeded
|
|
refer succeeded
|
|
bye succeeded
|
|
</programlisting>
|
|
</example>
|
|
</section> <!-- click-to-dial -->
|
|
<!-- for some reason, this does not work :-(
|
|
|
|
<example>
|
|
<title>Initiating a SIP Transaction from PHP via FIFO</title>
|
|
|
|
|
|
<programlisting>
|
|
<textobject>
|
|
<textdata fileref="../../examples/web_im/send_im.php">
|
|
</textobject>
|
|
|
|
</programlisting>
|
|
|
|
|
|
</example>
|
|
-->
|
|
|
|
</section> <!-- FIFO server -->
|
|
</section>
|
|
|