📄 apps.sgml
字号:
pswhichversionuptimeprint </programlisting> </example> The request which the <application moreinfo="none">serctl</application> command-line tool sent to FIFO server looked like this: <example> <title><command moreinfo="none">uptime</command> FIFO Request</title> <programlisting format="linespecific">: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 format="linespecific">[jiri@cat sip_router]$ serctl fifo foobar500 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 moreinfo="none">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 moreinfo="none">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 format="linespecific">#!/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 bodycat > /tmp/ser_fifo <<EOF:t_uac_dlg:hhNOTIFYsip:receiver@127.0.0.1.From: sip:originator@foo.barTo: sip:receiver@127.0.0.1foo: bar_special_headerx: yp_header: p_valueContact: <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 moreinfo="none">ser</application>. This is what the <command moreinfo="none">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 moreinfo="none">serweb</application>, <application moreinfo="none">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 format="linespecific"><![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 moreinfo="none">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 moreinfo="none"> 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 format="linespecific"> 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 initiatedINVITE callerFrom: controllerTo: callerSDP: on hold#2 calling user answes200 OKFrom: controllerTo: caller#3 CTD acknowledgesACK callerFrom controllerTo: caller#4 CTD initiates a transferREFER callerFrom: controllerTo: callerRefer-To: calleeRefered-By: controller#5 caller confirms delivery of REFER202 AcceptedFrom: controllerTo: caller#6 CTD terminates the wrapper call -- it is no longer neededBYE callerFrom: controllerTo: caller#7 BYE is confirmed200 OkFrom: controllerTo: caller#8 caller initates transaction solicited through REFERINVITE calleeFrom: callerTo: calleeReferred-By: controller#9 that's it -- it is now up to callee to answer the INVITE180 ringingFrom: callerTo: 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 moreinfo="none">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 format="linespecific">[jiri@cat examples]$ ./ctd.sh destination unspecified -- taking default value sip:23@192.168.2.16caller unspecified -- taking default value sip:113311@192.168.2.16invitation succeededrefer succeededbye 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 format="linespecific"> <textobject> <textdata fileref="../../examples/web_im/send_im.php" format="linespecific"> </textobject> </programlisting> </example>--> </section> <!-- FIFO server --> </chapter>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -