kamailio, SIP

Building IM Server using Kamailio

Instant messaging (IM) is a type of online chat which offers real-time text transmission over the Internet. Like XMPP, we can also use SIP for real-time text transmission. The Kamailio PRESENCE module helps us built the same locally. We can convert a simple Kamailio server into a full fledged IM server.

By default, all the registered endpoints will send a “PUBLISH” requests to the Presence server with their status and Presence server stores the status. Also the endpoints will send a “SUBSCRIBE” to other user’s status. For each “SUBSCRIBE” request, the Presence server will sent a “NOTIFY” request back with status of the user. This is how our UserAgent keeps track of each user’s status. Below is simple flow diagram for the same.

Alt text

Setting up Kamailio

In my previous blog, i’ve explained how to install Kamailio from source. The only difference is we need to enable two more modules ”presence” and ”presence_xml”. If Kamailio is already installed, we need to add these two modules into modules.lst at the ”include_modules” line. Once the module names are added, we need to run ”make install” to install the two new modules. Once the module is added, we need to enable the module.

Add “#!define WITH_PRESENCE” into the “kamailio.cfg” file. Then check if there is route logic defined for the “PRESENCE” module. By default there is a PRESENCE route defined in the default “kamailio.cfg” file. If it’s not there below is the route logic. Also we need to add “*route(PRESENCE)” in the ”request_route**” section.

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

        if(is_method("SUBSCRIBE") && $hdr(Event)=="message-summary") {
                route(TOVOICEMAIL);
                # returns here if no voicemail server is configured
                sl_send_reply("404", "No voicemail service");
                exit;
        }

#!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)
        {
                xlog("@ 404 here 3");
                sl_send_reply("404", "Not here");
                exit;
        }
        return;
}

Now start the Kamailio server. Now we need to add some users. For that we can use ”kamctl” binary.

$ kamctl add user1@192.168.56.100 user1

$ kamctl add user2@192.168.56.100 user2

Let’s go ahead and test the settings. For testing we need some IM clients. In my testing, i’ve used Jitsi and adium IM clients. Once the accounts are configured on the clients, it’s better to start a packet capture using wireshark, so that we can see these PUBLISH, SUBSCRIBE and NOTIFY requests between the clients and the Kamailio server. If you are using Adium, go to account options and check the “Publish Status to Everyone” so that it will start sending PUBLISH request to the Kamailio server. Now add the accounts to the Contact lists on the IM clients and then we will be able to see the users status (ONline/OFFline). Now we can start the chat conversation between the user’s.

Standard
FreeSwitch, kamailio, SIP

Integrating Kamailio with FreeSwitch

Kamailio aka OpenSER is one of the most powerfull and popular Open Source SIP server. It can be used as SIP Proxy/ Registrar/ LB/ Router etc. It also provides a lot of features like WebSocket support for WebRTC, ; SIMPLE instant messaging and presence with embedded XCAP server and MSRP relay,IMS extensions,ENUM and offcourse AAA (accounting, authentication and authorization) also. Kamailio is a modular system, ie, it has lot of modules which corresponds to particular functions. These modules can be easily installed and can be used easily in Kamailio. In this blog i’m going to use Kamailio as a proxy server. All the user’s are created in the Kamailio and FreeSwitch will be acting as a relay server for outbound calls. So Kamailio performs authentication and all the outbound calls wil be relayed to FreeSwitch.

Installing Kamailio

Lets download the latest version of Kamailio, now it’s 4.1

$ wget http://www.Kamailio.org/pub/Kamailio/latest/src/Kamailio-4.1.1_src.tar.gz

$ tar xvzf Kamailio-4.1.1_src.tar.gz && cd Kamailio-4.1.1

Before we start the build we need to install the basic dependencies.

$ apt-get install gcc flex bison libmysqlclient-dev make libxml2-dev libssl-dev

Now we have the dependencies installed, we can go ahead with the build.

$ make cfg      # generates config files for build system

Now open modules.lst and add the modules to be installed in ”include_modules” section. In my case i’m going to use MySQL backend so it will be ”include_modules= db_mysql” and then we can run the ”make all”. The other way is we can mention the modules directly while running the “make” rather editing the modules.lst file.

$ make include_modules="db_mysql" cfg

Now we can install,

$ make install

The above command will install Kamailio to our system. There are four main binaries for Kamailio,

Kamailio - Kamailio SIP server
kamdbctl - script to create and manage the Databases
kamctl - script to manage and control Kamailio SIP server
kamcmd - CLI - command line tool to interface with Kamailio SIP server

There is also one configuration file called “Kamailio.cfg” which is available by default at /usr/local/etc/Kamailio/Kamailio.cfg

Let’s go ahead with setting up MySQL server for Kamailio.

$ apt-get install mysql-server

Now edit the /usr/local/etc/Kamailio/kamctlrc Locate DBENGINE variable and set it to MYSQL by making ”DBENGINE=MYSQL”. Now we can use the “kamdbctl” binary to craete the default tables and users.

$ /usr/local/sbin/kamdbctl create

The script will add two users in MySQL:

  • Kamailio – (with default password ‘Kamailiorw’) – user which has full access rights to ‘Kamailio’ database

  • Kamailioro – (with default password ‘Kamailioro’) – user which has read-only access rights to ‘Kamailio’ database

There is a sample init.d script available along with Kamailio, which we can use it. We need to copy the sample init.d file to our system’s init.d folder. And the same for the system default file.

$ cp /usr/local/src/Kamailio-4.1.1/pkg/Kamailio/deb/precise/Kamailio.init /etc/init.d/Kamailio

$ cp /usr/local/src/Kamailio-4.1.1/pkg/Kamailio/deb/precise/Kamailio.default /etc/default/Kamailio

$ chmod 755 /etc/init.d/Kamailio 

Edit the new init file and modify the $DAEMON and $CFGFILE values.

DAEMON=/usr/local/sbin/Kamailio
CFGFILE=/usr/local/etc/Kamailio/Kamailio.cfg

$ mkdir -p /var/run/Kamailio    # Directory for the pid file

Default setting is to run Kamailio as user ”Kamailio” and group ”Kamailio”. For that we need to create the user:

$ adduser --quiet --system --group --disabled-password \
      --shell /bin/false --gecos "Kamailio" \
      --home /var/run/Kamailio Kamailio

$ chown Kamailio:Kamailio /var/run/Kamailio

Setting up Kamailio

All the Kamailio configurations are mentioned in only one single file /usr/local/etc/Kamailio/Kamailio.cfg. All the logics are defined in this file, and Kamailio blindly executes this logics and perform the actions. It’s very important that the logics defined in the config should suit to our VOIP platform requirement.

First we need to enable the modules and the necessary features, so add the below lines in the Kamailio.cfg

#!define WITH_MYSQL
#!define WITH_AUTH
#!define WITH_USRLOCDB
#!define WITH_FREESWITCH

We need to define the FreeSwitch server IP and port, for that we can add the below parameters in the “Custom Parameters” section.

#!ifdef WITH_FREESWITCH
freeswitch.bindip = "192.168.56.100" desc "FreeSWITCH IP Address"
freeswitch.bindport = "5090" desc "FreeSWITCH Port"
#!endif

Now we can go ahead to the ”request_route” section which performs the routing logic. Here i’m going to add two more routing logic for the FreeSwitch relay. After the ”request_route” section, we can see the definition for each routing options. Below that we need to add our new route definitions.

route[FSDISPATCH] {
        # dial number selection
        route(FSRELAY);
        exit;
}

route[FSRELAY] {
        $du = "sip:" + $sel(cfg_get.freeswitch.bindip) + ":" + $sel(cfg_get.freeswitch.bindport);
        if($var(newbranch)==1)
        {
                append_branch();
                $var(newbranch) = 0;
        }
        route(RELAY);
        exit;
}

By default, all the routes mentioned in the “request_route” will be executed line by line. There is a default route called ”Location”, which splits the user part from the request URI and verifies if the user exists in the location table. But when we dial an outside number/user, this location check will fail, so i’m going to add a condition which checks if the user in the request URI contains a number with a length 9-15 will be relayed to the FreeSwitch. Again this is just a simple condition, we can create a more complex condition, like check the domain part, if the domain part contains a domain which doesnot belong to our Domain list, we can either decline the request, or we can relay to FreeSwitch or we can make DNS query and we can make Kamailio to process the request to that domain’s Proxy server. Like this we can define our own conditions in the config file, and Kamailio will execute it line by line.

I’m going to add my check condition on the ”LOCATION” route definition.

route[LOCATION] {

    #!ifdef WITH_SPEEDDIAL
        # search for short dialing - 2-digit extension
        if($rU=~"^[0-9][0-9]$")
                if(sd_lookup("speed_dial"))
                        route(SIPOUT);
    #!endif
        if($rU=~"^[0-9]{9,15}$")        # checking for numbers in the Request URI
                route(FSDISPATCH);
    #!ifdef WITH_ALIASDB
        # search in DB-based aliases
        if(alias_db_lookup("dbaliases"))
                route(SIPOUT);
    #!endif
        $avp(oexten) = $rU;
        if (!lookup("location")) {
                xlog("L_INFO", "CALL $rm $ci lookup here\n");
                xlog("L_INFO", "$fU@$fd - Lookup contact location for $rm\n");
                xlog("L_INFO", "rc is $var(rc)");
                switch ($rc) {
                        case -1:
                        case -3:
                                xlog("L_ERR", "$fU@$fd - No contact found\n");
                                send_reply("404", "Not Found here");
                                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);
        }
        xlog("L_INFO", "CALL $rm $ci relay\n");
        xlog("L_INFO", "$fU@$fd - Relaying $rm\n");
            route(RELAY);
        exit;
}

So now all the calls coming with numbers of length 9-15 in the Request URI will be relayed to the FreeSwitch, and FreeSwitch will process the call based on the DialPlan configured in the FreeSwitch. Since i’m going to use IP authentication, i need to whitelist the Kamailio ip in “acl_conf.xml” file in the FreeSwitch autload conf directory, so that FreeSwitch will accept the invites from Kamailio. Again i’m not defining any Voicemail options here. If we have a Voice mail server, then we can create another route option and when the caller doesn’t pick the call we can route the call to the Voice Mail server.
For example the below condition will route the failures to FreeSwitch Voice Mailbox.

if(is_method("INVITE"))
        {
            # in case of failure - re-route to FreeSWITCH VoiceMail
            t_on_failure("FAIL_FSVBOX");        # where FSVBOX is a route definition
        }

Kamailio has a lot of modules which really comes in handy. For example we can use LDAP module to use LDAP as a backend. There is a PRESENCE module which helps us to setup an Instant Messaging server using Kamailio. I’ll be writing a blog on how to use Kamailio as an IM server soon. One of the main advantage of Kamailio over OpenSIP is the WebSocket support. This just a basic configuration, but we can design much complex system using Kamailio. We can even remove the default route logics, and we can use our own routing logics. Kamailio doesnot depend on default routing logics, it blindly reads the route and executes it for each incoming connections.

Standard