Kamailio Bytes – xHTTP

Generally Kamailio functions as a SIP router, receiving SIP messages and then responding with SIP.

Sometimes we may have a use case where we need to interact with Kamailio but with a request that isn’t a SIP message.

You’ve got a motion activated IP Camera, and you want to send an alert to a SIP phone if it detects motion.

The problem? The IP camera doesn’t speak SIP. but it can send an HTTP request if it detects motion.

Enter xHTTP!

We’ll get Kamailio to listen for HTTP requests and send an instant message using method “MESSAGE” to a SIP phone to let someone know there’s been motion.

Use Case

The sending of the message is fairly straight forward, we’ll use the UAC module to perform a uac_req_send() and put it in it’s own routing block called “SEND_MESSAGE”, which we’ll add after the request_route{} block:

route[SEND_MESSAGE]{
        $uac_req(method)="MESSAGE";
        $uac_req(ruri)="sip:10.0.1.5:5060";
        $uac_req(furi)="sip:nickvsnetworking.com";
        $uac_req(turi)="sip:thisphone";
        $uac_req(callid)=$(mb{s.md5});
        $uac_req(hdrs)="Subject: Test\r\n";
        $uac_req(hdrs)=$uac_req(hdrs) + "Content-Type: text/plain\r\n";
        $uac_req(body)="Camera detected movement!";
        uac_req_send();

}

(I talk a bit more about the UAC module and this process in the post on UAC basics and SIP instant messaging on my post on SIMPLE)

Now when we call the route ROUTE(SEND_MESSAGE); the SIP phone at 10.0.1.5 will get a message that pops up on the screen.

So the next step is getting something other than a SIP request to call our SEND_MESSAGE route.

For this we’ll use the xHTTP module, a barebones HTTP server for Kamailio.

It’s requirements are pretty easy, sl_reply needs to be loaded before xHTTP, and you may need to add tcp_accept_no_cl=yes to your core settings (aka Global Parameters at the top).

The two lines we’ll need to load and configure the module are equally as easy:

loadmodule "xhttp.so"
modparam("xhttp", "url_match", "^/sip/")

The url_match modparam just means that any HTTP request has to start with /sip/ in the URL.

Finally we’ll define an event route to handle any xHTTP requests after our request_route{} block:

event_route[xhttp:request] {
        xlog("Recieved HTTP request with request $hu");                         #Write to log the URL of http request.
        xhttp_reply("200", "OK", "text/html", "<html><body>OK</body></html>");  #Send HTTP response
}

Now if we restart Kamailio, and open a browser pointed to the IP of your Kamailio server, port 5060 /sip/Hello World you should get a response of “OK” in the browser:

And if we check syslog we should also see:

Jul 27 00:32:31 nick-voice-dev7 /usr/sbin/kamailio[111271]: ERROR: : Recieved HTTP request with request /sip/Hello%20world!</p>

Perfect, we now have an HTTP server in Kamailio, and we can read the HTTP request URL into a variable.

Next up we can call the route(SEND_MESSAGE) and our SIP phone will get a message

event_route[xhttp:request] {
        xlog("Recieved HTTP request with request $hu");                         #Write to log the URL of http request.
        xhttp_reply("200", "OK", "text/html", "<html><body>OK</body></html>");  #Send HTTP response
        route(SEND_MESSAGE);
}

Presto! When we call that URL (http://your-kamailio-ip:5060/sip/whatever) a SIP SIMPLE MESSAGE is sent.

But why stop there, let’s make this a bit prettier, we’ll set the message to equal the part of the HTTP request after the /sip/ so we can send custom data, replace the %20 with underscores and send it:

route[SEND_MESSAGE]{
        $uac_req(method)="MESSAGE";
        $uac_req(ruri)="sip:192.168.3.227:5060";
        $uac_req(furi)="sip:nickvsnetworking.com";
        $uac_req(turi)="sip:thisphone";
        $uac_req(callid)=$(mb{s.md5});
        $uac_req(hdrs)="Subject: Test\r\n";
        $uac_req(hdrs)=$uac_req(hdrs) + "Content-Type: text/plain\r\n";
        $uac_req(body)=$var(message);
        uac_req_send();

}

event_route[xhttp:request] {
        xlog("Recieved HTTP request with request $hu");                         #Write to log the URL of http request.
        $var(message) = $hu;                                                    #Set variable $var(message) to equal the URL of http request.
        $var(message) = $(var(message){s.substr,5,0});                          #Cut off first 5 chars to exclude the /sip/ prefix from the HTTP request
        $var(message) = $(var(message){s.replace,%20,_});                       #Replace %20 of space in HTTP request with Underscore _ for spaces
        xlog("var message is $var(message)");                                   #Write to log the http request minus the /sip/ prefix
        xhttp_reply("200", "OK", "text/html", "<html><body>OK</body></html>");  #Send HTTP response
        route(SEND_MESSAGE);                                                    #Call the SEND_OPTIONS route (See above)
}

We’ll also set our core settings / gloabal parameters to listen on TCP port 80 as well as UDP port 5060 so we don’t need to specify the port in the browser:

listen=tcp:0.0.0.0:80
listen=udp:0.0.0.0:5060

Now when we point our browser to http://your-kamailio-ip/sip/Mr.%20Watson,%20come%20here,%20I%20want%20to%20see%20you.

We’ll get this on our SIP endpoint:

Beautiful!

Hopefully by now you can see some of the cool things you can do with the HTTP module. Kamailio is so much more than just a SIP router / proxy, and these external modules being able to interface with it give you so many options.

Want to offer webhooks to customers to control their calls? xHTTP can do that!

Want to play a message to all users on calls announcing to them lunch is ready? RTPengine and xHTTP can do that too!

Here’s a copy of my running code for your reference.

Leave a Reply

Your email address will not be published. Required fields are marked *