Žilinská univerzita > Fakulta riadenia a informatiky > Katedra informačných sietí

Kamailio 3.3 and FreeSWITCH 1.2.2 interconnection for voicemail and conference services on Debian Squeeze (6.0) 64bit - TUTORIAL

This tutorial will, hopefully, guide you on configuration of interconnection between Kamailio and FreeSWITCH. We will use Kamailio as proxy and registrar server and use FreeSWITCH only for services.

 

All of the configuration files that have been changed are part of attachment of this tutorial. In Original.zip you will find the original files and in Modified.zip the modified version. So you can actually compare them side by side. This could be really useful and I hope it will help you in every way possible.

 

Note:

I will use mcedit as editor throughout this tutorial, but feel free to use anything you like (nano, joe, vim, whatever...)


1. Basic installation of Kamailio 3.3

 

First download and add GPG key to your apt key list:

root@server:/# wget http://deb.kamailio.org/kamailiodebkey.gpg
root@server:/# apt-key add kamailiodebkey.gpg

Then add the repository lines to your /etc/apt/sources.list file depending on the Kamailio version of your choice. As we have chosen the latest stable release (3.3) for Debian Squeeze we can either use:

root@server:/# mcedit /etc/apt/sources.list

deb http://deb.kamailio.org/kamailio33 squeeze main
deb-src http://deb.kamailio.org/kamailio33 squeeze main

 

Then just execute the following command from shell

root@server:/# apt-get update
root@server:/# apt-get install kamailio

 

Now we need to edit file /etc/default/kamailio in following manner. Find the line RUN_KAMAILIO=no and replace no with yes:

root@server:/# mcedit /etc/default/kamailio
RUN_KAMAILIO=yes

 

This change will make sure that Kamailio will automatically start also after reboot.

Then edit the file /etc/kamailio/kamailio.cfg and find the line #alias="sip.mydomain.com" in the
####### Global Parameters #########
section and change it accordingly to your domain. Delete the # character from the beginning as this character identifies comment.

 

root@server:/# mcedit /etc/kamailio/kamailio.cfg

alias="sitea.local"

Save the file.

 

You can now run Kamailio:

root@server:/# kamctl start

or

root@server:/# /etc/init.d/kamailio start

/etc/init.d/kamailio start is better when you want to see the IPs and ports that Kamailio listens to, use abbreviated form kamctl start when you don't need to verify this.

 

 

Note:

After every change in configuration (after edit of file /etc/kamailio/kamailio.cfg) you must restart Kamailio process. You can do this by this command:
root@server:/# kamctl restart
or
root@server:/# /etc/init.d/kamailio restart

The second command is better in the same way as /etc/init.d/kamailio start, because it gives an output of IP and ports which Kamailio listens to.

If you need to stop Kamailio entirely, just issue following command:
root@server:/# kamctl stop
or
(root@server:/# /etc/init.d/kamailio stop)

In this case it really doesn't matter which one you use.

 

 

To make sure that Kamailio listens on the right IP and port we will run it issuing the first mentioned way.

root@server:/# /etc/init.d/kamailio start
Starting Kamailio:
loading modules under /usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/
Listening on
             udp: 127.0.0.1:5060
             udp: 158.193.139.52:5060
             tcp: 127.0.0.1:5060
             tcp: 158.193.139.52:5060
Aliases:
             tcp: server:5060
             tcp: server.sitea.local:5060
             tcp: localhost:5060
             udp: server:5060
             udp: server.sitea.local:5060
             udp: localhost:5060
             *: sitea.local:*

kamailio started.

 

2.    Installation of MySQL and adding MySQL support into Kamailio

 

During MySQL server installation we have to add password for root user of database. That user have the rights to administrate all databases.

root@server:/# apt-get install mysql-server kamailio-mysql-modules

 

Next, we have to specify parameters, which the kamailio server will use for database connection. Therefore we need to edit the /etc/kamailio/kamctlrc file and we need to set up required parameters, which the kamailio server and kamctl cmd will use.

root@server:/# mcedit /etc/kamailio/kamctlrc

We will uncomment and ,if necessary, change following lines:

SIP_DOMAIN=sitea.local
DBENGINE=MYSQL
DBHOST=localhost
DBNAME=openser
DBRWUSER=openser
DBRWPW="openserrw"
DBROUSER=openserro
DBROPW=openserro
DBROOTUSER="root"
ALIASES_TYPE="DB"
CTLENGINE="FIFO"
# rewrite OSER_FIFO="FIFO", 
# because it is causing the fifo error
#!!! change from previous version of such a tutorial where OSER_FIFO="/tmp/kamailio_tmp" !!!
#http://nil.uniza.sk/sip/kamailio/adding-mysql-support-kamailio-31-debian-lenny
OSER_FIFO="/tmp/kamailio_fifo"
VERBOSE=1
PID_FILE=/var/run/kamailio.pid

Then we have to create Kamailio database by issuing command:

root@server:/# kamdbctl create

Then type in the mysql root password. If you want to, you can install also presence and some extra tables, if you plan to go beyond the basic configuration or to improve it later with some extra features such as presence, messaging and so on.

 

Then edit the file /etc/kamailio/kamailio.cfg

root@server:/# mcedit /etc/kamailio/kamailio.cfg

Find lines like #     - define WITH_MYSQL 
(only the following 4, not all)
and change them like this:

#!define WITH_MYSQL
#!define WITH_AUTH
#!define WITH_USRLOCDB
#!define WITH_ALIASDB

Then restart Kamailio

root@server:# /etc/init.d/kamailio restart

 

Note:

Some useful commands for Kamailio DB are:
kamdbctl reinit -drops the database then recreate it
kamdbctl create -create new database for Kamailio
kamdbctl drop -drops Kamailio database

 

So we can now add users which can then register with Kamailio and make calls. I strongly advice to test this before moving further - so if there are any errors you can find it easily, later on they will be much harder to spot!
To do this, we can use opensource client Jitsi (also good for testing presence and messaging), or free version of X-lite (just calls and messaging).

 

root@server:/# kamctl add pepe pass123
root@server:/# kamctl add jojo pass321

This will add 2 users (pepe with password pass123 and jojo with password pass321) into database, which can then register and make call with one another.

 


3.    Basic installation of FreeSWITCH

 

First we need to meet some prerequisites. You can check them here: http://wiki.freeswitch.org/wiki/Installation_Guide#Common_Prerequisites

 

root@server:/# apt-get install autoconf automake gawk g++ libjpeg62-dev libncurses5-dev libtool make python-dev 
pkg-config libtiff4-dev libperl-dev libgdbm-dev libdb-dev

 

I recommend to install FreeSWITCH from GIT rather than download it as an archive and compiling.
Git provides access to the latest features and bug fixes added throughout the day. Most often you will only use the "clone" and "pull" commands. There is an excellent Online Git Book available in multiple languages. http://progit.org/book

Installing GIT is rather simple:

root@server:# apt-get install git-core

 

Selecting version:
There are 2 branches in Git - Master and v1.2.stable
v1.2.stable is the branch for the 1.2 series. It will be the most recent 1.2.x release (currently 1.2.2), plus any patches made since that release.

Master is where the development for the future 1.4 release is being done. New features are added to this branch, but it may be less stable than 1.2.stable at times.

So we will choose the stable 1.2 version.

root@server:/# cd /usr/local/src
root@server:/usr/local/src# git clone -b v1.2.stable git://git.freeswitch.org/freeswitch.git

 

Note:
If you want to later switch branches on already cloned Git tree you can use:

root@server:/usr/local/src# git checkout master

(or git checkout v1.2.stable if you were using the Master branch)
To find out more check this site: http://wiki.freeswitch.org/wiki/Installation_Guide#Installed_from_Git

 

We will now proceed to the next step.
All of the following commands are run from freeswitch directory, therefore we issue the command:

root@server:/usr/local/src# cd /usr/local/src/freeswitch

 

The configuration files must be built before the first compile. ./bootstrap.sh creates many files including modules.conf. Once this is performed it's not normally required to be performed again:

root@server:/usr/local/src/freeswitch# ./bootstrap.sh

 

Note:

You can use multiple cores for your bootstrap/config/build, by specifying it at the start, e.g.: (note this may make build errors harder to spot)

cd /usr/local/src/freeswitch
./bootstrap.sh -j

 

 

Now to configure FreeSWITCH for compilation

./configure sets compilation options. Invoke the following command to configure for compilation:

root@server:/usr/local/src/freeswitch# ./configure

 

You can have the checks cached for each module, by using:

root@server:/usr/local/src/freeswitch# ./configure -C

 

If you want to install FreeSWITCH to a non-standard location you can simply append the --prefix option to the configure script as shown in this example:

root@server:/usr/local/src/freeswitch# ./configure --prefix=<example of non standard location>

 

Edit modules.conf

The modules.conf file contains the list of modules to be compiled, some are commented as they are not required. As your FreeSWITCH٠configuration becomes more complex additional modules may be required. If you plan to test the sample IVR after installation, FLITE must be added to the compile as follows:

Use an editor to navigate to and edit /usr/local/src/freeswitch/modules.conf (or whatever directory it was placed into)
    

root@server:/usr/local/src/freeswitch# mcedit modules.conf

Search for "flite" and remove the # to uncomment asr_tts/mod_flite

asr_tts/mod_flite

Save the file.

 

If this is your first experience with FreeSWITCH don't add more than FLITE. Adding functions may result in additional prerequisites that must be installed.

Building FLITE requires about 450 megabytes of addressable memory, so if you are building on a device with limited RAM, you'll need to create a swap file (a.k.a. Virtual Memory or paging file) of sufficient size to allow the build to proceed, or simply do not include mod_flite in the build. All other modules in the default configuration will build successfully on devices with less than 100MB of available RAM.

 

Note:

I have also installed module for HTML5 just for my testing purposes. Everything worked fine.

 

In the FreeSWITCH Wiki they forgot to mention that you need to have some unzipper for the modules because they are downloaded during the compilation and installation in .tar.bz2 format. Unzip worked for me just fine.

root@server:/usr/local/src/freeswitch# apt-get install unzip

 

Note:

This is the error you get if you don't install unzip

making all mod_flite
--2012-09-13 15:56:41--  http://files.freeswitch.org/downloads/libs/flite-1.5.4-current.tar.bz2
Resolving files.freeswitch.org... 108.161.188.3
Connecting to files.freeswitch.org|108.161.188.3|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14740774 (14M) [application/x-bzip2]
Saving to: 㧬ite-1.5.4-current.tar.bz2⍊
100%[===================================================================================================================>] 14,740,774  11.6M/s   in 1.2s

2012-09-13 15:56:42 (11.6 MB/s) - 㧬ite-1.5.4-current.tar.bz2⍊
/usr/local/src/freeswitch/build/getlib.sh: line 43: -c: command not found
/bin/tar: This does not look like a tar archive
/bin/tar: Exiting with failure status due to previous errors
/bin/bash: /usr/local/src/freeswitch/libs/flite-1.5.4-current/configure: No such file or directory
make[5]: *** [/usr/local/src/freeswitch/libs/flite-1.5.4-current/Makefile] Error 127
make[4]: *** [all] Error 1
make[3]: *** [mod_flite-all] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

 

 

List and description of the modules can be found here: http://wiki.freeswitch.org/wiki/Modules

 

 

Invoke the following commands to compile and create the binaries:

root@server:/usr/local/src/freeswitch# make && make install

 

Note:
"make install" does not overwrite existing configuration files in freeswitch/conf if a freeswitch.xml file already exists in conf.

 

Now for compilation and installation of sounds. There are IVR sound prompts and music on hold files that are optional but must be compiled and installed to run the sample IVR. There are four versions available:

    sounds-install moh-install (8 kHz)
    hd-sounds-install hd-moh-install (16 kHz)
    uhd-sounds-install uhd-moh-install (32 kHz)
    cd-sounds-install cd-moh-install (48 kHz)

The cd sounds are recommended since all the sampling rates are provided resulting in fewer problems. Invoke the following command:

root@server:/usr/local/src/freeswitch# make all cd-sounds-install cd-moh-install

Note:
If you want to know how to install FreeSWITCH on Debian with packages, take a look here:
http://codeghar.wordpress.com/2010/03/10/install-freeswitch-on-debian/
(after the packages are created, it is easier to install FreeSWITCH on more machines)

 

At last we create a symlink

root@server:/# ln -s /usr/local/freeswitch/bin/fs_cli /usr/local/bin/fs_cli

which will allow us connect to FreeSWITCH CLI (fs_cli) just by typing the command

root@server:/# fs_cli

If you want to leave CLI type in:

/bye

or
/exit
or
/quit

 

Finally we can run FreeSWITCH.

root@server:/usr/local/src/freeswitch# cd /usr/local/freeswitch/bin
root@server:/usr/local/freeswitch/bin# ./freeswitch

If you want to run FreeSWITCH on background, run it with option -nc

root@server:/usr/local/freeswitch/bin# ./freeswitch -nc

 

If we want to stop or restart FreeSWITCH here is how to do it from CLI:
fsctl shutdown [cancel|elegant|asap|restart|now]

    cancel    discontinue a previous shutdown request.
    elegant   wait for all traffic to stop; do not prevent new traffic.
    asap       wait for all traffic to stop; do not allow new traffic.
    restart    restart FreeSWITCH immediately following the shutdown.
    now        shutdown FreeSWITCH immediately.

 

When giving "elegant", "asap" or "now" it's also possible to give the restart command:
fsctl shutdown [elegant|asap|now] restart

 

4.    Kamailio configuration for interconnection

 

As there already is an WITH_VOICEMAIL directive and routing block present in Kamailio 3.3 default configuration file, we will keep it and use it to route calls that either not answered or busy or not answered in a specific time.

But we will need another block for routing to and from FreeSWITCH and conference (and anything else you would like to have, for example IVR, direct calling to VoiceMail or listening to VoiceMails from VoiceMail menu). Therefore we will name the second block simply as WITH_FREESWITCH. This block will accomodate all the other functions that will FreeSWITCH provide to us.

 

All of the following changes in part 4 (4.1,4.2 as well) are done in kamailio.cfg file located in /etc/kamailio/kamailio.cfg

 

 

Note:

Since there will be things added throughout this tutorial I will mark them with

 

for the beginning of the modified part

##<----MODIFIED---->## 

and for the end of the added or somehow modified part

##<////MODIFIED////>## 

just for better recognition

 

 

We will use two separate directives:
WITH_VOICEMAIL //which is already defined, just uncomment it
WITCH_FREESWITCH //we will need to add this for example after the WITH_VOICEMAIL directive

Example:

root@server:/# mcedit /etc/kamailio/kamailio.cfg

...
# *** To block 3XX redirect replies execute:
#     - define WITH_BLOCK3XX
#
# *** To enable VoiceMail routing execute:
#!define WITH_VOICEMAIL
#     - set the value of voicemail.srv_ip
#     - adjust the value of voicemail.srv_port
#
##<----MODIFIED---->##
# *** To enable other FreeSwitch routing like conferences and IVR execute:
#!define WITH_FREESWITCH
#     - set the value of freeswitch.srv_ip
#     - adjust the value of freeswitch.srv_port
##<////MODIFIED////>##
#
...

 

Then we will set the value of port and IP. In our case it will be the same IP and port of our FreeSWITCH. This is done in the
####### Custom Parameters #########
section.
As we will run the Kamailio and FreeSWITCH on the SAME machine, IP address will be the same as for Kamailio but port MUST be different. I have chosen port 5090.

 

Example

#!ifdef WITH_VOICEMAIL
# VoiceMail Routing on offline, busy or no answer
#
# - by default Voicemail server IP is empty to avoid misrouting
voicemail.srv_ip = "158.193.139.52" desc "VoiceMail IP Address"
voicemail.srv_port = "5090" desc "VoiceMail Port"
#!endif

#!ifdef WITH_FREESWITCH
# FreeSWITCH conference and IVR, everything except redirection to VoiceMail
#
freeswitch.srv_ip = "158.193.139.52" desc "Freeswitch IP Address"
freeswitch.srv_port = "5090" desc "Freeswitch Port"
#

 

We need to tell Kamailio to NOT authenticate any traffic coming from FreeSWITCH. This traffic is TRUSTED. We will make such a change in FreeSWITCH respectively later on in this tutorial.

So change the routing block AUTH:

 

Original routing block AUTH

# Authentication route
route[AUTH] {
#!ifdef WITH_AUTH

#!ifdef WITH_IPAUTH
    if((!is_method("REGISTER")) && allow_source_address())
    {
        # source IP allowed
        return;
    }
#!endif

    if (is_method("REGISTER") || from_uri==myself)
    {
        # authenticate requests
        if (!auth_check("$fd", "subscriber", "1")) {
            auth_challenge("$fd", "0");
            exit;
        }
        # user authenticated - remove auth header
        if(!is_method("REGISTER|PUBLISH"))
            consume_credentials();
    }
    # if caller is not local subscriber, then check if it calls
    # a local destination, otherwise deny, not an open relay here
    if (from_uri!=myself && uri!=myself)
    {
        sl_send_reply("403","Not relaying");
        exit;
    }

#!endif
    return;
}

 

Modified

# Authentication route
route[AUTH] {
#!ifdef WITH_AUTH

##<----MODIFIED---->##
#!ifdef WITH_FREESWITCH
    if(route(FROMFREESWITCH))
        return;
#!endif
##<////MODIFIED////>##

#!ifdef WITH_IPAUTH
    if((!is_method("REGISTER")) && allow_source_address())
    {
        # source IP allowed
        return;
    }
#!endif

    if (is_method("REGISTER") || from_uri==myself)
    {
        # authenticate requests
        if (!auth_check("$fd", "subscriber", "1")) {
            auth_challenge("$fd", "0");
            exit;
        }
        # user authenticated - remove auth header
        if(!is_method("REGISTER|PUBLISH"))
            consume_credentials();
    }
    # if caller is not local subscriber, then check if it calls
    # a local destination, otherwise deny, not an open relay here
    if (from_uri!=myself && uri!=myself)
    {
        sl_send_reply("403","Not relaying");
        exit;
    }

#!endif
    return;
}

 

Note that we have added a route block FROMFREESWITCH which is not defined yet. Now is the time to add it.
In addition we will also add block TOFREESWITCH for relaying all the calls to conferences, voicemails, ivr and so on to FreeSWITCH.
Just put this under the end of route[TOVOICEMAIL] section:

 

##<----MODIFIED---->##
# FreeSWITCH routing blocks

#!ifdef WITH_FREESWITCH
route[FROMFREESWITCH] {
    if($si== $sel(cfg_get.freeswitch.srv_ip)
            && $sp==$sel(cfg_get.freeswitch.srv_port))
        return 1;
    return -1;
}

route[TOFREESWITCH] {
    $du = "sip:" + $sel(cfg_get.freeswitch.srv_ip) + ":"
                + $sel(cfg_get.freeswitch.srv_port);
    route(RELAY);
}
#!endif
##<////MODIFIED////>##

 

Ok. This is pretty much it. With these configured we can move on to configuring VoiceMail and then some additional services.

 


4.1 Kamailio voicemail configuration

 

The nice thing about Kamailio 3.3 is that most of the work has been done for you in this version if you want to use only VoiceMail.

 

Original

# route to voicemail server
route[TOVOICEMAIL] {
#!ifdef WITH_VOICEMAIL
    if(!is_method("INVITE"))
        return;

    # check if VoiceMail server IP is defined
    if (strempty($sel(cfg_get.voicemail.srv_ip))) {
        xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
        return;
    }
    if($avp(oexten)==$null)
        return;

    $ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
                + ":" + $sel(cfg_get.voicemail.srv_port);
    route(RELAY);
    exit;
#!endif

We must slightly change (add a string "vmbox-" into variable $ru) TOVOICEMAIL routing block to this:

 

Modified

# route to voicemail server
route[TOVOICEMAIL] {
#!ifdef WITH_VOICEMAIL
    if(!is_method("INVITE"))
        return;

    # check if VoiceMail server IP is defined
    if (strempty($sel(cfg_get.voicemail.srv_ip))) {
        xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
        return;
    }
    if($avp(oexten)==$null)
        return;
    
    ##<----MODIFIED---->##
    $ru = "sip:" + "vmbox-" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
                + ":" + $sel(cfg_get.voicemail.srv_port);
    ##<////MODIFIED////>##
    route(RELAY);
    exit;
#!endif

    return;
}

The string vmbox- is not necessary if you make a different dialplan in FreeSWITCH. But it is not such a big thing and it really helps to differentiate traffic and ease debugging.

Everything should work just fine but we can make another small change. When calling an user which is not defined in Kamailio database, call is still forwarded to FreeSWITCH which responds with 404 Not Found. I don't like this concept as it is Kamailio which should reject such call. It is unnecessary to forward traffic, which we know would be rejected, to FreeSWITCH and we should stop it as soon as possible.

We will accomplish this by using one of the functions of uri_db module. The module is included in default installation of Kamailio but not loaded. So we need to load uri_db module first.

loadmodule "uri_db.so"

to the ####### Modules Section ########

This will allow us to use functions from this module.

Then we must slightly change routing block of LOCATION.

Just put route(TOVOICEMAIL) inside condition if (does_uri_exist()).

 

Original

# USER location service
route[LOCATION] {

#!ifdef WITH_SPEEDIAL
    # search for short dialing - 2-digit extension
    if($rU=~"^[0-9][0-9]$")
        if(sd_lookup("speed_dial"))
            route(SIPOUT);
#!endif

#!ifdef WITH_ALIASDB
    # search in DB-based aliases
    if(alias_db_lookup("dbaliases"))
        route(SIPOUT);
#!endif

    $avp(oexten) = $rU;
    if (!lookup("location")) {
        $var(rc) = $rc;
        route(TOVOICEMAIL);    
        t_newtran();
        switch ($var(rc)) {
            case -1:
            case -3:
                send_reply("404", "Not Found");
                exit;
            case -2:
                send_reply("405", "Method Not Allowed");
                exit;
        }
    }

    # when routing via usrloc, log the missed calls also
    if (is_method("INVITE"))
    {
        setflag(FLT_ACCMISSED);
    }
}

Modified

# USER location service
route[LOCATION] {

#!ifdef WITH_SPEEDIAL
    # search for short dialing - 2-digit extension
    if($rU=~"^[0-9][0-9]$")
        if(sd_lookup("speed_dial"))
            route(SIPOUT);
#!endif

#!ifdef WITH_ALIASDB
    # search in DB-based aliases
    if(alias_db_lookup("dbaliases"))
        route(SIPOUT);
#!endif

    $avp(oexten) = $rU;
    if (!lookup("location")) {
        $var(rc) = $rc;
        
        ##<----MODIFIED---->##
        if (does_uri_exist()) {
        route(TOVOICEMAIL);
        }
        ##<////MODIFIED////>##
        
        t_newtran();
        switch ($var(rc)) {
            case -1:
            case -3:
                send_reply("404", "Not Found");
                exit;
            case -2:
                send_reply("405", "Method Not Allowed");
                exit;
        }
    }

    # when routing via usrloc, log the missed calls also
    if (is_method("INVITE"))
    {
        setflag(FLT_ACCMISSED);
    }
}

Finished! This is all it takes for basic VoiceMail to function (after configuring FreeSWITCH of course). That means - if a user is busy, doesn't answer in 30s or reject the call it will be redirected to the voicemail.

But we also need to somehow listen to our voicemails...

This is how we do it. Find the route[SIPOUT] and modify it in following manner:

 

Original

# Routing to foreign domains
route[SIPOUT] {
    if (!uri==myself)
    {
        append_hf("P-hint: outbound\r\n");
        route(RELAY);
    }
}


 

Modified

# Routing to foreign domains
route[SIPOUT] {
    if (!uri==myself)
    {
        append_hf("P-hint: outbound\r\n");
        route(RELAY);
    }
    ##<----MODIFIED---->##
    #!ifdef WITH_FREESWITCH
    else
    {
    #Routing inside my domain

        #Routing to voicemail menu
        if ($tU=~"^9999$")
        {
            #voicemail menu
            xlog("L_NOTICE", " VoiceMail Menu Call");
            $rU = "vmmenu-" + $au;
            route(TOFREESWITCH);
        }
    }
    #!endif
    ##<////MODIFIED////>##
}

 

Additional configuration can be made to receive notifications that you have voicemail and even how many of them. Some of the clients support this (Jitsi for example). Since this operation is closely related to presence, we will add it there.

 

Note:

It is NOT needed to have the presence enabled for this function!

 

 

Original

# Presence server route
route[PRESENCE] {
    if(!is_method("PUBLISH|SUBSCRIBE"))
        return;

#!ifdef WITH_PRESENCE
    if (!t_newtran())
    {
        sl_reply_error();
        exit;
    };

    if(is_method("PUBLISH"))
    {
        handle_publish();
        t_release();
    }
    else
    if( is_method("SUBSCRIBE"))
    {
        handle_subscribe();
        t_release();
    }
    exit;
#!endif

    # if presence enabled, this part will not be executed
    if (is_method("PUBLISH") || $rU==$null)
    {
        sl_send_reply("404", "Not here");
        exit;
    }
    return;
}

 

Modified

# Presence server route
route[PRESENCE] {
    if(!is_method("PUBLISH|SUBSCRIBE"))
        return;

##<----MODIFIED---->##
#!ifdef WITH_FREESWITCH
    if (is_method("SUBSCRIBE") && $(hdr(Event))=="message-summary") {
    route(TOFREESWITCH);
    }
#!endif       
##<////MODIFIED////>##

#!ifdef WITH_PRESENCE
    if (!t_newtran())
    {
        sl_reply_error();
        exit;
    };

    if(is_method("PUBLISH"))
    {
        handle_publish();
        t_release();
    }
    else
    if( is_method("SUBSCRIBE"))
    {
        handle_subscribe();
        t_release();
    }
    exit;
#!endif

    # if presence enabled, this part will not be executed
    if (is_method("PUBLISH") || $rU==$null)
    {
        sl_send_reply("404", "Not here");
        exit;
    }
    return;
}

 

4.2 Kamailio Conference

 

Because we have already done all the hard work interconnecting with FreeSWITCH in the previous chapter, things are going to be really simple here.

 

So once again open the kamailio config file:

root@server:/# mcedit /etc/kamailio/kamailio.cfg

We will modify the route[SIPOUT] once more and change it just slightly. Just add the else if after the VoiceMail condition. We will put our conference routing there.

 

Original

# Routing to foreign domains
route[SIPOUT] {
    if (!uri==myself)
    {
        append_hf("P-hint: outbound\r\n");
        route(RELAY);
    }
    ##<----MODIFIED---->##
    #!ifdef WITH_FREESWITCH
    else
    {
    
    #Routing inside my domain
    
        #Routing to voicemail menu
        if ($tU=~"^9999$")
        {
            #voicemail menu
            xlog("L_NOTICE", " VoiceMail Menu Call");
            $rU = "vmmenu-" + $au;
            route(TOFREESWITCH);
        }
    }
    #!endif
    ##<////MODIFIED////>##
}

       
Modified

# Routing to foreign domains
route[SIPOUT] {
    if (!uri==myself)
    {
        append_hf("P-hint: outbound\r\n");
        route(RELAY);
    }
    ##<----MODIFIED---->##
    else
    {
    #!ifdef WITH_FREESWITCH
    #Routing inside my domain
    
        #Routing to voicemail menu
        if ($tU=~"^9999$")
        {
            #voicemail menu
            xlog("L_NOTICE", " VoiceMail Menu Call");
            $rU = "vmmenu-" + $au;
            route(TOFREESWITCH);
        }
        #Routing to conferences
        else if($rU=~"^3001$")
        {
            #conference
            xlog("L_NOTICE", " Conference Call");
            route(TOFREESWITCH);
        }
    }
    #!endif
    ##<////MODIFIED////>##
}

Okay that should do the trick! Now for the FreeSWITCH part.

And don't forget to restart Kamailio! If you made any typo, you will be warned during the restart. So go to the line that Kamailio complains about and repair it - then try to restart it again. Good luck!!!

root@server:/# /etc/init.d/kamailio restart

Congratulations, you have just add additional 90 lines to kamailio configuration file! :)

 

Note:

When debugging, messages from Kamailio logging (Kamailio logs) are stored in /var/log/syslog
This file is default logging file so there are other processes as well, don't be surprised when you see them.
This is very useful and try to use it whenever there is a problem. It really helps a lot. If you want to read just few rows from the end of the file (which are the most recent ones), try to use tail

 

root@server:/# tail /var/log/syslog

otherwise use some editor

root@server:/# mcedit /var/log/syslog

 

For more info about logging see this article:

http://nil.uniza.sk/sip/kamailio/kamailio-logging-how-debian-lenny

 

 

5. FreeSWITCH common config for interconnection

 

Be aware that there are many thing you can do with FreeSWITCH. These few explained here are merely a scratch of its possibilities. But once you learn to handle these and understand them, you can configure almost anything. This is the nice thing about FreeSWITCH as its configuration files are written completely in XML language rather than "custom made" such as those found in Asterisk.

Furthermore, FreeSWITCH is now well documented on its Wiki pages
http://wiki.freeswitch.org/wiki/
and in addition to that, you can visit their IRC channel which is always full of poeple, some of them even willing to help :).

We will try to leave intact as much of the original configuration as we can. There are a lot of demos and examples in each of them so keep your eyes and mind open - you might learn something ;-).

 

Note!!!:

There are lots of regular expressions. You should really get used to them. One big warning: when you will be adjusting configration to your need, don't forget that expression in brackets () are assigned to variables $1,$2... etc.

 

Example for some voicemail block:

<extension name="example">  
  <condition field="destination_number" expression="^vm-(1234)$">
   <action application="voicemail" data="default ${domain_name} $1"/>
  </condition>
</extension>

the content in the brackets, in this case 1234, will be then stored into variable $1 for further use in such block.

 

 

Note:

We will use marking of the modified parts similar to Kamailio version. But since this is XML, we will use typical XML syntax to comment.

 

beginning of modified part:

<!-- **MODIFIED** --> 

the end of the added or somehow modified part

<!-- //MODIFIED// -->

 

 

Look at the conf directory:

root@server:/# ls -all /usr/local/freeswitch/conf/

Here are stored all the configuration files. Take a look at the directory strucutre. Most of the configuration files are stored in autoload_configs. Main dialplan is stored in dialplan directory. Inside directory called "directory" there are user profiles files.

 

Remember earlier in this tutorial when we have said that traffic from FreeSWITCH will be trusted by Kamailio and vice versa? This is where we tell FreeSWITCH to trust Kamailio.
So turn off the authentication of calls - we will make sure in the next step by configuring ACL that nobody other will get in.

Now configuration of ACL.  As we have installed both proucts on one machine, the IP will be the same, just ports will differ.

root@server:/# mcedit /usr/local/freeswitch/conf/autoload_configs/acl.conf.xml

 

Original

    <list name="domains" default="deny">
      <!-- domain= is special it scans the domain from the directory to build the ACL -->
      <node type="allow" domain="$${domain}"/>
      <!-- use cidr= if you wish to allow ip ranges to this domains acl. -->
      <!-- <node type="allow" cidr="192.168.0.0/24"/> -->
    </list>

 

Modified

    <list name="domains" default="deny">
      <!-- domain= is special it scans the domain from the directory to build the ACL -->
      <node type="allow" domain="$${domain}"/>
      <!-- **MODIFIED** -->
      <node type="allow" cidr="158.193.139.52/32"/>
      <!-- //MODIFIED// -->
      <!-- use cidr= if you wish to allow ip ranges to this domains acl. -->
      <!-- <node type="allow" cidr="192.168.0.0/24"/> -->
    </list>

Then we need to direct the SIP traffic sent by Kamailio from public dialpan to default dialpan.
Edit usr/local/freeswitch/conf/dialplan/public.xml

root@server:/# mcedit usr/local/freeswitch/conf/dialplan/public.xml

and add following lines just behind the public_extensions section:

    <!-- **MODIFIED** -->
    <extension name="from_kamailio">
      <condition field="network_addr" expression="^158\.193\.139\.52$" />
      <condition field="destination_number" expression="^(.+)$">
        <action application="transfer" data="$1 XML default"/>
      </condition>
    </extension>
    <!-- //MODIFIED// -->

 

Since SIP in general uses the port 5060, we have configured Kamailio to bind that port, and since we are running both machines on the same machine with the same IP, FreeSWITCH will have listen on another port (5090, for TLS 5091).

Open the vars.xml file

root@server:/# mcedit /usr/local/freeswitch/conf/vars.xml

and find the section   <!-- Internal SIP Profile -->
Then change it in following manner (change the ports to 5090 and 5091 and disable authentication of calls - internal_auth_calls=false)

Original

  <!-- Internal SIP Profile -->
  <X-PRE-PROCESS cmd="set" data="internal_auth_calls=true"/>
  <X-PRE-PROCESS cmd="set" data="internal_sip_port=5060"/>
  <X-PRE-PROCESS cmd="set" data="internal_tls_port=5061"/>
  <X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false"/>
  <X-PRE-PROCESS cmd="set" data="internal_ssl_dir=$${base_dir}/conf/ssl"/>

 

Modified

  <!-- Internal SIP Profile -->
  <!-- **MODIFIED** -->
  <X-PRE-PROCESS cmd="set" data="internal_auth_calls=false"/>
  <X-PRE-PROCESS cmd="set" data="internal_sip_port=5090"/>
  <X-PRE-PROCESS cmd="set" data="internal_tls_port=5091"/>
  <!-- //MODIFIED// -->
  <X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false"/>
  <X-PRE-PROCESS cmd="set" data="internal_ssl_dir=$${base_dir}/conf/ssl"/>

 

Note:
We have changed the port for TLS to 5091, but TLS is not enabled by default. But it is not necessary as we can configure TLS in Kamailio. The traffic between Kamailio and FreeSWITCH doesn't have to be encrypted.

 

 

 

5.1 FreeSwitch Voicemail

 

Now we are going to edit the main dialplan section. This is where all the important stuff happens - such as redirecting calls to VoiceMail application or Conference app.

root@server:/# mcedit /usr/local/freeswitch/conf/dialplan/default.xml

Add the following after the "laugh break" section.

    <!-- **MODIFIED** -->
     <extension name="voicemail">
      <condition field="destination_number" expression="^vmbox-(.+)$">
        <action application="answer"/>
        <action application="voicemail" data="default ${domain_name} $1"/>
      </condition>
    </extension>
 
    <extension name="voicemailmenu">
      <condition field="destination_number" expression="^vmmenu-(.+)$">
        <action application="voicemail" data="check default ${domain_name} $1"/>
      </condition>
    </extension>
    <!-- //MODIFIED// -->

    
Ok, VoiceMail configuration is done! But we can't use it since we don't have user profiles defined. I will explain this after the conference part of tutorial.

 

5.2 FreeSWITCH Conference

 

Once again open the default dialplan but we won't change anything since it is all there. Just to know what is what - if you would like to change it later.

root@server:/# mcedit /usr/local/freeswitch/conf/dialplan/default.xml

Take a look at this section:

<!--
    start a dynamic conference with the settings of the "default" conference profile in conference.conf.xml
    -->                                                                                                                                                       
    <extension name="nb_conferences">
      <condition field="destination_number" expression="^(30\d{2})$">
    <action application="answer"/>
    <action application="conference" data="$1-${domain_name}@default"/>
      </condition>
    </extension>

    <extension name="wb_conferences">
      <condition field="destination_number" expression="^(31\d{2})$">
    <action application="answer"/>
    <action application="conference" data="$1-${domain_name}@wideband"/>
      </condition>
    </extension>

    <extension name="uwb_conferences">
      <condition field="destination_number" expression="^(32\d{2})$">
    <action application="answer"/>
    <action application="conference" data="$1-${domain_name}@ultrawideband"/>
      </condition>
    </extension>
    <!-- MONO 48kHz conferences -->
    <extension name="cdquality_conferences">
      <condition field="destination_number" expression="^(33\d{2})$">
    <action application="answer"/>
    <action application="conference" data="$1-${domain_name}@cdquality"/>
      </condition>
    </extension>

There are more types of conference defined, each in different quality of voice. The great thing about FreeSWITCH is that conferences are created dynamically when first user calls in, therefore NOT wasting memory on conferences that are currently empty.
Look at
/usr/local/freeswitch/conf/autoload_configs/conference.conf.xml

There is a lot of possibilities, for example using pin code when you want to enter conference. This can be very handy. Just add pin parameter to conference profile and there you go - your own private conference room with password.

<profiles>
    <!--If no profile is specified it will default to "default"-->
    <profile name="default">
    <param name="pin" value="123"/>
    ...
    </profile>
...
</profiles>

Pin is transmitted via DTMF signals in RTP stream as shown on callflow diagram. Therefore, only numeric pin is allowed.

Important!!! You have to reload the configuration files in order to make changes to running configuration of FreeSWITCH. But another nice thing about FreeSWITHC is that you don't have to actually restart whole FreeSWITCH after configuration change like you had to in Kamailio. Just connect to fs_cli and reload xml files:

root@server:/#fs_cli
freeswitch_internal> reloadxml
freeswitch_internal> /exit

 

5.3 FreeSWTICH - user profiles

 

One drawback of this interconnection is the need of defining the same users from Kamailio also in FreeSWITCH. I have read that you can overcome this by calling an application written in Lua (for example) that connects to Kamailio database and return the user profiles. But I have not tried it as I don't know LUA. Another way could be writing an application in php that will connect to the database and create profiles for FreeSWITCH dynamically. This is not so hard to do and I will try to write an article on that in future as manual creation of user profiles is not very effective, especially when dealing with many users.

User profiles are stored in:
/usr/local/freeswitch/conf/directory/default/

 

So here is the manual way. You must create an file in that directory. I will create profiles for pepe and jojo.

 

root@server:/# mcedit /usr/local/freeswitch/conf/directory/default/pepe.xml
<include>
  <user id="pepe" mailbox="2000"> <!--if id is numeric mailbox param is not necessary-->
    <!--
    ATTENTION PLEASE READ THIS... (I know you won't but you've been warrned)

    Let it be known that this user can register without a password but since we do not assign
    this user a user_context and we don't authenticate this user they will be put in context 'public'.

    This isn't a security issue as the endpoint would be put into the same context 'public' as the
    sofia profile that starts on 5080 by default. If you're paranoid just remove this file and
    remove the external profile also.

    If you're this paranoid you might wanna go buy some more tinfoil and disconnect from the internets.

    Cuz we all know the internets is for pr0n anyway.

    -->
    <params>
    <param name="vm-password" value="123"/>
    </params>
    <variables>
      <!--all variables here will be set on all inbound calls that originate from this user -->
      <!-- set these to take advantage of a dialplan localized to this user -->
      <variable name="accountcode" value="2000"/>
      <variable name="user_context" value="default"/>
      <variable name="effective_caller_id_name" value="pepe"/>
      <variable name="effective_caller_id_number" value="2000"/>
    </variables>
  </user>
</include>

 

Save the file and do another for jojo (with another vm-password for VoiceMail checking, and another mailbox value):

 

root@server:/# mcedit /usr/local/freeswitch/conf/directory/default/jojo.xml
<include>
  <user id="jojo" mailbox="2001"> <!--if id is numeric mailbox param is not necessary-->
    <!--
    ATTENTION PLEASE READ THIS... (I know you won't but you've been warrned)

    Let it be known that this user can register without a password but since we do not assign
    this user a user_context and we don't authenticate this user they will be put in context 'public'.

    This isn't a security issue as the endpoint would be put into the same context 'public' as the
    sofia profile that starts on 5080 by default. If you're paranoid just remove this file and
    remove the external profile also.

    If you're this paranoid you might wanna go buy some more tinfoil and disconnect from the internets.

    Cuz we all know the internets is for pr0n anyway.

    -->
    <params>
    <param name="vm-password" value="321"/>
    </params>
    <variables>
      <!--all variables here will be set on all inbound calls that originate from this user -->
      <!-- set these to take advantage of a dialplan localized to this user -->
      <variable name="accountcode" value="2001"/>
      <variable name="user_context" value="default"/>
      <variable name="effective_caller_id_name" value="jojo"/>
      <variable name="effective_caller_id_number" value="2001"/>
    </variables>
  </user>
</include>

 

Note:

Maybe you have spotted this line  <user id="jojo" mailbox="2001"> <!--if id is numeric mailbox param is not necessary-->
When you open another file like 1001.xml there is not an mailbox parameter. That is because number defined users (without alphabetical characters) have mailbox of the same number as their ID. Therefore it is not necessary to define this parameter.
The number is also used to represent user in another (not alphanumerical) way.

 

Note:

VoiceMail passwords MUST be defined as an numbers for the very same reason as for the conferences. Pin is transmitted in form of DTMF inside RTP.

 

Don't forget to reloadxml!

 

Congratulations, that's it!!!

 

6. Additional notes

 

Some great ways to debug SIP is to use nestat and ngrep. You can use netstat to find out which ports are open. Ngrep is a packet analyzer which is very useful.

 

Some hints how to use netstat:

 

root@server:/# netstat -tulpn

-t    tcp
-u   udp
-l    listening
-p   program name
-n   use addresses rather than DNS names
 

For the ngrep part.

You must first install ngrep:

root@server:/# apt-get install ngrep

Usage example:

root@server:/# ngrep -d eth0 -p -q -W byline port 5060 > outputfile.txt

-d                which interface will be used to capture data, usable if server has more than one interface

-p                does not put an interface into promiscuite mode (capture only our frames/packets)

-q                quiet mode, does not print other information, only application headers

-W byline      display output by lines

- port           listen on port (either source or destination)

>                 will save the output of the ngrep into file outputfile.txt

 

 

Note:

If you want to capture traffic between Kamailio and FreeSWITCH you ned to capture in on loopback interface, not ethernet!!!

 

 

Good luck with configuration and take care! If you have any questions, comments or you found some error feel free to post in as a comment.

 

AttachmentSize
File Original.zip20.04 KB
File Modified.zip22.38 KB
Groups: