1MSRP Module
2
3Daniel-Constantin Mierla
4
5   <miconda@gmail.com>
6
7Edited by
8
9Daniel-Constantin Mierla
10
11   <miconda@gmail.com>
12
13Alex Balashov
14
15   <abalashov@evaristesys.com>
16
17   Copyright © 2012 asipto.com
18     __________________________________________________________________
19
20   Table of Contents
21
22   1. Admin Guide
23
24        1. Overview
25        2. Dependencies
26
27              2.1. Kamailio Modules
28              2.2. External Libraries or Applications
29
30        3. Parameters
31
32              3.1. sipmsg (int)
33              3.2. cmap_size (int)
34              3.3. timer_interval (int)
35              3.4. auth_min_expires (int)
36              3.5. auth_max_expires (int)
37              3.6. use_path_addr (str)
38              3.7. event_callback (str)
39
40        4. Functions
41
42              4.1. msrp_relay()
43              4.2. msrp_reply(code, text [, hdrs])
44              4.3. msrp_is_request()
45              4.4. msrp_is_reply()
46              4.5. msrp_set_dst(addr, sock)
47              4.6. msrp_relay_flags(flags)
48              4.7. msrp_reply_flags(flags)
49              4.8. msrp_cmap_save()
50              4.9. msrp_cmap_lookup()
51
52        5. Pseudo Variables
53        6. RPC Commands
54
55              6.1. msrp.cmaplist
56
57        7. Event Routes
58        8. Usage
59
60   List of Examples
61
62   1.1. Set sipmsg parameter
63   1.2. Set cmap_size parameter
64   1.3. Set timer_interval parameter
65   1.4. Set auth_min_expires parameter
66   1.5. Set auth_max_expires parameter
67   1.6. Set use_path_addr parameter
68   1.7. Set event_callback parameter
69   1.8. msrp_relay usage
70   1.9. msrp_reply usage
71   1.10. msrp_is_request usage
72   1.11. msrp_is_reply usage
73   1.12. msrp_set_dst usage
74   1.13. msrp_relay_flags usage
75   1.14. msrp_reply_flags usage
76   1.15. msrp_cmap_save usage
77   1.16. msrp_cmap_lookup usage
78   1.17. Event Route (using htable for MSRP connection tracking)
79   1.18. Event Route (using msrp_cmap_ functions for connection tracking)
80
81Chapter 1. Admin Guide
82
83   Table of Contents
84
85   1. Overview
86   2. Dependencies
87
88        2.1. Kamailio Modules
89        2.2. External Libraries or Applications
90
91   3. Parameters
92
93        3.1. sipmsg (int)
94        3.2. cmap_size (int)
95        3.3. timer_interval (int)
96        3.4. auth_min_expires (int)
97        3.5. auth_max_expires (int)
98        3.6. use_path_addr (str)
99        3.7. event_callback (str)
100
101   4. Functions
102
103        4.1. msrp_relay()
104        4.2. msrp_reply(code, text [, hdrs])
105        4.3. msrp_is_request()
106        4.4. msrp_is_reply()
107        4.5. msrp_set_dst(addr, sock)
108        4.6. msrp_relay_flags(flags)
109        4.7. msrp_reply_flags(flags)
110        4.8. msrp_cmap_save()
111        4.9. msrp_cmap_lookup()
112
113   5. Pseudo Variables
114   6. RPC Commands
115
116        6.1. msrp.cmaplist
117
118   7. Event Routes
119   8. Usage
120
1211. Overview
122
123   This module provides a MSRP routing engine, a.k.a. MSRP relay. MSRP
124   (Message Session Relay Protocol) is defined by RFC4975, and the
125   extensions for an MSRP relay are covered in RFC4976.
126
127   A typical use of MSRP is instant messaging sessions initiated via SIP.
128   Unlike page-mode instant messaging, which is done via the SIP MESSAGE
129   request, MSRP uses a different communication channel which is
130   negotiated via INVITE-200 OK-ACK.
131
132   However, MSRP is still a text-based protocol. It uses several routing
133   mechanisms similar to what exists in SIP. Furthermore, MSRP requires
134   TCP, and recommends TLS for confidentiality and security. In light of
135   the scalability and performance of Kamailio in handling TCP/TLS, this
136   module reuses Kamailio's core framework to offer MSRP routing
137   capabilities. Along with embedded Presence and XCAP servers, Kamailio
138   now offers a complete solution for SIP beyond VoIP.
139
140   One of the main benefits of this module is the ability to reuse all the
141   other extensions that exist in the SIP server, including accounting,
142   authentication, authorization to database connectors, security and DoS
143   attack protections.
144
145   Kamailio can handle SIP and MSRP traffic received on the same port; the
146   appropriate configuration file block being executed based on the type
147   of message. Therefore, you can use Kamailio as a stand-alone MSRP relay
148   or you can have an instance handling both SIP and MSRP. Another option
149   is to configure Kamailio to listen on multiple ports, some of them for
150   SIP and others for MSRP.
151
1522. Dependencies
153
154   2.1. Kamailio Modules
155   2.2. External Libraries or Applications
156
1572.1. Kamailio Modules
158
159   The following modules must be loaded before this module:
160     * None.
161
162   The following modules are required to make proper use of this module:
163     * tls.
164
1652.2. External Libraries or Applications
166
167   The following libraries or applications must be installed before
168   running Kamailio with this module loaded:
169     * None
170
1713. Parameters
172
173   3.1. sipmsg (int)
174   3.2. cmap_size (int)
175   3.3. timer_interval (int)
176   3.4. auth_min_expires (int)
177   3.5. auth_max_expires (int)
178   3.6. use_path_addr (str)
179   3.7. event_callback (str)
180
1813.1. sipmsg (int)
182
183   If set to 1, the module will build a SIP message from MSRP frame
184   headers, providing it to “event_route[msrp:frame-in]”. All the config
185   file functions (apart from SIP request relay) that can be used in a
186   request route block can be used in the MSRP event_route.
187
188   Default value is '1'.
189
190   Example 1.1. Set sipmsg parameter
191...
192modparam("msrp", "sipmsg", 1)
193...
194
1953.2. cmap_size (int)
196
197   The size of connection map table, to be computed as power of 2 (e.g.,
198   if the value is 4, then the number of slots in map table is 2^4 = 16).
199
200   Default value is '0' (no internal map table to be used).
201
202   Example 1.2. Set cmap_size parameter
203...
204modparam("msrp", "cmap_size", 8)
205...
206
2073.3. timer_interval (int)
208
209   The timer interval in seconds to run the procedure for cleaning expired
210   connections.
211
212   Default value is '60'.
213
214   Example 1.3. Set timer_interval parameter
215...
216modparam("msrp", "timer_interval", 90)
217...
218
2193.4. auth_min_expires (int)
220
221   The minimum value accepted for the “Expires” header in AUTH requests.
222
223   Default value is '60'.
224
225   Example 1.4. Set auth_min_expires parameter
226...
227modparam("msrp", "auth_min_expiresl", 90)
228...
229
2303.5. auth_max_expires (int)
231
232   The maximum value accepted for “Expires” header in AUTH requests.
233
234   Default value is '3600'.
235
236   Example 1.5. Set auth_max_expires parameter
237...
238modparam("msrp", "auth_max_expiresl", 1800)
239...
240
2413.6. use_path_addr (str)
242
243   The hostname:port to be used when building the Path header.
244
245   Default value is NULL (server IP and port are used).
246
247   Example 1.6. Set use_path_addr parameter
248...
249modparam("msrp", "use_path_addr", "msrp.kamailio.org:5061")
250...
251
2523.7. event_callback (str)
253
254   The name of the function in the kemi configuration file (embedded
255   scripting language such as Lua, Python, ...) to be executed instead of
256   event_route[...] blocks.
257
258   The function receives a string parameter with the name of the event,
259   the values can be: 'msrp:frame-in'.
260
261   Default value is 'empty' (no function is executed for events).
262
263   Example 1.7. Set event_callback parameter
264...
265modparam("msrp", "event_callback", "ksr_msrp_event")
266...
267-- event callback function implemented in Lua
268function ksr_msrp_event(evname)
269        KSR.info("===== msrp module triggered event: " .. evname .. "\n");
270        return 1;
271end
272...
273
2744. Functions
275
276   4.1. msrp_relay()
277   4.2. msrp_reply(code, text [, hdrs])
278   4.3. msrp_is_request()
279   4.4. msrp_is_reply()
280   4.5. msrp_set_dst(addr, sock)
281   4.6. msrp_relay_flags(flags)
282   4.7. msrp_reply_flags(flags)
283   4.8. msrp_cmap_save()
284   4.9. msrp_cmap_lookup()
285
2864.1.  msrp_relay()
287
288   Relay MSRP frame according to the To-Path. This function has to be
289   executed for each MSRP request or reply that has to be forwarded. Note
290   that due to nature of the MSRP transport layer, which is reliable
291   (TCP/TLS), there is no retransmission of MSRP frames.
292
293   This function can be used in ANY_ROUTE.
294
295   Example 1.8. msrp_relay usage
296...
297event_route[msrp:frame-in] {
298    msrp_relay();
299}
300...
301
3024.2.  msrp_reply(code, text [, hdrs])
303
304   Send a reply for the current MSRP request, adding optional headers.
305
306   The parameter can be a pseudo-variable.
307
308   This function can be used in ANY_ROUTE.
309
310   Example 1.9. msrp_reply usage
311...
312event_route[msrp:frame-in] {
313    msrp_reply("403", "Not allowed");
314}
315...
316
3174.3.  msrp_is_request()
318
319   Return true if the MSRP frame is a request.
320
321   This function can be used in ANY_ROUTE.
322
323   Example 1.10. msrp_is_request usage
324...
325event_route[msrp:frame-in] {
326    if(msrp_is_request())
327    {
328        msrp_relay();
329        exit;
330    }
331}
332...
333
3344.4.  msrp_is_reply()
335
336   Return true if the MSRP frame is a reply.
337
338   This function can be used in ANY_ROUTE.
339
340   Example 1.11. msrp_is_reply usage
341...
342event_route[msrp:frame-in] {
343    if(msrp_is_reply())
344    {
345        msrp_relay();
346        exit;
347    }
348}
349...
350
3514.5.  msrp_set_dst(addr, sock)
352
353   Set destination attributes: addr - target address as MSRP URI; sock -
354   local socket to be used (format 'proto:ip:port').
355
356   The parameter can be a pseudo-variable.
357
358   This function can be used in ANY_ROUTE.
359
360   Example 1.12. msrp_set_dst usage
361...
362event_route[msrp:frame-in] {
363    ...
364    msrp_set_dst("msrp://127.0.0.1:8000", "tcp:127.0.0.1:5060");
365    ...
366}
367...
368
3694.6.  msrp_relay_flags(flags)
370
371   Set transport layer sending flags for forwarding current MSRP frame;
372   flags - a bitmask of flags - 1 (don't create a new connection), 2
373   (close connection after send).
374
375   The parameter can be a pseudo-variable.
376
377   This function can be used in ANY_ROUTE.
378
379   Example 1.13. msrp_relay_flags usage
380...
381event_route[msrp:frame-in] {
382    ...
383    msrp_relay_flags("1");
384    ...
385}
386...
387
3884.7.  msrp_reply_flags(flags)
389
390   Set transport layer sending flags for replies to the current MSRP
391   frame; flags - a bitmask of flags - 1 (don't create a new connection),
392   2 (close connection after send).
393
394   The parameter can be a pseudo-variable.
395
396   This function can be used in ANY_ROUTE.
397
398   Example 1.14. msrp_reply_flags usage
399...
400event_route[msrp:frame-in] {
401    ...
402    msrp_reply_flags("1");
403    ...
404}
405...
406
4074.8.  msrp_cmap_save()
408
409   Save details of a MSRP connection upon AUTH request inside the internal
410   map table, indexed by session id.
411
412   This function can be used in ANY_ROUTE.
413
414   Example 1.15. msrp_cmap_save usage
415...
416event_route[msrp:frame-in] {
417    ...
418        if(method=="AUTH") { msrp_cmap_save(); exit; }
419    ...
420}
421...
422
4234.9.  msrp_cmap_lookup()
424
425   Lookup MSRP connection details for current session id.
426
427   This function can be used in ANY_ROUTE.
428
429   Example 1.16. msrp_cmap_lookup usage
430...
431event_route[msrp:frame-in] {
432    ...
433        if(method=="SEND" and $msrp(nexthops)==1) {
434                if(msrp_cmap_lookup()) {
435                        msrp_relay();
436                } else {
437                        msrp_reply("481", "Session not found");
438                }
439        }
440    ...
441}
442...
443
4445. Pseudo Variables
445
446   The module exports a pseudo-variable class, $msrp(key), to access the
447   MSRP frame (e.g. first line attributes, body, all frame content).
448
449   The module exports a transformations class, 'msrpuri', to allow access
450   attributes of a MSRP URI.
451
452   These are documented in the appropriate Wiki pages hosted on the
453   project web site.
454
4556. RPC Commands
456
457   6.1. msrp.cmaplist
458
4596.1.  msrp.cmaplist
460
461   List active MSRP connections.
462
463   Example:
464...
465kamcmd msrp.cmaplist
466...
467
4687. Event Routes
469
470   For each MSRP frame received from the network, the module executes
471   event_route[msrp:frame-in] block in the config file.
472
4738. Usage
474
475   When the sipmsg parameter is set to 1 (which is the default), the
476   module internally builds a SIP request from the MSRP frame and exposes
477   it to the config file interpreter. This way, all the functions that are
478   valid for SIP requests can be used safely in
479   event_route[msrp:frame-in].
480
481   To build the SIP request, the module takes the first line and the
482   headers from an MSRP message and appends them to a static buffer. The
483   next two examples show an MSRP frame and the resulting SIP request.
484...
485MSRP 6aef SEND
486To-Path: msrps://a.example.org:9000/kjfjan;tcp \
487  msrps://b.example.net:9000/aeiug;tcp \
488  msrps://bob.example.net:8145/foo;tcp
489From-Path: msrps://alice.example.org:7965/bar;tcp
490Success-Report: yes
491Byte-Range: 1-*/*
492Message-ID: 87652
493Content-Type: text/plain
494
495Hi Bob, I'm about to send you a photo.
496-------6aef$
497...
498...
499MSRP sip:a@127.0.0.1 SIP/2.0
500Via: SIP/2.0/UDP 127.0.0.1:9;branch=z9hG4bKa
501From: <b@127.0.0.1>;tag=a
502To: <a@127.0.0.1>
503Call-ID: a
504CSeq: 1 MSRP
505Content-Length: 0
506MSRP-First-Line: MSRP 6aef SEND
507To-Path: msrps://a.example.org:9000/kjfjan;tcp \
508  msrps://b.example.net:9000/aeiug;tcp \
509  msrps://bob.example.net:8145/foo;tcp
510From-Path: msrps://alice.example.org:7965/bar;tcp
511Success-Report: yes
512Byte-Range: 1-*/*
513Message-ID: 87652
514Content-Type: text/plain
515
516...
517
518   Note that MSRP does not permit line folding. A "\" in the examples
519   shows a line continuation due to the limitations of line length of this
520   document. Neither the backslash nor the extra CRLF is included in the
521   actual request or response.
522
523   As can be observed, the MSRP frame content starts with the body of the
524   'MSRP-First-Line:' header. Using static content to get to a valid SIP
525   request is a perfect trade-off for performance.
526
527   Besides the option to access parts of MSRP frame via an
528   internally-built SIP message, the module exports a new pseudo-variable
529   class $msrp(key) which returns attributes from the MSRP frame. There is
530   also a new transformation, {msrpuri.key}, to get access to parts of an
531   MSRP URI. See the appropriate Wiki pages on the project's web site for
532   full details about new pseudo-variable and transformation classes.
533
534   Next is an example of configuration file with the routing block for
535   MSRP frames. In this config, the SIP traffic is rejected.
536
537   Example 1.17. Event Route (using htable for MSRP connection tracking)
538...
539
540#!KAMAILIO
541
542debug=2
543memdbg=5
544memlog=5
545
546children=4
547
548log_stderror=yes
549auto_aliases=no
550
551tcp_accept_no_cl=yes
552tcp_connection_lifetime=1810
553
554listen=127.0.0.1:5060
555
556mpath="modules_k/:modules/"
557
558loadmodule "sl.so"
559loadmodule "kex.so"
560loadmodule "mi_fifo.so"
561loadmodule "ctl.so"
562loadmodule "msrp.so"
563loadmodule "pv.so"
564loadmodule "auth.so"
565loadmodule "cfgutils.so"
566loadmodule "htable.so"
567loadmodule "xlog.so"
568
569modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
570
571modparam("auth", "nonce_count", 1)
572modparam("auth", "qop", "auth")
573
574#!substdef "!MSRP_MIN_EXPIRES!1800!g"
575#!substdef "!MSRP_MAX_EXPIRES!3600!g"
576modparam("htable", "htable", "msrp=>size=8;autoexpire=MSRP_MAX_EXPIRES;")
577
578request_route {
579        sl_send_reply("403", "No SIP Here");
580        exit;
581}
582
583reply_route {
584        drop;
585}
586
587event_route[msrp:frame-in] {
588        xdbg("============#[[$msrp(method)]]===========\n");
589        xdbg("============*[[$si:$sp]]\n");
590        xdbg("============ crthop:   [$msrp(crthop)]\n");
591        xdbg("============ prevhop:  [$msrp(prevhop)]\n");
592        xdbg("============ nexthop:  [$msrp(nexthop)]\n");
593        xdbg("============ firsthop: [$msrp(firsthop)]\n");
594        xdbg("============ lasthop:  [$msrp(lasthop)]\n");
595        xdbg("============ prevhops: [$msrp(prevhops)]\n");
596        xdbg("============ nexthops: [$msrp(nexthops)]\n");
597        xdbg("============ srcaddr:  [$msrp(srcaddr)]\n");
598        xdbg("============ srcsock:  [$msrp(srcsock)]\n");
599        xdbg("============ sessid:   [$msrp(sessid)]\n");
600
601        msrp_reply_flags("1");
602
603        if(msrp_is_reply())
604        {
605                msrp_relay();
606        }
607        else if($msrp(method)=="AUTH")
608        {
609                if($msrp(nexthops)>0)
610                {
611                        msrp_relay();
612                        exit;
613                }
614
615                # frame for local server - send Use-Path
616                # -- passwd can be loaded from DB based on $au
617                $var(passwd) = "xyz123";
618                if(!pv_www_authenticate("myrealm", "$var(passwd)", "0",
619                                        "$msrp(method)"))
620                {
621                        if(auth_get_www_authenticate("myrealm", "1",
622                                                        "$var(wauth)"))
623                        {
624                                msrp_reply("401", "Unauthorized",
625                                                "$var(wauth)");
626                        } else {
627                                msrp_reply("500", "Server Error");
628                        }
629                        exit;
630                }
631
632                if ($hdr(Expires) != $null) {
633                        $var(expires) = (int) $hdr(Expires);
634                        if ($var(expires) < MSRP_MIN_EXPIRES) {
635                                msrp_reply("423", "Interval Out-of-Bounds",
636                                        "Min-Expires: MSRP_MIN_EXPIRES\r\n");
637                                exit;
638                        } else {
639                                msrp_reply("423", "Interval Out-of-Bounds",
640                                        "Max-Expires: MSRP_MAX_EXPIRES\r\n");
641                                exit;
642                        }
643
644                } else
645                        $var(expires) = MSRP_MAX_EXPIRES;
646
647                $var(cnt) = $var(cnt) + 1;
648                pv_printf("$var(sessid)", "s.$(pp).$(var(cnt)).$(RANDOM)");
649                $sht(msrp=>$var(sessid)::srcaddr) = $msrp(srcaddr);
650                $sht(msrp=>$var(sessid)::srcsock) = $msrp(srcsock);
651                $shtex(msrp=>$var(sessid)) = $var(expires) + 5;
652                # - Use-Path: the MSRP address for server + session id
653                $var(headers) = "Use-Path: msrp://127.0.0.1:5060/"
654                                + $var(sessid) + ";tcp\r\n"
655                                + "Expires: " + $var(expires) + "\r\n";
656                msrp_reply("200", "OK", "$var(headers)");
657        }
658        else if($msrp(method)=="SEND" || $msrp(method)=="REPORT")
659        {
660                if($msrp(nexthops)>1)
661                {
662                        if ($msrp(method)!="REPORT")
663                        {
664                                msrp_reply("200", "OK");
665                        }
666                        msrp_relay();
667                        exit;
668                }
669                $var(sessid) = $msrp(sessid);
670                if($sht(msrp=>$var(sessid)::srcaddr) == $null)
671                {
672                        # one more hop, but we don't have address in htable
673                        if ($msrp(method)!="REPORT")
674                        {
675                                msrp_reply("481", "Session-does-not-exist");
676                        }
677                        exit;
678                }
679                else if($msrp(method)!="REPORT")
680                {
681                        msrp_reply("200", "OK");
682                }
683                msrp_relay_flags("1");
684                msrp_set_dst("$sht(msrp=>$var(sessid)::srcaddr)",
685                                "$sht(msrp=>$var(sessid)::srcsock)");
686                msrp_relay();
687        }
688        else
689        {
690                msrp_reply("501", "Request-method-not-understood");
691        }
692}
693
694...
695
696   Example 1.18. Event Route (using msrp_cmap_ functions for connection
697   tracking)
698...
699
700#!KAMAILIO
701
702debug=2
703memdbg=5
704memlog=5
705
706children=4
707
708log_stderror=yes
709auto_aliases=no
710
711tcp_accept_no_cl=yes
712tcp_connection_lifetime=1810
713
714listen=127.0.0.1:5060
715
716mpath="modules_k/:modules/"
717
718loadmodule "sl.so"
719loadmodule "kex.so"
720loadmodule "mi_fifo.so"
721loadmodule "ctl.so"
722loadmodule "msrp.so"
723loadmodule "pv.so"
724loadmodule "auth.so"
725loadmodule "cfgutils.so"
726loadmodule "xlog.so"
727
728modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
729
730modparam("auth", "nonce_count", 1)
731modparam("auth", "qop", "auth")
732
733modparam("msrp", "cmap_size", 8)
734modparam("msrp", "use_path_addr", "msrp://127.0.0.1:5060")
735
736request_route {
737        sl_send_reply("403", "No SIP Here");
738        exit;
739}
740
741reply_route {
742        drop;
743}
744
745event_route[msrp:frame-in] {
746        xdbg("============#[[$msrp(method)]]===========\n");
747        xdbg("============*[[$si:$sp]]\n");
748        xdbg("============ crthop:   [$msrp(crthop)]\n");
749        xdbg("============ prevhop:  [$msrp(prevhop)]\n");
750        xdbg("============ nexthop:  [$msrp(nexthop)]\n");
751        xdbg("============ firsthop: [$msrp(firsthop)]\n");
752        xdbg("============ lasthop:  [$msrp(lasthop)]\n");
753        xdbg("============ prevhops: [$msrp(prevhops)]\n");
754        xdbg("============ nexthops: [$msrp(nexthops)]\n");
755        xdbg("============ srcaddr:  [$msrp(srcaddr)]\n");
756        xdbg("============ srcsock:  [$msrp(srcsock)]\n");
757        xdbg("============ sessid:   [$msrp(sessid)]\n");
758
759        msrp_reply_flags("1");
760
761        if (msrp_is_reply())
762        {
763                msrp_relay();
764        }
765        else if($msrp(method)=="AUTH")
766        {
767                if($msrp(nexthops)>0)
768                {
769                        msrp_relay();
770                        exit;
771                }
772
773                # frame for local server - send Use-Path
774                # -- passwd can be loaded from DB based on $au
775                $var(passwd) = "xyz123";
776                if(!pv_www_authenticate("myrealm", "$var(passwd)", "0",
777                                        "$msrp(method)"))
778                {
779                        if(auth_get_www_authenticate("myrealm", "1",
780                                                        "$var(wauth)"))
781                        {
782                                msrp_reply("401", "Unauthorized",
783                                                "$var(wauth)");
784                        } else {
785                                msrp_reply("500", "Server Error");
786                        }
787                        exit;
788                }
789
790                msrp_cmap_save();
791        }
792        else if ($msrp(method)=="SEND" || $msrp(method)=="REPORT")
793        {
794                if ($msrp(nexthops)>1)
795                {
796                        if ($msrp(method)!="REPORT")
797                        {
798                                msrp_reply("200", "OK");
799                        }
800                        msrp_relay();
801                        exit;
802                }
803
804                if (msrp_cmap_lookup())
805                {
806                        if ($msrp(method)!="REPORT")
807                        {
808                                msrp_reply("200", "OK");
809                        }
810                        msrp_relay_flags("1");
811                        msrp_relay();
812                }
813                else
814                {
815                        msrp_reply("481", "Session-does-not-exist");
816                }
817        }
818        else
819        {
820                msrp_reply("501", "Request-method-not-understood");
821        }
822}
823
824...
825