1WebSocket Module
2
3Peter Dunkley
4
5   Crocodile RCS Ltd
6
7   Copyright © 2012-2013 Crocodile RCS Ltd
8     __________________________________________________________________
9
10   Table of Contents
11
12   1. Admin Guide
13
14        1. Overview
15        2. How it works
16
17              2.1. Initiating a connection
18              2.2. SIP message routing
19              2.3. MSRP message routing
20
21        3. Dependencies
22
23              3.1. Kamailio Modules
24              3.2. External Libraries or Applications
25
26        4. Parameters
27
28              4.1. keepalive_mechanism (integer)
29              4.2. keepalive_timeout (integer)
30              4.3. keepalive_processes (integer)
31              4.4. keepalive_interval (integer)
32              4.5. ping_application_data (string)
33              4.6. sub_protocols (integer)
34              4.7. cors_mode (integer)
35              4.8. verbose_list (int)
36              4.9. event_callback (str)
37              4.10. timer_interval (integer)
38              4.11. rm_delay_interval (integer)
39
40        5. Functions
41
42              5.1. ws_handle_handshake()
43              5.2. ws_close([status, reason[, connection_id]])
44
45        6. RPC Commands
46
47              6.1. ws.dump
48              6.2. ws.close
49              6.3. ws.ping
50              6.4. ws.pong
51              6.5. ws.disable
52              6.6. ws.enable
53
54        7. Event routes
55
56              7.1. websocket:closed
57
58        8. Exported Pseudo Variables
59
60              8.1. $ws_conid
61
62   List of Examples
63
64   1.1. event_route[xhttp:request]
65   1.2. WebSocket SIP Routing
66   1.3. Set keepalive_mechanism parameter
67   1.4. Set keepalive_timeout parameter
68   1.5. Set keepalive_processes parameter
69   1.6. Set keepalive_interval parameter
70   1.7. Set ping_application_data parameter
71   1.8. Set sub_protocols parameter
72   1.9. Set cors_mode parameter
73   1.10. Set verbose_list parameter
74   1.11. Set event_callback parameter
75   1.12. Set timer_intervalparameter
76   1.13. Set rm_delay_intervalparameter
77   1.14. ws_handle_handshake usage
78   1.15. ws_close usage
79   1.16. event_route[websocket:closed] usage
80   1.17. $ws_conid usage
81
82Chapter 1. Admin Guide
83
84   Table of Contents
85
86   1. Overview
87   2. How it works
88
89        2.1. Initiating a connection
90        2.2. SIP message routing
91        2.3. MSRP message routing
92
93   3. Dependencies
94
95        3.1. Kamailio Modules
96        3.2. External Libraries or Applications
97
98   4. Parameters
99
100        4.1. keepalive_mechanism (integer)
101        4.2. keepalive_timeout (integer)
102        4.3. keepalive_processes (integer)
103        4.4. keepalive_interval (integer)
104        4.5. ping_application_data (string)
105        4.6. sub_protocols (integer)
106        4.7. cors_mode (integer)
107        4.8. verbose_list (int)
108        4.9. event_callback (str)
109        4.10. timer_interval (integer)
110        4.11. rm_delay_interval (integer)
111
112   5. Functions
113
114        5.1. ws_handle_handshake()
115        5.2. ws_close([status, reason[, connection_id]])
116
117   6. RPC Commands
118
119        6.1. ws.dump
120        6.2. ws.close
121        6.3. ws.ping
122        6.4. ws.pong
123        6.5. ws.disable
124        6.6. ws.enable
125
126   7. Event routes
127
128        7.1. websocket:closed
129
130   8. Exported Pseudo Variables
131
132        8.1. $ws_conid
133
1341. Overview
135
136   This module implements a WebSocket (RFC 6455) server and provides
137   connection establishment (handshaking), management (including
138   connection keep-alive), and framing for the SIP and MSRP WebSocket
139   sub-protocols (RFC 7118 and RFC 7977).
140
141   The module supports WebSockets (ws) and secure WebSockets (wss)
142   transports
143
1442. How it works
145
146   2.1. Initiating a connection
147   2.2. SIP message routing
148   2.3. MSRP message routing
149
1502.1. Initiating a connection
151
152   A WebSocket connection is initiated with an HTTP GET. The xhttp module
153   is used to handle this GET and call the Section 5.1, “
154   ws_handle_handshake() ” exported function.
155
156   event_route[xhttp:request] should perform some validation of the HTTP
157   headers before calling Section 5.1, “ ws_handle_handshake() ”. The
158   event_route can also be used to make sure the HTTP GET has the correct
159   URI, perform HTTP authentication on the WebSocket connection, and check
160   the Origin header (RFC 6454) to ensure a browser-based SIP UA or MSRP
161   client has been downloaded from the correct location.
162
163   Example 1.1. event_route[xhttp:request]
164...
165loadmodule "sl.so"
166loadmodule "xhttp.so"
167loadmodule "msrp.so"  # Only required if using MSRP over WebSockets
168loadmodule "websocket.so"
169...
170event_route[xhttp:request] {
171        set_reply_close();
172        set_reply_no_connect();
173
174        if ($Rp != 80
175#!ifdef WITH_TLS
176            && $Rp != 443
177#!endif
178        ) {
179
180                xlog("L_WARN", "HTTP request received on $Rp\n");
181                xhttp_reply("403", "Forbidden", "", "");
182                exit;
183        }
184
185        xlog("L_DBG", "HTTP Request Received\n");
186
187        if ($hdr(Upgrade)=~"websocket"
188                        && $hdr(Connection)=~"Upgrade"
189                        && $rm=~"GET") {
190
191                # Validate Host - make sure the client is using the correct
192                # alias for WebSockets
193                if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) {
194                        xlog("L_WARN", "Bad host $hdr(Host)\n");
195                        xhttp_reply("403", "Forbidden", "", "");
196                        exit;
197                }
198
199                # Optional... validate Origin - make sure the client is from an
200                # authorised website.  For example,
201                #
202                # if ($hdr(Origin) != "http://communicator.MY_DOMAIN"
203                #     && $hdr(Origin) != "https://communicator.MY_DOMAIN") {
204                #       xlog("L_WARN", "Unauthorised client $hdr(Origin)\n");
205                #       xhttp_reply("403", "Forbidden", "", "");
206                #       exit;
207                # }
208
209                # Optional... perform HTTP authentication
210
211                # ws_handle_handshake() exits (no further configuration file
212                # processing of the request) when complete in case of failure.
213                if (ws_handle_handshake())
214                {
215                        # Optional... cache some information about the
216                        # successful connection
217                        exit;
218                }
219        }
220
221        xhttp_reply("404", "Not found", "", "");
222}
223...
224
2252.2. SIP message routing
226
227   SIP over WebSockets uses invalid URIs in routing headers (Contact:,
228   Record-Route:, and Via:) because a JavaScript stack running in a
229   browser has no way to determine the local address from which the
230   WebSocket connection is made. This means that the routing headers
231   cannot be used for request or response routing in the normal manner.
232
233   RFC 7118 - The WebSocket Protocol as a Transport for the Session
234   Initiation Protocol - states that SIP WebSocket Clients and the SIP
235   registrar should implement SIP Outbound (RFC 5626) and Path header
236   support (RFC 3327) to enable requests and responses to be correctly
237   routed. Kamailio has a module called "Outbound" for this functionality.
238
239   The nathelper module functions (nat_uac_test(), fix_nated_register(),
240   add_contact_alias(), and handle_ruri_alias()) and the Kamailio core
241   force_rport() can be used to ensure correct routing of SIP WebSocket
242   requests without using Outbound and Path.
243
244   Example 1.2. WebSocket SIP Routing
245...
246loadmodule "sl.so"
247loadmodule "tm.so"
248...
249loadmodule "websocket.so"
250...
251request_route {
252
253        # per request initial checks
254        route(REQINIT);
255
256        if (nat_uac_test(64)) {
257                # Do NAT traversal stuff for requests from a WebSocket
258                # connection - even if it is not behind a NAT!
259                # This won't be needed in the future if Kamailio and the
260                # WebSocket client support Outbound and Path.
261                force_rport();
262                if (is_method("REGISTER"))
263                        fix_nated_register();
264                else {
265                        if (!add_contact_alias()) {
266                                xlog("L_ERR", "Error aliasing contact <$ct>\n");
267                                sl_send_reply("400", "Bad Request");
268                                exit;
269                        }
270                }
271        }
272
273        if (!is_method("REGISTER"))
274                t_on_reply("WS_REPLY");
275...
276# Handle requests within SIP dialogs
277route[WITHINDLG] {
278        if (has_totag()) {
279                # sequential request withing a dialog should
280                # take the path determined by record-routing
281                if (loose_route()) {
282                        if ($du == "") {
283                                if (!handle_ruri_alias()) {
284                                        xlog("L_ERR", "Bad alias <$ru>\n");
285                                        sl_send_reply("400", "Bad Request");
286                                        exit;
287                                }
288                        }
289                        route(RELAY);
290                } else {
291                        if ( is_method("ACK") ) {
292...
293onreply_route[WS_REPLY] {
294        if (nat_uac_test(64)) {
295                # Do NAT traversal stuff for replies to a WebSocket connection
296                # - even if it is not behind a NAT!
297                # This won't be needed in the future if Kamailio and the
298                # WebSocket client support Outbound and Path.
299                add_contact_alias();
300        }
301}
302...
303
3042.3. MSRP message routing
305
306   MSRP over WebSocket clients create invalid local URIs for use in Path
307   headers (From-Path: and To-Path:) because a JavaScript stack running in
308   a browser has no way to determine the local address from which the
309   WebSocket connection is made. This is OK because MSRP over WebSocket
310   clients MUST use an MSRP relay and it is the MSRP relay's
311   responsibility to select the correct connection to the client based on
312   the MSRP URIs that it has created (and maintains a mapping for).
313
3143. Dependencies
315
316   3.1. Kamailio Modules
317   3.2. External Libraries or Applications
318
3193.1. Kamailio Modules
320
321   The following module must be loaded before this module:
322     * sl.
323     * tm.
324
325   The following modules are required to make proper use of this module:
326     * nathelper or outbound.
327     * xhttp.
328
329   The following module is required to use the secure WebSocket (wss)
330   scheme:
331     * tls.
332
333   The following module is required to support MSRP over WebSockets:
334     * msrp.
335
3363.2. External Libraries or Applications
337
338   The following libraries must be installed before running Kamailio with
339   this module loaded:
340     * OpenSSL.
341     * GNU libunistring.
342
3434. Parameters
344
345   4.1. keepalive_mechanism (integer)
346   4.2. keepalive_timeout (integer)
347   4.3. keepalive_processes (integer)
348   4.4. keepalive_interval (integer)
349   4.5. ping_application_data (string)
350   4.6. sub_protocols (integer)
351   4.7. cors_mode (integer)
352   4.8. verbose_list (int)
353   4.9. event_callback (str)
354   4.10. timer_interval (integer)
355   4.11. rm_delay_interval (integer)
356
3574.1. keepalive_mechanism (integer)
358
359   The keep-alive mechanism to use for WebSocket connections.
360
361Note
362
363   If nathelper is only being used for WebSocket connections then
364   nathelper NAT pinging is not required. If nathelper is used for
365   WebSocket connections and TCP/TLS aliasing/NAT-traversal then WebSocket
366   keep-alives are not required.
367
368     * 0 - no WebSocket keep-alives
369     * 1 - Ping WebSocket keep-alives
370     * 2 - Pong WebSocket keep-alives
371
372   Default value is 1.
373
374   Example 1.3. Set keepalive_mechanism parameter
375...
376modparam("websocket", "keepalive_mechanism", 0)
377...
378
3794.2. keepalive_timeout (integer)
380
381   The time (in seconds) after which to send a keep-alive on idle
382   WebSocket connections.
383
384   Default value is 180.
385
386   Example 1.4. Set keepalive_timeout parameter
387...
388modparam("websocket", "keepalive_timeout", 30)
389...
390
3914.3. keepalive_processes (integer)
392
393   The number of processes to start to perform WebSocket connection
394   keep-alives.
395
396   Default value is 1.
397
398   Example 1.5. Set keepalive_processes parameter
399...
400modparam("websocket", "keepalive_processes", 2)
401...
402
4034.4. keepalive_interval (integer)
404
405   The number of seconds between each keep-alive process run
406
407   Default value is 1.
408
409   Example 1.6. Set keepalive_interval parameter
410...
411modparam("websocket", "keepalive_interval", 2)
412...
413
4144.5. ping_application_data (string)
415
416   The application data to use in keep-alive Ping and Pong frames.
417
418   Default value is Kamailio Server: header content
419
420   Example 1.7. Set ping_application_data parameter
421...
422modparam("websocket", "ping_application_data", "WebSockets rock")
423...
424
4254.6. sub_protocols (integer)
426
427   A bitmap that allows you to control the sub-protocols supported by the
428   WebSocket server.
429     * 1 - sip (RFC 7118)
430     * 2 - msrp (RFC 7977) - the msrp module must be loaded before the
431       websocket module
432
433   Default value is 1 when msrp module is not loaded, 3 when msrp module
434   is loaded.
435
436   Example 1.8. Set sub_protocols parameter
437...
438modparam("websocket", "sub_protocols", 2)
439...
440
4414.7. cors_mode (integer)
442
443   This parameter lets you set the "Cross-origin resource sharing"
444   behaviour of the WebSocket server.
445     * 0 - Do not add an "Access-Control-Allow-Origin:" header to the
446       response accepting the WebSocket handshake.
447     * 1 - Add a "Access-Control-Allow-Origin: *" header to the response
448       accepting the WebSocket handshake.
449     * 2 - Add a "Access-Control-Allow-Origin:" header containing the same
450       body as the "Origin:" header from the request to the response
451       accepting the WebSocket handshake. If there is no "Origin:" header
452       in the request no header will be added to the response.
453
454   Default value is 0.
455
456   Example 1.9. Set cors_mode parameter
457...
458modparam("websocket", "cors_mode", 2)
459...
460
4614.8. verbose_list (int)
462
463   Allows to enable/disable the printing of debug messages when getting
464   the list of websocket connections. If enabled, it prints debug messages
465   every second for ping operations.
466
467   Default value is 0 (disabled).
468
469   Example 1.10. Set verbose_list parameter
470...
471modparam("websocket", "verbose_list", 1)
472...
473
4744.9. event_callback (str)
475
476   The name of the function in the kemi configuration file (embedded
477   scripting language such as Lua, Python, ...) to be executed instead of
478   event_route[...] blocks specific for websocket module.
479
480   The function has one string parameter, the value is the name of the
481   event_route block, respectively "websocket:closed".
482
483   Default value is 'empty' (no function is executed for events).
484
485   Example 1.11. Set event_callback parameter
486...
487modparam("websocket", "event_callback", "ksr_websocket_event")
488...
489-- event callback function implemented in Lua
490function ksr_websocket_event(evname)
491        KSR.info("===== websocket module triggered event: " .. evname .. "\n");
492        return 1;
493end
494...
495
4964.10. timer_interval (integer)
497
498   The number of seconds between each timer process run
499
500   Default value is 1.
501
502   Example 1.12. Set timer_intervalparameter
503...
504modparam("websocket", "timer_interval", 5)
505...
506
5074.11. rm_delay_interval (integer)
508
509   The number of seconds to wait before destroying the websocket
510   connection once put in remove state.
511
512   Default value is 5.
513
514   Example 1.13. Set rm_delay_intervalparameter
515...
516modparam("websocket", "rm_delay_interval", 2)
517...
518
5195. Functions
520
521   5.1. ws_handle_handshake()
522   5.2. ws_close([status, reason[, connection_id]])
523
5245.1.  ws_handle_handshake()
525
526   This function checks an HTTP GET request for the required headers and
527   values, and (if successful) upgrades the connection from HTTP to
528   WebSocket.
529
530   This function can be used from ANY_ROUTE (but will only work in
531   event_route[xhttp:request]).
532
533Note
534
535   This function returns 0, stopping all further processing of the
536   request, when there is a problem. Otherwise, it returns 1 (or positive
537   number) in case of success.
538
539   Example 1.14. ws_handle_handshake usage
540...
541ws_handle_handshake();
542...
543
5445.2.  ws_close([status, reason[, connection_id]])
545
546   This function closes a WebSocket connection.
547
548   The function returns -1 if there is an error and 1 if it succeeds.
549
550   The meaning of the parameters is as follows:
551     * status - an integer indicating the reason for closure.
552     * reason - a string describing the reason for closure.
553     * connection_id - the connection to close. If not specified the
554       connection the current message arrived on will be closed.
555
556Note
557
558   status and reason values SHOULD correspond to the definitions in
559   section 7.4 of RFC 6455. If these parameters are not used the defaults
560   of "1000" and "Normal closure" will be used.
561
562   This function can be used from ANY_ROUTE.
563
564   Example 1.15. ws_close usage
565...
566ws_close(4000, "Because I say so");
567...
568
5696. RPC Commands
570
571   6.1. ws.dump
572   6.2. ws.close
573   6.3. ws.ping
574   6.4. ws.pong
575   6.5. ws.disable
576   6.6. ws.enable
577
5786.1. ws.dump
579
580   Provides the details of the first 50 WebSocket connections.
581
582   Name: ws.dump
583
584   Parameters:
585     * order (optional) - “id_hash”, “used_desc”, or “used_asc”.
586
587Note
588
589   If no parameter is provided id_hash order is used.
590
591   RPC Command Usage:
592...
593kamcmd ws.dump used_asc
594...
595
5966.2. ws.close
597
598   Starts the close handshake for the specified WebSocket connection.
599
600   Name: ws.close
601
602   Parameters:
603     * id - WebSocket connection ID.
604
605   RPC Command Usage:
606...
607kamcmd ws.close: 1
608...
609
6106.3. ws.ping
611
612   Sends a Ping frame on the specified WebSocket connection.
613
614   Name: ws.ping
615
616   Parameters:
617     * id - WebSocket connection ID.
618
619   RPC Command Usage:
620...
621kamcmd ws.ping 1
622...
623
6246.4. ws.pong
625
626   Sends a Pong frame on the specified WebSocket connection.
627
628   Name: ws.pong
629
630   Parameters:
631     * id - WebSocket connection ID.
632
633   RPC Command Usage:
634...
635kamcmd ws.pong 1
636...
637
6386.5. ws.disable
639
640   Disables WebSockets preventing new connections from being established.
641
642   Name: ws.disable
643
644   Parameters: none
645
646   RPC Command Usage:
647...
648kamcmd ws.disable
649...
650
6516.6. ws.enable
652
653   Enables WebSockets allowing new connections to be established.
654
655Note
656
657   WebSockets are enabled at start-up.
658
659   Name: ws.enable
660
661   Parameters: none
662
663   RPC Command Format:
664...
665kamcmd ws.enable
666...
667
6687. Event routes
669
670   7.1. websocket:closed
671
6727.1.  websocket:closed
673
674   When defined, the module calls event_route[websocket:closed] when a
675   connection closes. The connection may be identified using the $si and
676   $sp pseudo-variables.
677
678   Example 1.16. event_route[websocket:closed] usage
679...
680event_route[websocket:closed] {
681        xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
682}
683...
684
6858. Exported Pseudo Variables
686
687   8.1. $ws_conid
688
6898.1. $ws_conid
690
691   Connection id of closed websocket connection. Can only be used in
692   websocket:closed event route.
693
694   Example 1.17. $ws_conid usage
695...
696event_route[websocket:closed] {
697        xlog("L_INFO", "WebSocket connection with id $ws_conid has closed\n");
698}
699...
700