src/modules/msrp/README
19e138b5
 MSRP Module
 
 Daniel-Constantin Mierla
 
    <miconda@gmail.com>
 
 Edited by
 
 Daniel-Constantin Mierla
 
    <miconda@gmail.com>
 
ad54eb1c
 Alex Balashov
 
    <abalashov@evaristesys.com>
 
9cb2a163
    Copyright © 2012 asipto.com
19e138b5
      __________________________________________________________________
 
    Table of Contents
 
    1. Admin Guide
 
         1. Overview
         2. Dependencies
 
               2.1. Kamailio Modules
               2.2. External Libraries or Applications
 
         3. Parameters
 
               3.1. sipmsg (int)
ea3cacb1
               3.2. cmap_size (int)
               3.3. timer_interval (int)
               3.4. auth_min_expires (int)
               3.5. auth_max_expires (int)
830af85c
               3.6. use_path_addr (str)
a69aab1c
               3.7. event_callback (str)
19e138b5
 
         4. Functions
 
               4.1. msrp_relay()
               4.2. msrp_reply(code, text [, hdrs])
               4.3. msrp_is_request()
               4.4. msrp_is_reply()
               4.5. msrp_set_dst(addr, sock)
               4.6. msrp_relay_flags(flags)
               4.7. msrp_reply_flags(flags)
ea3cacb1
               4.8. msrp_cmap_save()
               4.9. msrp_cmap_lookup()
19e138b5
 
         5. Pseudo Variables
bc8b005b
         6. RPC Commands
 
               6.1. msrp.cmaplist
 
         7. Event Routes
         8. Usage
19e138b5
 
    List of Examples
 
    1.1. Set sipmsg parameter
ea3cacb1
    1.2. Set cmap_size parameter
    1.3. Set timer_interval parameter
    1.4. Set auth_min_expires parameter
    1.5. Set auth_max_expires parameter
830af85c
    1.6. Set use_path_addr parameter
a69aab1c
    1.7. Set event_callback parameter
    1.8. msrp_relay usage
    1.9. msrp_reply usage
    1.10. msrp_is_request usage
    1.11. msrp_is_reply usage
    1.12. msrp_set_dst usage
    1.13. msrp_relay_flags usage
    1.14. msrp_reply_flags usage
    1.15. msrp_cmap_save usage
    1.16. msrp_cmap_lookup usage
    1.17. Event Route (using htable for MSRP connection tracking)
    1.18. Event Route (using msrp_cmap_ functions for connection tracking)
19e138b5
 
 Chapter 1. Admin Guide
 
    Table of Contents
 
    1. Overview
    2. Dependencies
 
         2.1. Kamailio Modules
         2.2. External Libraries or Applications
 
    3. Parameters
 
         3.1. sipmsg (int)
ea3cacb1
         3.2. cmap_size (int)
         3.3. timer_interval (int)
         3.4. auth_min_expires (int)
         3.5. auth_max_expires (int)
830af85c
         3.6. use_path_addr (str)
a69aab1c
         3.7. event_callback (str)
19e138b5
 
    4. Functions
 
         4.1. msrp_relay()
         4.2. msrp_reply(code, text [, hdrs])
         4.3. msrp_is_request()
         4.4. msrp_is_reply()
         4.5. msrp_set_dst(addr, sock)
         4.6. msrp_relay_flags(flags)
         4.7. msrp_reply_flags(flags)
ea3cacb1
         4.8. msrp_cmap_save()
         4.9. msrp_cmap_lookup()
19e138b5
 
    5. Pseudo Variables
bc8b005b
    6. RPC Commands
 
         6.1. msrp.cmaplist
 
    7. Event Routes
    8. Usage
19e138b5
 
 1. Overview
 
0c95e9cd
    This module provides a MSRP routing engine, a.k.a. MSRP relay. MSRP
ad54eb1c
    (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
3ce2efce
    mechanisms similar to what exists in SIP. Furthermore, MSRP requires
ad54eb1c
    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
dfcdc7b8
    now offers a complete solution for SIP beyond VoIP.
ad54eb1c
 
    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,
19e138b5
    authentication, authorization to database connectors, security and DoS
ad54eb1c
    attack protections.
19e138b5
 
ad54eb1c
    Kamailio can handle SIP and MSRP traffic received on the same port; the
0c95e9cd
    appropriate configuration file block being executed based on the type
ad54eb1c
    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.
0c95e9cd
 
19e138b5
 2. Dependencies
 
    2.1. Kamailio Modules
    2.2. External Libraries or Applications
 
 2.1. Kamailio Modules
 
    The following modules must be loaded before this module:
      * None.
 
6dc38a36
    The following modules are required to make proper use of this module:
      * tls.
 
19e138b5
 2.2. External Libraries or Applications
 
    The following libraries or applications must be installed before
    running Kamailio with this module loaded:
      * None
 
 3. Parameters
 
    3.1. sipmsg (int)
ea3cacb1
    3.2. cmap_size (int)
    3.3. timer_interval (int)
    3.4. auth_min_expires (int)
    3.5. auth_max_expires (int)
830af85c
    3.6. use_path_addr (str)
a69aab1c
    3.7. event_callback (str)
19e138b5
 
 3.1. sipmsg (int)
 
dfcdc7b8
    If set to 1, the module will build a SIP message from MSRP frame
9cb2a163
    headers, providing it to “event_route[msrp:frame-in]”. All the config
dfcdc7b8
    file functions (apart from SIP request relay) that can be used in a
    request route block can be used in the MSRP event_route.
19e138b5
 
    Default value is '1'.
 
    Example 1.1. Set sipmsg parameter
 ...
 modparam("msrp", "sipmsg", 1)
 ...
 
ea3cacb1
 3.2. cmap_size (int)
 
    The size of connection map table, to be computed as power of 2 (e.g.,
    if the value is 4, then the number of slots in map table is 2^4 = 16).
 
    Default value is '0' (no internal map table to be used).
 
    Example 1.2. Set cmap_size parameter
 ...
 modparam("msrp", "cmap_size", 8)
 ...
 
 3.3. timer_interval (int)
 
    The timer interval in seconds to run the procedure for cleaning expired
    connections.
 
    Default value is '60'.
 
    Example 1.3. Set timer_interval parameter
 ...
 modparam("msrp", "timer_interval", 90)
 ...
 
 3.4. auth_min_expires (int)
 
9cb2a163
    The minimum value accepted for the “Expires” header in AUTH requests.
ea3cacb1
 
    Default value is '60'.
 
    Example 1.4. Set auth_min_expires parameter
 ...
 modparam("msrp", "auth_min_expiresl", 90)
 ...
 
 3.5. auth_max_expires (int)
 
9cb2a163
    The maximum value accepted for “Expires” header in AUTH requests.
ea3cacb1
 
    Default value is '3600'.
 
    Example 1.5. Set auth_max_expires parameter
 ...
 modparam("msrp", "auth_max_expiresl", 1800)
 ...
 
830af85c
 3.6. use_path_addr (str)
 
dfcdc7b8
    The hostname:port to be used when building the Path header.
830af85c
 
    Default value is NULL (server IP and port are used).
 
    Example 1.6. Set use_path_addr parameter
 ...
 modparam("msrp", "use_path_addr", "msrp.kamailio.org:5061")
 ...
 
a69aab1c
 3.7. event_callback (str)
 
    The name of the function in the kemi configuration file (embedded
    scripting language such as Lua, Python, ...) to be executed instead of
    event_route[...] blocks.
 
    The function receives a string parameter with the name of the event,
    the values can be: 'msrp:frame-in'.
 
    Default value is 'empty' (no function is executed for events).
 
    Example 1.7. Set event_callback parameter
 ...
c70f0941
 modparam("msrp", "event_callback", "ksr_msrp_event")
a69aab1c
 ...
 -- event callback function implemented in Lua
 function ksr_msrp_event(evname)
         KSR.info("===== msrp module triggered event: " .. evname .. "\n");
         return 1;
 end
 ...
 
19e138b5
 4. Functions
 
    4.1. msrp_relay()
    4.2. msrp_reply(code, text [, hdrs])
    4.3. msrp_is_request()
    4.4. msrp_is_reply()
    4.5. msrp_set_dst(addr, sock)
    4.6. msrp_relay_flags(flags)
    4.7. msrp_reply_flags(flags)
ea3cacb1
    4.8. msrp_cmap_save()
    4.9. msrp_cmap_lookup()
19e138b5
 
9cb2a163
 4.1.  msrp_relay()
19e138b5
 
ad54eb1c
    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
dfcdc7b8
    that due to nature of the MSRP transport layer, which is reliable
ad54eb1c
    (TCP/TLS), there is no retransmission of MSRP frames.
19e138b5
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.8. msrp_relay usage
19e138b5
 ...
 event_route[msrp:frame-in] {
     msrp_relay();
 }
 ...
 
9cb2a163
 4.2.  msrp_reply(code, text [, hdrs])
19e138b5
 
ad54eb1c
    Send a reply for the current MSRP request, adding optional headers.
19e138b5
 
ad54eb1c
    The parameter can be a pseudo-variable.
19e138b5
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.9. msrp_reply usage
19e138b5
 ...
 event_route[msrp:frame-in] {
     msrp_reply("403", "Not allowed");
 }
 ...
 
9cb2a163
 4.3.  msrp_is_request()
19e138b5
 
    Return true if the MSRP frame is a request.
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.10. msrp_is_request usage
19e138b5
 ...
 event_route[msrp:frame-in] {
     if(msrp_is_request())
     {
         msrp_relay();
         exit;
     }
 }
 ...
 
9cb2a163
 4.4.  msrp_is_reply()
19e138b5
 
    Return true if the MSRP frame is a reply.
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.11. msrp_is_reply usage
19e138b5
 ...
 event_route[msrp:frame-in] {
     if(msrp_is_reply())
     {
         msrp_relay();
         exit;
     }
 }
 ...
 
9cb2a163
 4.5.  msrp_set_dst(addr, sock)
19e138b5
 
    Set destination attributes: addr - target address as MSRP URI; sock -
    local socket to be used (format 'proto:ip:port').
 
ad54eb1c
    The parameter can be a pseudo-variable.
19e138b5
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.12. msrp_set_dst usage
19e138b5
 ...
 event_route[msrp:frame-in] {
     ...
     msrp_set_dst("msrp://127.0.0.1:8000", "tcp:127.0.0.1:5060");
     ...
 }
 ...
 
9cb2a163
 4.6.  msrp_relay_flags(flags)
19e138b5
 
    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).
 
ad54eb1c
    The parameter can be a pseudo-variable.
19e138b5
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.13. msrp_relay_flags usage
19e138b5
 ...
 event_route[msrp:frame-in] {
     ...
     msrp_relay_flags("1");
     ...
 }
 ...
 
9cb2a163
 4.7.  msrp_reply_flags(flags)
19e138b5
 
ad54eb1c
    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).
19e138b5
 
ad54eb1c
    The parameter can be a pseudo-variable.
19e138b5
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.14. msrp_reply_flags usage
19e138b5
 ...
 event_route[msrp:frame-in] {
     ...
     msrp_reply_flags("1");
     ...
 }
 ...
 
9cb2a163
 4.8.  msrp_cmap_save()
ea3cacb1
 
    Save details of a MSRP connection upon AUTH request inside the internal
    map table, indexed by session id.
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.15. msrp_cmap_save usage
ea3cacb1
 ...
 event_route[msrp:frame-in] {
     ...
da298e85
         if(method=="AUTH") { msrp_cmap_save(); exit; }
ea3cacb1
     ...
 }
 ...
 
9cb2a163
 4.9.  msrp_cmap_lookup()
ea3cacb1
 
    Lookup MSRP connection details for current session id.
 
    This function can be used in ANY_ROUTE.
 
a69aab1c
    Example 1.16. msrp_cmap_lookup usage
ea3cacb1
 ...
 event_route[msrp:frame-in] {
     ...
da298e85
         if(method=="SEND" and $msrp(nexthops)==1) {
ea3cacb1
                 if(msrp_cmap_lookup()) {
                         msrp_relay();
                 } else {
                         msrp_reply("481", "Session not found");
                 }
         }
     ...
 }
 ...
 
19e138b5
 5. Pseudo Variables
 
ad54eb1c
    The module exports a pseudo-variable class, $msrp(key), to access the
    MSRP frame (e.g. first line attributes, body, all frame content).
19e138b5
 
ad54eb1c
    The module exports a transformations class, 'msrpuri', to allow access
    attributes of a MSRP URI.
19e138b5
 
ad54eb1c
    These are documented in the appropriate Wiki pages hosted on the
    project web site.
19e138b5
 
bc8b005b
 6. RPC Commands
 
    6.1. msrp.cmaplist
 
9cb2a163
 6.1.  msrp.cmaplist
bc8b005b
 
    List active MSRP connections.
 
    Example:
 ...
 kamcmd msrp.cmaplist
 ...
 
 7. Event Routes
19e138b5
 
    For each MSRP frame received from the network, the module executes
    event_route[msrp:frame-in] block in the config file.
 
bc8b005b
 8. Usage
19e138b5
 
dfcdc7b8
    When the sipmsg parameter is set to 1 (which is the 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].
0c95e9cd
 
ad54eb1c
    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.
0c95e9cd
 ...
 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
ad54eb1c
    shows a line continuation due to the limitations of line length of this
0c95e9cd
    document. Neither the backslash nor the extra CRLF is included in the
    actual request or response.
 
ad54eb1c
    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.
0c95e9cd
 
ad54eb1c
    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.
0c95e9cd
 
    Next is an example of configuration file with the routing block for
    MSRP frames. In this config, the SIP traffic is rejected.
19e138b5
 
a69aab1c
    Example 1.17. Event Route (using htable for MSRP connection tracking)
19e138b5
 ...
 
 #!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"
 
 modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
 
70b0875f
 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;")
19e138b5
 
 request_route {
         sl_send_reply("403", "No SIP Here");
         exit;
 }
 
0c95e9cd
 reply_route {
         drop;
 }
 
19e138b5
 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");
 
70b0875f
         if(msrp_is_reply())
         {
                 msrp_relay();
         }
682f0026
         else if($msrp(method)=="AUTH")
19e138b5
         {
                 if($msrp(nexthops)>0)
                 {
                         msrp_relay();
                         exit;
                 }
70b0875f
 
19e138b5
                 # frame for local server - send Use-Path
                 # -- passwd can be loaded from DB based on $au
                 $var(passwd) = "xyz123";
682f0026
                 if(!pv_www_authenticate("myrealm", "$var(passwd)", "0",
                                         "$msrp(method)"))
19e138b5
                 {
70b0875f
                         if(auth_get_www_authenticate("myrealm", "1",
682f0026
                                                         "$var(wauth)"))
19e138b5
                         {
682f0026
                                 msrp_reply("401", "Unauthorized",
19e138b5
                                                 "$var(wauth)");
                         } else {
                                 msrp_reply("500", "Server Error");
                         }
                         exit;
                 }
70b0875f
 
                 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;
 
19e138b5
                 $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);
70b0875f
                 $shtex(msrp=>$var(sessid)) = $var(expires) + 5;
19e138b5
                 # - Use-Path: the MSRP address for server + session id
70b0875f
                 $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)");
19e138b5
         }
682f0026
         else if($msrp(method)=="SEND" || $msrp(method)=="REPORT")
19e138b5
         {
                 if($msrp(nexthops)>1)
                 {
682f0026
                         if ($msrp(method)!="REPORT")
                         {
                                 msrp_reply("200", "OK");
                         }
19e138b5
                         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
8b731296
                         if ($msrp(method)!="REPORT")
                         {
                                 msrp_reply("481", "Session-does-not-exist");
                         }
19e138b5
                         exit;
                 }
682f0026
                 else if($msrp(method)!="REPORT")
                 {
                         msrp_reply("200", "OK");
                 }
19e138b5
                 msrp_relay_flags("1");
                 msrp_set_dst("$sht(msrp=>$var(sessid)::srcaddr)",
                                 "$sht(msrp=>$var(sessid)::srcsock)");
                 msrp_relay();
         }
682f0026
         else
         {
                 msrp_reply("501", "Request-method-not-understood");
         }
19e138b5
 }
 
da298e85
 ...
 
a69aab1c
    Example 1.18. Event Route (using msrp_cmap_ functions for connection
da298e85
    tracking)
 ...
 
 #!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 "xlog.so"
 
 modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
 
 modparam("auth", "nonce_count", 1)
 modparam("auth", "qop", "auth")
 
 modparam("msrp", "cmap_size", 8)
 modparam("msrp", "use_path_addr", "msrp://127.0.0.1:5060")
 
 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;
                 }
 
                 msrp_cmap_save();
         }
         else if ($msrp(method)=="SEND" || $msrp(method)=="REPORT")
         {
                 if ($msrp(nexthops)>1)
                 {
                         if ($msrp(method)!="REPORT")
                         {
                                 msrp_reply("200", "OK");
                         }
                         msrp_relay();
                         exit;
                 }
 
                 if (msrp_cmap_lookup())
                 {
                         if ($msrp(method)!="REPORT")
                         {
                                 msrp_reply("200", "OK");
                         }
                         msrp_relay_flags("1");
                         msrp_relay();
                 }
                 else
                 {
                         msrp_reply("481", "Session-does-not-exist");
                 }
         }
         else
         {
                 msrp_reply("501", "Request-method-not-understood");
         }
 }
 
19e138b5
 ...