Using the PSTN Gateway Connectivity ser.cfg Example
Before you can use the PSTN enabled ser.cfg you we must take care of a few remaining items. The first thing to
do is copy the following files which the permissions module will look for upon server startup.
The last thing to take care of before you can use the PSTN gateway example, namely add a record to the MySQL
trusted table. To do so you can issue the following SQL command by opening up your MySQL terminal.
[#] mysql u ser p
-- enter your mysql password --
mysql> use ser;
mysql> insert into trusted values (192.0.2.245, any, ^sip:.*$);
NOTE: The above INSERT SQL statement tells SER to allow any protocol (udp or tcp) from IP 192.0.2.245 (the
IP of the PSTN gateway) to send any message to SER without being challenged for credentials.
NOTE: You must restart SER when altering the trusted table because the entries in this table are read only during
server start up. Alternatively, you can use the FIFO command: serctl fifo trusted_reload
Now that your SIP router is PSTN Enabled you can start dialing domestic and international destinations. A word
of caution is that many PSTN gateways perform their own accounting. You must be certain that SER is properly
record-routing all messages to guarantee that BYE messages are sent to the PSTN gateway.
If a BYE message is not delivered to a PSTN gateway then you run the risk of additional toll charges because the
PSTN circuit could be left open.
Chapter 10. Call Forwarding ser.cfg
What this ser.cfg will do:
1. Introduce forwarding concepts known as serial forking and redirection
2. Implement blind call forwarding
3. Implement forward on busy
4. Implement forward on no answer
Call forwarding can be achieved using one of two methods, namely serial forking and redirection. Both methods
have advantages. Serial forking, as the name implies creates a new leg of the call (after the first fails) and sends a
new INVITE message to the forwarded destination. On the other hand, redirection sends a reply message back to
the caller and gives them the forwarded location. The caller then creates a brand new INVITE message with the
forwarded destination in the R-URI and places the call.
Redirection must be used with caution if a PSTN gateway is accessible. The reason is that it is conceivable that
SER could send a redirection response back to a PSTN gateway and the PSTN gateway could then send a new
INVITE message to the forwarded destination and bypass SER, which could be an international call for which
SER is unaware. This would result in toll charges that are not billable. The reason that SER could be unaware of
the new call is that redirection is accomplished by replying with a 302 Temporarily Moved message. In the IP
world, the intention is that the IP phone shall decide what to do, possibly even ask the user should I go ahead and
make the call to the new destination? This way the user will acknowledge potential charges. However, there is no
standard way 302 messages are handling in the interface between PSTN and IP and non-billable calls is a possibility.
Serial forking does not have this possible security exposure because SER will record route all messages, which
means that even if the forwarded destination is a PSTN phone, SER will be able to account for the call and the toll
charges, if any, would be billable to the subscriber.
This section implements three types of call forwarding:
1. Blind Call Forwarding All INVITE messages sent to the phone will be intercepted at the SIP router. The SIP
router will create a new call leg and send the INVITE message to the forwarded destination. This means that
the phone with blind call forwarding set will not even ring. This also means that it doesnt matter if the phone
is registered with SER.
2. Forward On Busy If a phone replies to an INVITE message with a 486 Busy, SER will intercept the 486 response
and create a new call leg, which will send an INVITE message to the forwarded destination.
3. Forward No Answer If a phone replies to an INVITE message with a 408 Request Timeout, SER will intercept
the 408 message and create a new call leg, which will send an INVITE message to the forwarded destination.
Blind call forwarding is handled somewhat differently than forward no answer and forward on busy because blind
call forwarding is altering an INVITE message for which the destination set has yet to be processed. This means
that we can simply change the R-URI and relay the message.
The other two types of call forwarding require much more effort to implement because we must catch the error
replies, alter the R-URI, and then append the forwarded contact location to the destination set and finally relay the
message.
All call forwarding preferences are stored in the MySQL usr_preferences table. We will use the AVPOPS module
to read a subscribers call forwarding settings. AVPOPS will also be used to alter the call sequence and perform
serial forking that we require.
PLEASE NOTE! This configuration cannot recursive forwarding, i.e. forwarding to somebody who has forwarded.
Adding support for this is complex, but is possible and is left as an exercise for the reader ;-)
In addition we have included an appendix describing the Call processing Language that allows more comprehensive
control of a call.
modparam("permissions", "db_mode", 1)
modparam("permissions", "trusted_table", "trusted")
modparam("avpops", "avp_table", "usr_preferences")
route {
# -----------------------------------------------------------------
# Sanity Check Section
# -----------------------------------------------------------------
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483", "Too Many Hops");
break;
};
if (msg:len > max_len) {
sl_send_reply("513", "Message Overflow");
break;
};
# -----------------------------------------------------------------
# Record Route Section
# -----------------------------------------------------------------
if (method=="INVITE" && client_nat_test("3")) {
# INSERT YOUR IP ADDRESS HERE
record_route_preset("192.0.2.13:5060;nat=yes");
} else if (method!="REGISTER") {
record_route();
};
# -----------------------------------------------------------------
# Call Tear Down Section
# -----------------------------------------------------------------
if (method=="BYE" || method=="CANCEL") {
end_media_session();
};
# -----------------------------------------------------------------
# Loose Route Section
# -----------------------------------------------------------------
if (loose_route()) {
if (!has_totag()) {
sl_send_reply("403", "Forbidden");
break;
};
if (method=="INVITE") {
if ((method=="INVITE" || method=="REFER") && !has_totag()) {
if (!proxy_authorize("","subscriber")) {
proxy_challenge("","0");
break;
} else if (!check_from()) {
sl_send_reply("403", "Use From=ID");
break;
};
consume_credentials();
};
if (client_nat_test("3")||search("^Route:.*;nat=yes")){
setflag(6);
use_media_proxy();
};
};
route(1);
break;
};
# ----------------------------------------------------------
# Call Type Processing Section
# ----------------------------------------------------------
if (!is_uri_host_local()) {
if (is_from_local() || allow_trusted()) {
route(4);
route(1);
} else {
sl_send_reply("403", "Forbidden");
};
break;
};
if (method=="ACK") {
route(1);
break;
} if (method=="CANCEL") {
route(1);
break;
} else if (method=="INVITE") {
route(3);
break;
} else if (method=="REGISTER") {
route(2);
break;
};
lookup("aliases");
if (!is_uri_host_local()) {
route(4);
route(1);
break;
};
if (!lookup("location")) {
sl_send_reply("404", "User Not Found");
break;
};
route(1);
}
route[1] {
# ----------------------------------------------------------
# Default Message Handler
# ----------------------------------------------------------
if (!check_to()) {
sl_send_reply("401", "Unuthorized");
break;
};
consume_credentials();
if (!save("location")) {
sl_reply_error();
};
}
route[3] {
# ----------------------------------------------------------
# INVITE Message Handler
# ----------------------------------------------------------
if (client_nat_test("3")) {
setflag(7);
force_rport();
fix_nated_contact();
};
if (!allow_trusted()) {
if (!proxy_authorize("","subscriber")) {
proxy_challenge("","0");
break;
} else if (!check_from()) {
sl_send_reply("403", "Use From=ID");
break;
};
consume_credentials();
};
if (uri=~"^sip:1[0-9]{10}@") {
strip(1);
};
lookup("aliases");
if (!is_uri_host_local()) {
route(4);
route(1);
break;
};
if (uri=~"^sip:011[0-9]*@") {
route(4);
route(5);
break;
};
if (avp_db_load("$ruri/username", "s:callfwd")) {
setflag(22);
avp_pushto("$ruri", "s:callfwd");
route(6);
break;
};
if (!lookup("location")) {
if (uri=~"^sip:[0-9]{10}@") {
route(4);
route(5);
break;
};
sl_send_reply("404", "User Not Found");
break;
};
if (avp_db_load("$ruri/username", "s:fwdbusy")) {
if (!avp_check("s:fwdbusy", "eq/$ruri/i")) {
setflag(26);
};
};
if (avp_db_load("$ruri/username", "s:fwdnoanswer")) {
if (!avp_check("s:fwdnoanswer", "eq/$ruri/i")) {
setflag(27);
};
};
t_on_failure("1");
route(4);
route(1);
}
route[4] {
# ----------------------------------------------------------
# NAT Traversal Section
# ----------------------------------------------------------
if (isflagset(6) || isflagset(7)) {
if (!isflagset(8)) { 11
setflag(8);
use_media_proxy();
};
};
}
route[5] {
# ----------------------------------------------------------
# PSTN Handler
# ----------------------------------------------------------
rewritehost("192.0.2.245"); # INSERT YOUR PSTN GATEWAY IP ADDRESS
avp_write("i:45", "inv_timeout");
t_on_failure("1");12
route(1);
}
13route[6] {
# ----------------------------------------------------------
# Call Forwarding Handler
#
# This must be done as a route block because sl_send_reply() cannot be
# called from the failure_route block
# ----------------------------------------------------------
if (uri=~"^sip:1[0-9]{10}@") { 14
strip(1);
};
lookup("aliases");15
if (!is_uri_host_local()) { 16
if (!isflagset(22)) {
append_branch();
};
route(4);
route(1);
break;
};
if (uri=~"^sip:011[0-9]*@") {
route(4); 17
route(5);
break;
};
if (!lookup("location")) { 18
if (uri=~"^sip:[0-9]{10}@") {
route(4);
route(1);
break;
};
sl_send_reply("404", "User Not Found");
};
route(4);
route(1);
}
onreply_route[1] {
if ((isflagset(6) || isflagset(7)) &&
(status=~"(180)|(183)|2[0-9][0-9]")) {
if (!search("^Content-Length:[ ]*0")) {
use_media_proxy();
};
};
if (client_nat_test("1")) {
fix_nated_contact();
};
}
19failure_route[1] {
if (t_check_status("487")) { 20
break;
};
if (isflagset(26) && t_check_status("486")) { 21
if (avp_pushto("$ruri", "s:fwdbusy")) {22
avp_delete("s:fwdbusy");23
resetflag(26);
route(6);24
break;
};
};
if (isflagset(27) && t_check_status("408")) { 25
if (avp_pushto("$ruri", "s:fwdnoanswer")) { 26
avp_delete("s:fwdnoanswer");27
resetflag(27);
route(6); 28
break;
};
};
end_media_session();29
}
Call Forwarding ser.cfg Analysis
1. Call forwarding is dependent on the avpops module. This module needs to access the MySQL database in
order to read a subscribers call forwarding preferences from the usr_preferences table. So, here we specify
the MySQL database and table for call forwarding preferences.
2. Here is where we implement the blind call forwarding functionality. When processing an INVITE message
we need to lookup any row in the MySQL usr_preferences table to see if we can find a record that has the
name portion of the R-URI and an attribute of callfwd. If the avp_db_load() function returns TRUE then the
AVP named s:callfwd will have the blind call forwarding destination set.
3. If we are about to serial fork the call because of blind call forwarding, then we set flag 22 for future reference
in route[6]. This is important because this flag determines whether or not we need to call the append_branch()
function which actually forks the call. A subtle item to understand here is that blind call forwarding can only
happen when processing the original INVITE. This means that the destination set of the call has not been
processed yet, so we can safely alter the R-URI and the call to append_branch() should not be done.
Forward on busy and forward no answer however, only occur after the original INVITE has failed, which
means the destination set has been processed. In order to fork the call at this point the append_branch()
function must be called.Therefore, flag 22 will be set only for blind call forwarding.
4. Since avp_db_load() found a blind call forwarding record in MySQL we need to write that new destination
to the R-URI in order to send the INVITE message to the correct destination. Avp_pushto() does just this.
This statement copies the value in AVP s:callfwd to the R-URI of the actual message.
5. Send the processing to route(6) which handles all call forwarding.
6. This section loads the subscribers preferences for forward on busy and forward no answer. Load the forward
on busy setting from the MySQL usr_preferences table. Here we look for records in the database table where
the attribute column value is fwdbusy and the username part (before @) of the R-URI can be found in the
tables username column. avp_db_load() returns true if one or more records were found.
7. We do not allow users to forward to their now SIP phone, which would cause looping problems for SER. So
we use avp_check() to make sure the forward on busy destination is not the same as the R-URI destination.
If forward on busy is set then we need to remember this for future processing in the failure_route of this
configuration script. If the subscriber in the R-URI has forward on busy enabled, then flag 26 will be set,
and we will be able to detect this in the failure_route.
8. Load the forward no answer setting from the MySQL usr_preferences table. Here we look for records where
the username port of the R-URI has an attribute column value of fwdnoanswer.
9. We do not allow users to forward to their own SIP phone, which would cause looping problems for SER. So
we use avp_check() to make sure the forward no answer destination is not the same as the R-URI destination.
If forward on busy is set then we need to remember this for future processing in the failure_route of this
configuration script. If the subscriber in the R-URI has forward no answer enable then flag 27 will be set,
and we will be able to detect this in the failure_route.
10.t_on_failure() informs SER that we want to perform special handling when a failure condition occurs. Failure
conditions in this context refer to 4xx and 5xx response codes. For example, 486 is the response code for a
busy answer.
By setting t_on_failure(1) before calling t_relay(), SER will pass control to the code block defined as failure_
route[1] which appears at the end of the configuration scr
11. We must take special precautions not to call use_media_proxy() more than once because by doing so the c=
field in the SDP will get corrupted. This can happen if the original INVITE was NATed in route(4), get called
during the call set up, and a 486 Busy is received. This will trigger the forward on busy functionality. Once the call is forked, use_media_proxy() must not be called because it was already called during the original
INVITE processing logic.
12. Enable the failure route for all PSTN calls.
13. Here we introduce the call forwarding handler. This handler will create the new call leg for all three types
of call forwarding.
14. In North America we dial 1+ ten digits to call a long distance number. If the R-URI contains this prefix we
strip it off before processing.
15. Find any aliases. The call forwarding number in the MySQL usr_preferences table could very well be an
alias in our database.
16. If the R-URI is not served by our domain then call append_branch() for forward on busy and forward no
answer before enabling the NAT processing code in route(4) and relaying the cal from route(1).
17. If the R-URI is an international PSTN destination then call the NAT processing code in route(4) and relay
to the PSTN via route(5).
18. Find the R-URI in the user location cache. If a user is not found, then determine if it is a domestic PSTN
destination. If so, enable the NAT processing logic in route(4) and relay the call to the PSTN via route(5).
Enable NAT traversal code and relay the message. Messages hitting this line are INVITE messages being
forwarded to another SIP phone that is registered on this SIP router.
19. Here we introduce the failure route. If we call t_on_failure() before t_relay(), then SER will execute this code
block when a 4xx or 5xx reply message is received.
20. If we entered the failure route because the caller cancelled the call (ie, response code 487), then we simply
stop processing.
21. If forward on busy (flag 26) is set and the reply message is a 486, then enter the forward on busy code block.
22. Here we retrieve the previously loaded forward on busy destination URI. The AVP named s:fwdbusy is
copied to the R-URI.
23. Since we've now copied the forward on busy URI to the R-URI we can safely delete the AVP. We could
omit this line altogether and SER would free the AVP when the transaction is freed.
We now clear the forward on busy flag to prevent accidentally entering this code block on future 486 messages.
24. Here we pass control to the call forwarding route block and exit.
25. If forward no answer (flag 27) is set and the reply message is a 408 then enter the forward no answer code
block.
26. Here we retrieve the previously loaded forward no answer destination URI. The AVP named s:fwdnoanswer
is copied to the R-URI.
27. Since we've now copied the forward no answer URI to the R-URI we can safely delete the AVP. We could
omit this line altogether and SER would free the AVP when the transaction is freed.
We now clear the forward no answer flag to prevent accidentally entering this code block on future 408
messages.
28. Here we pass control to the call forwarding route block and exit.
29. Disable mediaproxy if it was enabled during the call set up.
Using the Call Forwarding ser.cfg Example
In order to use the new call forwarding SER configuration you need to populate the usr_preferences table in
MySQL. Below are a few example rows which show each of the call forwarding types.
Chapter 11. Appendix - How to download
and configure the latest version of SER
This appendix will show you how to download all the relevant source code, compile and install all the binaries to
make a working system. You will also be shown how to modify the source to support MySQL.
Downloading the Latest SER Source Code
As an alternative, you can get the source from the CVS. The source code to SER is kept under CVS control on the
website cvs.berlios.de.
To load the source you will either need the CVS package or you will have to browse the ftp.berlios.de
[ftp://ftp.berlios.de/] website to find the source code.
Most linux distributions have cvs loaded, in which case you can login to your usual account and enter the following
command :-
[ you will be prompted for a password, please just enter RETURN ]
cvs co -r rel_0_9_0 sip_router
This will create a directory sip_router in the current directory with all the source code, but not RTPproxy. To get
RPTproxy, you run the command cvs co -r rel_0_9_0 rtpproxy
Making the SER Binaries and installing
Once the source code has been loaded ( either via cvs or by extraction from a zip file ) we are now ready to compile
and install the binaries. The default makefiles does not compile a number of module ( including the MySQL
module ) but for the first hello world scenario we dont need it.
To make the code enter the following commands :-
cd sip_router
make all
All the modules will be compiled and ready for installation. To perform this task you need root privileges, so enter
the following command :-
su
[ Enter your root password ]
make install
This will install the binaries by default in the directory /usr/local/etc/ser
Your installation is now ready to be executed. However the next sub-section describes how to make your sip
server start whenever your machine is rebooted.
To check that everything is OK, enter the ser -V and you should get the following output :-
version: ser 0.9.3 (i386/linux)
flags: STATS: Off, USE_IPV6, USE_TCP, DISABLE_NAGLE, USE_MCAST, DNS_IP_HACK, SHM_MEM, SHM_ADAPTIVE_WAIT_LOOPS=1024, MAX_RECV_BUFFER_SIZE 262144, MAX_LISTEN 16, MAX_URI_SIZE 1024, @(#) $Id: main.c,v 1.197 2004/12/03 19:09:31 andrei Exp $
main.c compiled on 18:17:55 Mar 6 2005 with gcc 3.3
You will now have a working system. The binaries are loaded into the directory /usr/local/sbin, and the configuration
files ( including ser.cfg ) loaded into the directory /usr/local/etc/ser.
If you take the hello world ser.cfg file and replace the one in the configuration directory you can start the sip
server by having root privileges and entering the command :-
# ser
To check everything is OK, run the ps command to see if there are a number of ser processes running.
You now have a working system.
You can get the latest version from http://mediaproxy.ag-projects.com/.
The package has thorough INSTALL and README files. PLEASE NOTE that the configuration files in this
document does not use proxydispatcher.py. That is, the mediaproxy SER module calls the mediaproxy.py proxy
daemon directly. If you want to install mediaproxy on another server, you will have to start proxydispatcher.py
on the server running SER and mediaproxy.py on the dedicated RTP proxy server. Change the following line in
ser.cfg:
Please refer to the INSTALL and README files if you want to run multiple mediaproxy RTP proxy servers.
Configuring the system
Generally, the system has to be configured so that the installed programmes are executed at start-up. Normally,
this is completed by providing files in /etc/init.d. We leave it to the user to configure the services of their own
system; however we have provided example scripts to start the SER and mediaproxy processes. Please note, if you
are not supporting RTP proxying, then you do not need to run the mediaproxy process.
To install the scripts, please create the file(s) in the /etc/init.d directory and then run the commands :-
# chkconfig -add ser
# chkconfig -add mediaproxy
Init.d/ser
#!/bin/bash
#
# Startup script for SER
#
# chkconfig: 345 91 15
# description: Ser is a fast SIP Proxy.
#
# processname: ser
# pidfile: /var/run/ser.pid
# config: /etc/ser/ser.cfg
# Source function library.
. /etc/rc.d/init.d/functions
ser=/usr/local/sbin/ser
prog=ser
OPTIONS="-d -d -d -d -d -d -d -d -d"
RETVAL=0
start() {
echo -n $"Starting $prog: "
daemon $ser $OPTIONS
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch /var/lock/subsys/ser
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc $ser
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f /var/lock/subsys/ser /var/run/ser.pid
}
reload() {
echo -n $"Reloading $prog: "
killproc $ser -HUP
RETVAL=$?
echo
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $ser
RETVAL=$?
;;
restart)
stop
sleep 3
start
;;
condrestart)
if [ -f /var/run/ser.pid ] ; then
stop
start
fi
;;
*)
echo $"Usage: $prog {start|stop|restart|condrestart|status|help}"
exit 1
esac
exit $RETVAL
Init.d/mediaproxy
The mediaproxy programme is used to support NAT configurations.
#!/bin/sh
#
# chkconfig: 2345 90 20
# description: VoIP RTP Proxy Server
#
# processname: mediaproxy
# pidfile: /var/run/mediaproxy.pid
# source function library
. /etc/rc.d/init.d/functions
# Options for mediaproxy and dispatcher. Do not include --pid pidfile
# --pid pidfile will be added automatically if needed.
PROXY_OPTIONS="--ip=10.3.0.221 --listen=127.0.0.1"
DISPATCHER_OPTIONS="domain://sip.dialez.com"
NAME="mediaproxy"
DESC="SER MediaProxy server"
test -f $PROXY || exit 0
test -f $DISPATCHER || exit 0
if [ "$PROXY_PID" != "/var/run/mediaproxy.pid" ]; then
PROXY_OPTIONS="--pid $PROXY_PID $PROXY_OPTIONS"
A database is needed to support a number of functions within ser. Namely authentication and accounting. In our
configuration we have used MySQL, other databases can be supported but will require a different setup.
We are assuming that you have a working MySQL database with a root password. Of course, you will also need
the development MySQL package loaded as it contains the header files for the source code.
To support MySQL, three steps are needed :-
1. Modify the source, rebuild and reinstall the binaries
2. Modify MySQL to support the database and tables needed
3. Modify the ser.cfg to use the database
All the source has already been loaded, what we need to change is the Makefile so that we now include the MySQL
module. Edit the file src/sip_router/Makefile and at the line starting exclude_modules= remove the reference to
mysql. Save the file and then recompile the code with the command make all. Reinstall the binaries by taking root
privileges and executing make install.
MySQL needs to be modified to support the SER database and tables. Again take on root privileges and execute
make dbinstall. You will be asked for the root MySQL password and also the realm that you want. This is configurable,
but normally you use the IP address of the sip server.
Now replace the ser.cfg file with the one that supports MySQL and restart the sip server.
Debugging Tips
There a number of techniques available to debug SER, the main types fall into two categories :-
1. Capture the SIP messages
2. Generate debug information
These types will now be described.
Capture of SIP Messages
A very useful technique is to look at the actual SIP messages that are produced by SER as seen by other clients
on the network. Two tools are commonly used, ethereal ( or the text based equivalent tethereal ) and ngrep. Assuming
that you have root access to the sip server, then the syntax for running ethereal is :-
# ethereal port 5060
This will display all packets being sent and received from port 5060 which is the common port used by sip. Added
-w file.cap will store the data for future viewing.
Generate Debug Information
SER has the ability to generate a vast amount of information that can be used for debugging. To capture this data,
either the stderr file can be redirected, or the program run in foreground. This later technique is achieved by
modifying the line fork=no in ser.cfg.
Once the data is being displayed /captured, then the level of detail can be varied by modifying the line debug=4
in ser.cfg higher the number more detail is generated.
Finally the user can add more information by inserting into ser.cfg the command xlog at appropriate points then
debug information is required. Please refer to the xlog module README for details.
Chapter 12. Appendix The Call Processing
Language (CPL)
The Call Processing Language (CPL) is a language designed to describe and control Internet telephony services
and provide call processing functionality. It is designed for end user service creation and is purposely limited its
capabilities. It works on top of SIP or H323 and is a safe language for non-experienced users as it can only access
limited resources, cannot call external programs and does not provide loops or recursion. To highlight the applicability
of this language, suggestions are given below regarding possible uses of CPL scripts, including call routing,
screening and logging services:
1. Call Forward on Busy/No Answer
2. Call Screening and Rule Based Call Processing
3. Intelligent User Location
4. Administrator Service Definition
[Enables administrators to devise policies for site wide telephony use]
1. Web Middleware
2. Sequential Call Forking (Note the SER LCR and AVPOPS module can also be utilised)
Ser.cfg
Before CPL scripts can become operational on the SER server, the ser.cfg must be modified to interpret the scripts
correctly.
The cpl-c module must first be loaded by ser:
loadmodule "/opt/ser/lib/ser/modules/cpl-c.so"
Next the modules must be configured:
In this case "username" and "password" represent the username and password for the mysql database named ser.
The entry at "localhost" should match with the server name on which the mysql database is running. ser and heslo
are the default username and password.
modparam("cpl-c", "cpl_table", "cpl")
This refers to the "cpl" table which is the default table for the cpl-scripts in the database.
Pointers to the location of the CPL XML DTD file must be given (the XML DTD is necessary for parsing CPL
scripts and is described in further detail later in this section).
modparam("cpl-c", "lookup_domain", "location")
This parameter should be set to "location" to let the lookup-node work correctly.
All the above parameters are mandatory. Two more parameters exist which are optional: A debugging parameter
pointing to the existence of a log file and a parameter that specifies the maximum of recursive executions in CPL.
If an invite is incoming and a cpl script exists for the recipient, the default call processing is forfeited in favour of
the CPL script logic.
#--------------------Call Type Processing Section---------------------#
# if the request is for other domain use UsrLoc
# (in case, it does not work, use the following command
# with proper names and addresses in it)
if (uri==myself) {
if (method == "INVITE"){
if(!cpl_run_script("incoming", "is_stateless"))
{
# script execution failed
t_reply("500", "CPL script execution failed");
};
route(3);
break;
} else if (method == "REGISTER"){
#handle REGISTER messages with CPL script
cpl_process_register();
route(2);
break;
};
Once the ser.cfg has been modified and SER has been restarted, issue the pstree command and two child processes
should be observed:
e.g
|---rtpproxy
|---ser-+-25&[ser]
---2*[ser---ser]
Uploading a CPL Scrip
A CPL script can be uploaded onto SER using either the SIP REGISTER message or manually via SERs FIFO
facility.
SIP REGISTER Message
A SIP REGISTER message (the message used by SIP to register a user on the network) contains the CPL script
in the body/payload. When the REGISTER message reaches SER, the CPL script is retrieved from the payload
and stored in the cpl table of the ser database. Thus, the CPL script resides in the SER database and will be executed
when a call arrives addressed to that user. Then the script will drive the action to be taken with that call according
to the requirements specified by the user in the script
CPLED, a free graphical tool, can be used for the above purpose. It includes a script transport feature whereby
scripts can be downloaded, uploaded or removed via http or the SIP REGISTER method (authentication supported).
For more information refer to http://www.iptel.org/products/cpled/.
Serctl FIFO Interface
To use the FIFO interface, a command similar to the following can be used:
If a user wishes to remove a particular CPL script, this can also be done using SERs FIFO facility.
serctl fifo REMOVE_CPL user@domain
hat, Where, Which & How?
What does a CPL script do? - A CPL script runs in a signaling server (not protocol specific, can be SIP or H323)
and controls that systems proxy, redirect or rejection actions for the set-up of a particular call. More specifically
it replaces the user location functionality of a signaling server. It takes the registration information, the specifics
of the call request and other external information and chooses the signaling actions to perform.
Where are CPL scripts located? - Users can have CPL scripts on any network server which their call establishment
requests pass through and with which they have a trust relationship. CPL scripts can reside on SIP/H323 servers,
application servers or intelligent agents.
Which party generates CPL scripts? - CPL scripts are extremely generic in their ability to be adapted to the requirements
of all parties involved in a call transaction. In the most direct approach, end users can utilise CPL for describing
their services. Third parties can also utilise CPL to create and/or customize services for clients, running
on either servers owned by the user or the users service provider. Service administrators can also use CPL to define
server service policies and it can also act as a back end for a web interface whereby service creation and customization
is provided transparently to the user
CPL scripts are usually associated with a particular Internet telephony address. Each SER user can only have one
CPL script. If a new script is loaded, the previous one is overwritten. If different services are required by the same
user e.g. time based routing, call screening, forward on busy etc, then these must be mixed in the same script during
provisioning.
How? - Methods for CPL Script Generation
Manually
CPL scripts can be easily created by hand due to its uncomplicated syntax and similarity with HTML. Examples
of such scripts are included at the end of this document.
Automated
As previously described, web middleware could be utilised to transparently provision the CPL syntax.
Graphical Tools
Graphical User Interface (GUI) tools are also available for provisioning CPL scripts. These provide inexperienced
users with powerful access to CPLs functionality through a simple interface.
An example of this is CPLED, a free graphical CPL editor which was mentioned earlier in the section. It is written
in JAVA and can be used as a standalone application or JAVA applet.
The XML DTD for CPL
Syntactically, CPL scripts are represented by XML documents. This is advantageous in that it makes parsing easy
and parsing tools are publicly available. It is simple to understand and like HTML consists of a hierarchical
structure of tags. A complete Document Type Declaration (DTD) describing the XML syntax of the CPL can be
found in the /ser-0.9.0/modules/cpl-c directory and also should be called from the ser.cfg as shown earlier. It should
be consulted if syntax errors are experienced uploading CPL scripts and all CPL scripts should comply with this
document. The XML DTD is also provided in Appendix X.
CPL Script Examples
Call Screening a Particular Contact
This script demonstrates CPLs call screening abilities and rejects all calls received from extension 2000.
?xml version=1.0 ?
!DOCTYPE cpl SYSTEM cpl.dtd
cpl
incoming
address-switch field=”origin” subfield=”user
address is=2000
reject status=reject reason=I don’t take calls from extension 2000 /
/address
/address-switch
/incoming
/cpl
Time-Based Switch
This script illustrates a time-based CPL script. Incoming calls received between Monday Friday and 9 a.m to 5
p.m. are proxied as normal. However if a call presents at the server outside those hours, it is directed to the users
voicemail.
The following example illustrates a service based a calls priority value and language settings. If the call request
has a priority of urgent or higher, the default script behavior is performed. Otherwise the language field is checked
for the language (Spanish) and if it is present the call is proxied to a Spanish-speaking operator, otherwise to an
English-speaking operator.
A More Complex Example [not verified]
In this scenario a user wants all calls directed to the terminal at his desk. If he does not answer after a certain
period of time, calls from this boss are forwarded to his pda and all others are directed to his voicemail.