Table of Contents
List of Examples
sipmsg
parametermsrp
usagemsrp_reply
usagemsrp_is_request
usagemsrp_is_reply
usagemsrp_set_dst
usagemsrp_relay_flags
usagemsrp_reply_flags
usageTable of Contents
This module provides a MSRP routing engine, a.k.a. MSRP relay. MSRP (Message Session Relay Protocol) is defined by RFC4975, and the extensions for an MSRP relay are covered in RFC4976.
A typical use of MSRP is instant messaging sessions initiated via SIP. Unlike page-mode instant messaging, which is done via the SIP MESSAGE request, MSRP uses a different communication channel which is negotiated via INVITE-200 OK-ACK.
However, MSRP is still a text-based protocol. It uses several routing mechanisms similar to what exists in SIP. Furthermore, MSRP requires TCP, and recommends TLS for confidentiality and security. In light of the scalability and performance of Kamailio in handling TCP/TLS, this module reuses Kamailio's core framework to offer MSRP routing capabilities. Along with embedded Presence and XCAP servers, Kamailio offers now a complete solution for SIP beyond VoIP.
One of the main benefits of this module is the ability to reuse all the other extensions that exist in the SIP server, including accounting, authentication, authorization to database connectors, security and DoS attack protections.
Kamailio can handle SIP and MSRP traffic received on the same port; the appropriate configuration file block being executed based on the type of message. Therefore, you can use Kamailio as a stand-alone MSRP relay or you can have an instance handling both SIP and MSRP. Another option is to configure Kamailio to listen on multiple ports, some of them for SIP and others for MSRP.
If 1, the module will build a SIP message from MSRP frame headers, providing it to event_route[msrp:frame-in]. All the config file functions (apart from SIP request relay) that can be used in a request route block can be used in msrp event_route.
Default value is '1'.
Relay MSRP frame according to the To-Path. This function has to be executed for each MSRP request or reply that has to be forwarded. Note that due to nature of MSRP transport layer, which is reliable (TCP/TLS), there is no retransmission of MSRP frames.
This function can be used in ANY_ROUTE.
Send a reply for the current MSRP request, adding optional headers.
The parameter can be a pseudo-variable.
This function can be used in ANY_ROUTE.
Example 1.3. msrp_reply
usage
... event_route[msrp:frame-in] { msrp_reply("403", "Not allowed"); } ...
Return true if the MSRP frame is a request.
This function can be used in ANY_ROUTE.
Example 1.4. msrp_is_request
usage
... event_route[msrp:frame-in] { if(msrp_is_request()) { msrp_relay(); exit; } } ...
Return true if the MSRP frame is a reply.
This function can be used in ANY_ROUTE.
Example 1.5. msrp_is_reply
usage
... event_route[msrp:frame-in] { if(msrp_is_reply()) { msrp_relay(); exit; } } ...
Set destination attributes: addr - target address as MSRP URI; sock - local socket to be used (format 'proto:ip:port').
The parameter can be a pseudo-variable.
This function can be used in ANY_ROUTE.
Example 1.6. msrp_set_dst
usage
... event_route[msrp:frame-in] { ... msrp_set_dst("msrp://127.0.0.1:8000", "tcp:127.0.0.1:5060"); ... } ...
Set transport layer sending flags for forwarding current MSRP frame; flags - a bitmask of flags - 1 (don't create a new connection), 2 (close connection after send).
The parameter can be a pseudo-variable.
This function can be used in ANY_ROUTE.
Example 1.7. msrp_relay_flags
usage
... event_route[msrp:frame-in] { ... msrp_relay_flags("1"); ... } ...
Set transport layer sending flags for replies to the current MSRP frame; flags - a bitmask of flags - 1 (don't create a new connection), 2 (close connection after send).
The parameter can be a pseudo-variable.
This function can be used in ANY_ROUTE.
Example 1.8. msrp_reply_flags
usage
... event_route[msrp:frame-in] { ... msrp_reply_flags("1"); ... } ...
The module exports a pseudo-variable class, $msrp(key), to access the MSRP frame (e.g. first line attributes, body, all frame content).
The module exports a transformations class, 'msrpuri', to allow access attributes of a MSRP URI.
These are documented in the appropriate Wiki pages hosted on the project web site.
For each MSRP frame received from the network, the module executes event_route[msrp:frame-in] block in the config file.
When 'sipmsg' parameter is set to 1 (which is default), the module internally builds a SIP request from the MSRP frame and exposes it to the config file interpreter. This way, all the functions that are valid for SIP requests can be used safely in event_route[msrp:frame-in].
To build the SIP request, the module takes the first line and the headers from an MSRP message and appends them to a static buffer. The next two examples show an MSRP frame and the resulting SIP request.
... MSRP 6aef SEND To-Path: msrps://a.example.org:9000/kjfjan;tcp \ msrps://b.example.net:9000/aeiug;tcp \ msrps://bob.example.net:8145/foo;tcp From-Path: msrps://alice.example.org:7965/bar;tcp Success-Report: yes Byte-Range: 1-*/* Message-ID: 87652 Content-Type: text/plain Hi Bob, I'm about to send you a photo. -------6aef$ ...
... MSRP sip:a@127.0.0.1 SIP/2.0 Via: SIP/2.0/UDP 127.0.0.1:9;branch=z9hG4bKa From: <b@127.0.0.1>;tag=a To: <a@127.0.0.1> Call-ID: a CSeq: 1 MSRP Content-Length: 0 MSRP-First-Line: MSRP 6aef SEND To-Path: msrps://a.example.org:9000/kjfjan;tcp \ msrps://b.example.net:9000/aeiug;tcp \ msrps://bob.example.net:8145/foo;tcp From-Path: msrps://alice.example.org:7965/bar;tcp Success-Report: yes Byte-Range: 1-*/* Message-ID: 87652 Content-Type: text/plain ...
Note that MSRP does not permit line folding. A "\" in the examples shows a line continuation due to the limitations of line length of this document. Neither the backslash nor the extra CRLF is included in the actual request or response.
As can be observed, the MSRP frame content starts with the body of the 'MSRP-First-Line:' header. Using static content to get to a valid SIP request is a perfect trade-off for performance.
Besides the option to access parts of MSRP frame via an internally-built SIP message, the module exports a new pseudo-variable class $msrp(key) which returns attributes from the MSRP frame. There is also a new transformation, {msrpuri.key}, to get access to parts of an MSRP URI. See the appropriate Wiki pages on the project's web site for full details about new pseudo-variable and transformation classes.
Next is an example of configuration file with the routing block for MSRP frames. In this config, the SIP traffic is rejected.
Example 1.9. Event Route
... #!KAMAILIO debug=2 memdbg=5 memlog=5 children=4 log_stderror=yes auto_aliases=no tcp_accept_no_cl=yes tcp_connection_lifetime=1810 listen=127.0.0.1:5060 mpath="modules_k/:modules/" loadmodule "sl.so" loadmodule "kex.so" loadmodule "mi_fifo.so" loadmodule "ctl.so" loadmodule "msrp.so" loadmodule "pv.so" loadmodule "auth.so" loadmodule "cfgutils.so" loadmodule "htable.so" loadmodule "xlog.so" # ----- mi_fifo params ----- modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo") modparam("auth", "nonce_count", 1) modparam("auth", "qop", "auth") #!substdef "!MSRP_MIN_EXPIRES!1800!g" #!substdef "!MSRP_MAX_EXPIRES!3600!g" modparam("htable", "htable", "msrp=>size=8;autoexpire=MSRP_MAX_EXPIRES;") request_route { sl_send_reply("403", "No SIP Here"); exit; } reply_route { drop; } event_route[msrp:frame-in] { xdbg("============#[[$msrp(method)]]===========\n"); xdbg("============*[[$si:$sp]]\n"); xdbg("============ crthop: [$msrp(crthop)]\n"); xdbg("============ prevhop: [$msrp(prevhop)]\n"); xdbg("============ nexthop: [$msrp(nexthop)]\n"); xdbg("============ firsthop: [$msrp(firsthop)]\n"); xdbg("============ lasthop: [$msrp(lasthop)]\n"); xdbg("============ prevhops: [$msrp(prevhops)]\n"); xdbg("============ nexthops: [$msrp(nexthops)]\n"); xdbg("============ srcaddr: [$msrp(srcaddr)]\n"); xdbg("============ srcsock: [$msrp(srcsock)]\n"); xdbg("============ sessid: [$msrp(sessid)]\n"); msrp_reply_flags("1"); if(msrp_is_reply()) { msrp_relay(); } else if($msrp(method)=="AUTH") { if($msrp(nexthops)>0) { msrp_relay(); exit; } # frame for local server - send Use-Path # -- passwd can be loaded from DB based on $au $var(passwd) = "xyz123"; if(!pv_www_authenticate("myrealm", "$var(passwd)", "0", "$msrp(method)")) { if(auth_get_www_authenticate("myrealm", "1", "$var(wauth)")) { msrp_reply("401", "Unauthorized", "$var(wauth)"); } else { msrp_reply("500", "Server Error"); } exit; } if ($hdr(Expires) != $null) { $var(expires) = (int) $hdr(Expires); if ($var(expires) < MSRP_MIN_EXPIRES) { msrp_reply("423", "Interval Out-of-Bounds", "Min-Expires: MSRP_MIN_EXPIRES\r\n"); exit; } else { msrp_reply("423", "Interval Out-of-Bounds", "Max-Expires: MSRP_MAX_EXPIRES\r\n"); exit; } } else $var(expires) = MSRP_MAX_EXPIRES; $var(cnt) = $var(cnt) + 1; pv_printf("$var(sessid)", "s.$(pp).$(var(cnt)).$(RANDOM)"); $sht(msrp=>$var(sessid)::srcaddr) = $msrp(srcaddr); $sht(msrp=>$var(sessid)::srcsock) = $msrp(srcsock); $shtex(msrp=>$var(sessid)) = $var(expires) + 5; # - Use-Path: the MSRP address for server + session id $var(headers) = "Use-Path: msrp://127.0.0.1:5060/" + $var(sessid) + ";tcp\r\n" + "Expires: " + $var(expires) + "\r\n"; msrp_reply("200", "OK", "$var(headers)"); } else if($msrp(method)=="SEND" || $msrp(method)=="REPORT") { if($msrp(nexthops)>1) { if ($msrp(method)!="REPORT") { msrp_reply("200", "OK"); } msrp_relay(); exit; } $var(sessid) = $msrp(sessid); if($sht(msrp=>$var(sessid)::srcaddr) == $null) { # one more hop, but we don't have address in htable if ($msrp(method)!="REPORT") { msrp_reply("481", "Session-does-not-exist"); } exit; } else if($msrp(method)!="REPORT") { msrp_reply("200", "OK"); } msrp_relay_flags("1"); msrp_set_dst("$sht(msrp=>$var(sessid)::srcaddr)", "$sht(msrp=>$var(sessid)::srcsock)"); msrp_relay(); } else { msrp_reply("501", "Request-method-not-understood"); } } ...