Sophie

Sophie

distrib > Fedora > 13 > i386 > media > os > by-pkgid > cb7205622a1b72763262ee3e5a936b14 > files > 74

sems-1.1.1-6.fc12.i686.rpm


******* IMPORTANT ***************************************************************************
 This is only needed if SER, the SIP Express Router, is used as SIP stack for SEMS. Since 1.0 
 you can simply use the sipctrl module, which provides a SIP stack for SEMS. sipctrl is set
 as the default control plugin, so usually there need not be any changes in that regard.

 But, if you need more functionality from the SIP stack, e.g. TLS, TCP, filtering of inbound 
 requests etc., you can use ser2 with the binrpcctl module, and the SASI SER application server 
 interface, and then parts of the information below apply.
*********************************************************************************************

***************************
*  Sems + Ser mini-HOWTO  *
***************************


1. Introduction:

This document describes the configuration of a typical Sems installation. In 
this document, it will be asserted that the reader has a basic understanding 
of Linux and SIP (Session Initiation Protocol, RFC 3261). If you don't, 
please try to get more familiar to Linux before continuing reading this
document. If need more information on SIP, consider downloading iptel.org's
SIP tutorial (www.iptel.org/sip).


2. Getting Ser and Sems to communicate together:

To work properly, Sems needs a working Ser instance, which will be used as
Sems' SIP stack. They communicate together through unix socket servers. 
Each side implements a server, enabling communication in both ways.You 
will need to configure Ser to use Sems's server, and Sems to use Ser's 
server. If you plan to run more than one Ser instance on the same host, 
be sure to know wich Ser instance you want to connect to SEMS.

Usually the best is to have one SER instance which acts only as SIP stack
for Sems. This SER could e.g. be listening on port 5070 for SIP messages.
If in the home proxy (or any other place) a new INVITE should be sent to Sems, 
e.g. into a conference, the home proxy just relays the INVITE to the media server 
on port 5070. An example ser-sems.cfg file for this type of configuration
can be found in core/etc/ser-sems.cfg.

For each version of Sems there is a recommended version of SER to run it with. Thus 
it might be necessary to run two different versions of SER on the same machine. The 
best method to do this is to install the SER for Sems in a special location, e.g. 
in /opt/ser-sems/.

For sems 0.10.0, for which the recommended ser version is ser-0.9.6-sems, Do : 

 mkdir -p /opt/ser-sems/src 
 cd  /opt/ser-sems/src
 wget http://ftp.iptel.org/pub/sems/ser-0.9.6-sems_src.tar.gz
 tar -vxzf ser-0.9.6-sems_src.tar.gz
 cd ser-0.9.6-sems
 make install PREFIX=/opt/ser-sems

This way, you have your own ser-sems installation in a compleatly
seperate dir, and you can simply continue to play with it as you want  :)  

2.1 Configure Sems to use Ser's Unix socket server


    - edit Ser's configuration file (default location:
      /usr/local/etc/ser/ser.cfg) and look for the 'unix_sock=' 
      configuration parameter. It should look like:
	 unix_sock="/tmp/ser_sock"

      If the 'unix_sock' parameter does not exist, add it to the global 
      section. If you have another value for that parameter, you don't need to
      change it, just remember it.

    - open Sems's configuration file (default location:
      /usr/local/etc/sems/sems.conf) 
      - look for the 'ser_socket_name=' parameter. It must have the 
        same value as 'unix_sock=' in Ser's configuration file, 
        but without quotes. In our example:

         ser_socket_name=/tmp/ser_sock

      - configure the socket on which sems will get responses from ser:

         reply_socket_name=/tmp/sems_resp_sock

      - then configure SEMS' socket itself, useing the 
        'socket_name=' parameter in sems.conf. Default value:

	 socket_name=/tmp/sems_sock


2.2 How to redirect a call to sems?

2.2.1 How it works:

So that a caller gets connected to Sems, Ser has to pass every SIP message
concerning that call to Sems through unix socket. Basically, Sems 
needs to get an INVITE message to begin a call, and a BYE message to terminate 
that call. Sems must also be aware of CANCELs. ACKs should be absorbed by Ser, 
as Sems does not need them. If you want SEMS to be aware of DTMF tones sent
via SIP INFO messagees, they must be passed to SEMS as well. 
Redirecting the messages is a very simple operation. You just have to 
call the t_write_unix() function from the 'tm' module, which you have to 
load. As ser needs to be aware about the transaction of the request, you #
need to call t_newtran() before writing the request to the socket using 
t_write_unix.

2.2.2 Load Ser's tm module 

    - add following line to your ser.cfg in the 'module loading' section:

    loadmodule "/usr/local/lib/ser/modules/tm.so"

    configure tm to also pass provisional replies to sems:
    modparam("tm", "pass_provisional_replies", 1)

2.2.3 Redirecting SIP messages to Sems:

In this example it is assumed that different applications should be executed
when different LHS part of the URI are called, for example, 100 should be 
redirected to conference, 200 to announcement etc.

    - add following lines to your ser.cfg where you need to redirect the call:

      # select messages to redirect:
      if ( method=="ACK" || method=="INVITE" || method=="BYE" ||
           method=="CANCEL" ){

	   # switch to stateful mode:
	   if (!t_newtran()){
		sl_send_reply("500","could not create transaction");
		break;
	   };

	   # prevent timeout on the other side:
	   t_reply("100","Trying - just wait a minute !");
	   
	   if (method=="INVITE"){

		# redirect the call to the 'conference' plug-in
		# if the URI begin with 100
		if (uri=~"sip:100.*@") {

		   # assumes that Sems configuration parameter 'socket_name='
		   # has been set to /tmp/sems_sock
		   if(!t_write_unix("/tmp/sems_sock","conference")) {
		      t_reply("500","error contacting sems");
		   };
		   break;
		};

		# redirect the call to the 'announcement' plug-in
		# if the URI begin with 200
		if (uri=~"sip:200.*@") {

		   if(!t_write_unix("/tmp/sems_sock","announcement")) {
		      t_reply("500","error contacting sems");
		   };
		   break;
		};

		# no service number, redirect to voicemail.
		# load email address into AVP so that voicemail gets the
		# callee's email address. (see below for avpops modparams)
                #   
		avp_db_load( "$ruri", "$email/$email_scheme");
		if(!t_write_unix("/tmp/sems_sock","voicemail")) {
		    t_reply("500","error contacting sems");
		};
		break;
	   } 
	   else if (method=="BYE" || method="CANCEL") {

		# Sems should already know which plug-in is handling that
                # call. "bye" is no plug-in name. It is a reserved name which
		# tells Sems to terminate the call.

		if(!t_write_unix("/tmp/sems_sock","bye")) {
		    t_reply("500","error contacting sems");
		};
	   } 
	   else if (method=="ACK") {
		# absorb ACKs
		t_relay();
	   }
 
      };

In more complicated scenario, you could also redirect REFERs to Sems which
would enable you for example to implement a click-to-dial, or invite other
users to take part to conference.

2.3 Passing additional parameters to SEMS: email address for voicemail

Arbitrary AVPs (attribute value pairs) can be appended to a request when it is
written to sems with t_write_req/t_write_unix using tw_append. The AVPs can
e.g. be loaded from a database before, modified with avpops etc. 

This is a flexible method, e.g. the language of a user can be stored in the
database, and the greeting and voicemail template will be selected according
to the language.

For the voicemail plug-in to work properly, sems has to get the email address
of the callee. As email adresses are usually stored in a database and ser
usually already has a db connection, the email address is looked up when the 
INVITE request is processed and added as extra header 'P-Email-Address' to 
the request. Then SEMS gets the address from this header.

The relevant parts of the ser configuration then look like this:

# load db module
loadmodule "/usr/local/lib/ser/modules/mysql.so"

# load avp modules
loadmodule "modules/avp/avp.so"
loadmodule "modules/avpops/avpops.so"

# configure avpops db connection
modparam( "avpops", "avp_url", "mysql://ser:heslo@localhost/ser" )
modparam( "avpops", "avp_table", "subscriber" )
modparam( "avpops", "uuid_column", "id" )

# configure aliases, the number doesn't matter as long as there are no collisions)
modparam( "avpops", "avp_aliases", "email=i:67 ; language=i:68" )

# scheme to access the database
modparam( "avpops", "db_scheme", 
	  "email_scheme:table=subscriber;value_col=email_address;value_type=string")
modparam( "avpops", "db_scheme", 
	  "language_scheme:table=subscriber;value_col=language;value_type=string")

# configure tm to append this when tw_appent voicemail_headers is used
modparam("tm", "tw_append",
	       "voicemail_headers:P-Email-Address=avp[$email];P-Language=avp[$language]")

# ...

# in route section:
                        # no service number, redirect to voicemail.

			avp_db_load( "$ruri", "$email/$email_scheme");
			avp_db_load( "$ruri", "$language/$language_scheme");

			if(!t_write_unix("/tmp/sems_sock","voicemail/voicemail_headers")) {
			   t_reply("500","error contacting sems");
			};
			break;


This assumes that there is a column 'id', a column 'username', a column 'email_address' and a
column 'language' in the table named 'subscriber'. dbtext sample file would be:
----- subscriber  --------------------------------
id(int,auto) username(str,null) domain(str,null) email_address(str,null) language(str,null)
1:Alice:iptel.org:alice@mymail.org:english
2:rco:iptel.org:rco@iptel.org:french
3:Alex:iptel.org:alex@iptel.org:german
----- subsciber end ------------------------------

AVPs for email and language may also be loaded from e.g. raduis.

2.4 Passing SIP INFO messages to SEMS for DTMF 

The same mechanism using tw_append is used to pass the headers content-type, content-length
and the body of an INFO message to SEMS:

modparam( "tm", "tw_append",
   "info_append:hdr[Content-Length];hdr[Content-Type];msg[body]")
...

if (method=="INFO") {
        if(!t_write_unix("/tmp/sems_sock","sems/info_append")){
            log("could not contact sems\n");
            t_reply("500","could not contact media server");
        };
} 

2.5 Passing arbitrary parameters to SEMS

For early media announcements (early_announce app) the final reply code
can be configured from the ser configuration. 

modparam( "avpops", "avp_aliases", "early_code=i:66 ; early_reason=i:67" )

# this is to be appended to the invite
modparam("tm", "tw_append",
               "early_headers:P-Final-Reply-Code=avp[$early_code];P-Final-Reply-Reason=avp[$early_reason]")

...

   avp_write("405", "$early_code");
   avp_write("Prohiboted", "$early_reason");

   if(!t_write_unix("/tmp/sems_sock","early_announce/early_headers")){
             log("could not contact early_announce\n");
             t_reply("404","not found");
   };
   break;


3. Example real-life voicemail config

This would be a real-life config example for voicemail with email address and 
language loading from radius, and NAT handling. 


modparam("tm", "tw_append", "vm_avps:P-Email-Address=$avp(CALLEE_EMAIL_AVP);P-Language=$avp(CALLEE_LANGUAGE_AVP)")

...

if (method == "INVITE") {
	if (!t_newtran()) {
		xlog("L_ERR", "Could not create new transaction for <$rm> to <$ru>\n");
		sl_send_reply("500","Could not create new transaction");
		exit;
	};
	t_reply("100", "Trying -- just wait a minute!");
	if (isflagset(FROM_NATED)) {
		fix_nated_contact();
		fix_nated_sdp("1");  # add direction=active
	};
	if (isflagset(VOICEMAIL)) {
		avp_load_radius("callee");
		if (!is_avp_set("$avp(CALLEE_EMAIL_AVP)")) {
			xlog("L_ERR", "Callee <$ru> email address not found\n");
			t_reply("404", "Not found");
			exit;
		};
		if(!t_write_unix("/tmp/sems_sock","voicemail/vm_avps")) {
	        	xlog("L_ERR", "Could not contact Voicemail Server for <$ru>\n");
			t_reply("500","Could not contact Voicemail Server");
			exit;
		};
		xlog("L_INFO", "Relayed $rm <$ru> by <$fu> to Voicemail Server\n");
		exit;
	};
};

...

# In-dialog requests
if (has_totag()) {
	loose_route();
	if (isflagset(FROM_NATED)) {
		fix_nated_contact();
	};
	if ((method == "ACK") && (uri != myself)) {
		route(FIND_SERVICE);
		switch ($retcode) {
		    case -1:
			xlog("L_ALERT", "Transit is not allowed to <$ru>\n");
			sl_send_reply("403", "Forbidden - Transit is not allowed");
			exit;
		    default:
		};
		if (!is_uri_host_local()) {
			xlog("L_ALERT", "Transit is not allowed to <$ru>\n");
			sl_send_reply("403", "Forbidden - Transit is not allowed");
			exit;
		};
		# negative ack
		t_relay();
		exit;
	};
	if (uri != myself) {
		xlog("L_ALERT", "Transit is not allowed to <$ru>\n");
		sl_send_reply("403", "Forbidden - Transit is not allowed");
		exit;
	};
	# Relay in-dialog request
	if (method =~ "(ACK|INVITE|BYE)") {
		if (!t_newtran()) {
			xlog("L_ERR", "Could not create new transaction\n");
			sl_send_reply("500","Could not create new transaction");
			exit;
		};
		if (method == "INVITE") {
			if (isflagset(FROM_NATED)) fix_nated_sdp("1");
			if(!t_write_unix("/tmp/sems_sock","invite")) {
		    	    	xlog("L_ERR", "Could not contact answer machine\n");
				t_reply("500","Could not contact Answer Machine");
			};
			exit;
		};
		if (method == "ACK") {
			t_relay();
			xlog("L_INFO", "Relayed in-dialog ACK to <$ru>\n");
			exit;
		};
		if (method=="BYE") {
			if(!t_write_unix("/tmp/sems_sock","bye")) {
        		xlog("L_ERR", "Could not contact answer machine\n");
				t_reply("500","Could not contact Answer Machine");
			};	
			xlog("L_INFO", "Relayed in-dialog BYE to <$ru>\n");
			exit;
		};
	};