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