4.2. Application FIFO Server 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, ser's complementary web-interface, serweb, 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 SIP stack. Another application relying on the FIFO interface is serctl, ser management utility. The command-line utility can browse server's in-memory user-location database, display running processes and operational statistics. The way the FIFO server works is similar to how /proc filesystem works on some operating systems. It provides a human-readable way to access ser's internals. Applications dump their requests into the FIFO server and receive a status report when request processing completes. ser exports a lot of its functionality located in both the core and external modules through the FIFO server. FIFO requests are formed easily. They begin with a command enclosed in colons and followed by name of file or pipe (relative to /tmp/ 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 t_uac_dlg 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 ser listens (filename configured by the fifo config file option). An easy way to use the FIFO interface is via the serctl 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 uptime and which commands. uptime returns server's running time, which 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 4-6. Use of serctl to Access FIFO Server [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 The request which the serctl command-line tool sent to FIFO server looked like this: Example 4-7. uptime FIFO Request :uptime:ser_receiver_1114 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 SIP 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 4-8. FIFO Errors [jiri@cat sip_router]$ serctl fifo foobar 500 command 'foobar' not available Example 4-9. Showing User Contacts Using serctl 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 ul_show_contact to retrieve current whereabouts of user "jiri". [jiri@fox ser]$ serctl fifo ul_show_contact location jiri ;q=0.00;expires=1012 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 examples/web_im/send_im.php for how to initiate a SIP transaction (instant message) from a PHP script via the FIFO server. This example uses FIFO command t_uac_dlg. 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 4-10. Sending IM From Shell Script #!/bin/sh # # call this script to send an instant message; script parameters # will be displayed in message body # # paremeters 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 < Content-Type: text/plain; charset=UTF-8 .. Hello world!!!! $@ .. EOF Example 4-11. Manipulation of User Contacts 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 ser. This is what the ul_add FIFO command is good for. Paremeterized 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. The example is borrowed from serweb, ser'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. /* construct and send a FIFO command; the command parameters $sip_addre ss, $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". //conta ct $expires."\n". //expir es $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; }