mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
597 lines
16 KiB
597 lines
16 KiB
WebSocket Module
|
|
|
|
Peter Dunkley
|
|
|
|
Crocodile RCS Ltd
|
|
|
|
Copyright © 2012-2013 Crocodile RCS Ltd
|
|
__________________________________________________________________
|
|
|
|
Table of Contents
|
|
|
|
1. Admin Guide
|
|
|
|
1. Overview
|
|
2. How it works
|
|
|
|
2.1. Initiating a connection
|
|
2.2. SIP message routing
|
|
2.3. MSRP message routing
|
|
|
|
3. Dependencies
|
|
|
|
3.1. Kamailio Modules
|
|
3.2. External Libraries or Applications
|
|
|
|
4. Parameters
|
|
|
|
4.1. keepalive_mechanism (integer)
|
|
4.2. keepalive_timeout (integer)
|
|
4.3. keepalive_processes (integer)
|
|
4.4. keepalive_interval (integer)
|
|
4.5. ping_application_data (string)
|
|
4.6. sub_protocols (integer)
|
|
4.7. cors_mode (integer)
|
|
|
|
5. Functions
|
|
|
|
5.1. ws_handle_handshake()
|
|
5.2. ws_close([status, reason[, connection_id]])
|
|
|
|
6. MI Commands
|
|
|
|
6.1. ws.dump
|
|
6.2. ws.close
|
|
6.3. ws.ping
|
|
6.4. ws.pong
|
|
6.5. ws.disable
|
|
6.6. ws.enable
|
|
|
|
7. Event routes
|
|
|
|
7.1. websocket:closed
|
|
|
|
List of Examples
|
|
|
|
1.1. event_route[xhttp:request]
|
|
1.2. WebSocket SIP Routing
|
|
1.3. Set keepalive_mechanism parameter
|
|
1.4. Set keepalive_timeout parameter
|
|
1.5. Set keepalive_processes parameter
|
|
1.6. Set keepalive_interval parameter
|
|
1.7. Set ping_application_data parameter
|
|
1.8. Set sub_protocols parameter
|
|
1.9. Set cors_mode parameter
|
|
1.10. ws_handle_handshake usage
|
|
1.11. ws_close usage
|
|
1.12. event_route[websocket:closed] usage
|
|
|
|
Chapter 1. Admin Guide
|
|
|
|
Table of Contents
|
|
|
|
1. Overview
|
|
2. How it works
|
|
|
|
2.1. Initiating a connection
|
|
2.2. SIP message routing
|
|
2.3. MSRP message routing
|
|
|
|
3. Dependencies
|
|
|
|
3.1. Kamailio Modules
|
|
3.2. External Libraries or Applications
|
|
|
|
4. Parameters
|
|
|
|
4.1. keepalive_mechanism (integer)
|
|
4.2. keepalive_timeout (integer)
|
|
4.3. keepalive_processes (integer)
|
|
4.4. keepalive_interval (integer)
|
|
4.5. ping_application_data (string)
|
|
4.6. sub_protocols (integer)
|
|
4.7. cors_mode (integer)
|
|
|
|
5. Functions
|
|
|
|
5.1. ws_handle_handshake()
|
|
5.2. ws_close([status, reason[, connection_id]])
|
|
|
|
6. MI Commands
|
|
|
|
6.1. ws.dump
|
|
6.2. ws.close
|
|
6.3. ws.ping
|
|
6.4. ws.pong
|
|
6.5. ws.disable
|
|
6.6. ws.enable
|
|
|
|
7. Event routes
|
|
|
|
7.1. websocket:closed
|
|
|
|
1. Overview
|
|
|
|
This module implements a WebSocket (RFC 6455) server and provides
|
|
connection establishment (handshaking), management (including
|
|
connection keep-alive), and framing for the SIP and MSRP WebSocket
|
|
sub-protocols (draft-ietf-sipcore-sip-websocket and
|
|
draft-pd-msrp-websocket).
|
|
|
|
The module supports WebSockets (ws) and secure WebSockets (wss)
|
|
|
|
2. How it works
|
|
|
|
2.1. Initiating a connection
|
|
2.2. SIP message routing
|
|
2.3. MSRP message routing
|
|
|
|
2.1. Initiating a connection
|
|
|
|
A WebSocket connection is initiated with an HTTP GET. The xhttp module
|
|
is used to handle this GET and call the Section 5.1, “
|
|
ws_handle_handshake() ” exported function.
|
|
|
|
event_route[xhttp:request] should perform some validation of the HTTP
|
|
headers before calling Section 5.1, “ ws_handle_handshake() ”. The
|
|
event_route can also be used to make sure the HTTP GET has the correct
|
|
URI, perform HTTP authentication on the WebSocket connection, and check
|
|
the Origin header (RFC 6454) to ensure a browser-based SIP UA or MSRP
|
|
client has been downloaded from the correct location.
|
|
|
|
Example 1.1. event_route[xhttp:request]
|
|
...
|
|
loadmodule "sl.so"
|
|
loadmodule "xhttp.so"
|
|
loadmodule "msrp.so" # Only required if using MSRP over WebSockets
|
|
loadmodule "websocket.so"
|
|
...
|
|
event_route[xhttp:request] {
|
|
set_reply_close();
|
|
set_reply_no_connect();
|
|
|
|
if ($Rp != 80
|
|
#!ifdef WITH_TLS
|
|
&& $Rp != 443
|
|
#!endif
|
|
) {
|
|
|
|
xlog("L_WARN", "HTTP request received on $Rp\n");
|
|
xhttp_reply("403", "Forbidden", "", "");
|
|
exit;
|
|
}
|
|
|
|
xlog("L_DBG", "HTTP Request Received\n");
|
|
|
|
if ($hdr(Upgrade)=~"websocket"
|
|
&& $hdr(Connection)=~"Upgrade"
|
|
&& $rm=~"GET") {
|
|
|
|
# Validate Host - make sure the client is using the correct
|
|
# alias for WebSockets
|
|
if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) {
|
|
xlog("L_WARN", "Bad host $hdr(Host)\n");
|
|
xhttp_reply("403", "Forbidden", "", "");
|
|
exit;
|
|
}
|
|
|
|
# Optional... validate Origin - make sure the client is from an
|
|
# authorised website. For example,
|
|
#
|
|
# if ($hdr(Origin) != "http://communicator.MY_DOMAIN"
|
|
# && $hdr(Origin) != "https://communicator.MY_DOMAIN") {
|
|
# xlog("L_WARN", "Unauthorised client $hdr(Origin)\n");
|
|
# xhttp_reply("403", "Forbidden", "", "");
|
|
# exit;
|
|
# }
|
|
|
|
# Optional... perform HTTP authentication
|
|
|
|
# ws_handle_handshake() exits (no further configuration file
|
|
# processing of the request) when complete.
|
|
if (ws_handle_handshake())
|
|
{
|
|
# Optional... cache some information about the
|
|
# successful connection
|
|
exit;
|
|
}
|
|
}
|
|
|
|
xhttp_reply("404", "Not found", "", "");
|
|
}
|
|
...
|
|
|
|
2.2. SIP message routing
|
|
|
|
SIP over WebSockets uses invalid URIs in routing headers (Contact:,
|
|
Record-Route:, and Via:) because a JavaScript stack running in a
|
|
browser has no way to determine the local address from which the
|
|
WebSocket connection is made. This means that the routing headers
|
|
cannot be used for request or response routing in the normal manner.
|
|
|
|
draft-ietf-sipcore-sip-websocket states that SIP WebSocket Clients and
|
|
the SIP registrar should implement Outbound (RFC 5626) and Path (RFC
|
|
3327) to enable requests and responses to be correctly routed. However,
|
|
Kamailio does not currently support Outbound and it may not be possible
|
|
to guarantee all SIP WebSocket clients will support Outbound and Path.
|
|
|
|
The nathelper module functions (nat_uac_test(), fix_nated_register(),
|
|
add_contact_alias(), and handle_ruri_alias()) and the Kamailio core
|
|
force_rport() can be used to ensure correct routing of SIP WebSocket
|
|
requests without using Outbound and Path.
|
|
|
|
Example 1.2. WebSocket SIP Routing
|
|
...
|
|
loadmodule "sl.so"
|
|
loadmodule "tm.so"
|
|
...
|
|
loadmodule "websocket.so"
|
|
...
|
|
request_route {
|
|
|
|
# per request initial checks
|
|
route(REQINIT);
|
|
|
|
if (nat_uac_test(64)) {
|
|
# Do NAT traversal stuff for requests from a WebSocket
|
|
# connection - even if it is not behind a NAT!
|
|
# This won't be needed in the future if Kamailio and the
|
|
# WebSocket client support Outbound and Path.
|
|
force_rport();
|
|
if (is_method("REGISTER"))
|
|
fix_nated_register();
|
|
else {
|
|
if (!add_contact_alias()) {
|
|
xlog("L_ERR", "Error aliasing contact <$ct>\n");
|
|
sl_send_reply("400", "Bad Request");
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!is_method("REGISTER"))
|
|
t_on_reply("WS_REPLY");
|
|
...
|
|
# Handle requests within SIP dialogs
|
|
route[WITHINDLG] {
|
|
if (has_totag()) {
|
|
# sequential request withing a dialog should
|
|
# take the path determined by record-routing
|
|
if (loose_route()) {
|
|
if ($du == "") {
|
|
if (!handle_ruri_alias()) {
|
|
xlog("L_ERR", "Bad alias <$ru>\n");
|
|
sl_send_reply("400", "Bad Request");
|
|
exit;
|
|
}
|
|
}
|
|
route(RELAY);
|
|
} else {
|
|
if ( is_method("ACK") ) {
|
|
...
|
|
onreply_route[WS_REPLY] {
|
|
if (nat_uac_test(64)) {
|
|
# Do NAT traversal stuff for replies to a WebSocket connection
|
|
# - even if it is not behind a NAT!
|
|
# This won't be needed in the future if Kamailio and the
|
|
# WebSocket client support Outbound and Path.
|
|
add_contact_alias();
|
|
}
|
|
}
|
|
...
|
|
|
|
2.3. MSRP message routing
|
|
|
|
MSRP over WebSocket clients create invalid local URIs for use in Path
|
|
headers (From-Path: and To-Path:) because a JavaScript stack running in
|
|
a browser has no way to determine the local address from which the
|
|
WebSocket connection is made. This is OK because MSRP over WebSocket
|
|
clients MUST use an MSRP relay and it is the MSRP relay's
|
|
responsibility to select the correct connection to the client based on
|
|
the MSRP URIs that it has created (and maintains a mapping for).
|
|
|
|
3. Dependencies
|
|
|
|
3.1. Kamailio Modules
|
|
3.2. External Libraries or Applications
|
|
|
|
3.1. Kamailio Modules
|
|
|
|
The following module must be loaded before this module:
|
|
* sl.
|
|
* tm.
|
|
|
|
The following modules are required to make proper use of this module:
|
|
* nathelper or outbound.
|
|
* xhttp.
|
|
|
|
The following module is required to use the secure WebSocket (wss)
|
|
scheme:
|
|
* tls.
|
|
|
|
The following module is required to support MSRP over WebSockets:
|
|
* msrp.
|
|
|
|
3.2. External Libraries or Applications
|
|
|
|
The following libraries must be installed before running Kamailio with
|
|
this module loaded:
|
|
* OpenSSL.
|
|
* GNU libunistring.
|
|
|
|
4. Parameters
|
|
|
|
4.1. keepalive_mechanism (integer)
|
|
4.2. keepalive_timeout (integer)
|
|
4.3. keepalive_processes (integer)
|
|
4.4. keepalive_interval (integer)
|
|
4.5. ping_application_data (string)
|
|
4.6. sub_protocols (integer)
|
|
4.7. cors_mode (integer)
|
|
|
|
4.1. keepalive_mechanism (integer)
|
|
|
|
The keep-alive mechanism to use for WebSocket connections.
|
|
|
|
Note
|
|
|
|
If nathelper is only being used for WebSocket connections then
|
|
nathelper NAT pinging is not required. If nathelper is used for
|
|
WebSocket connections and TCP/TLS aliasing/NAT-traversal then WebSocket
|
|
keep-alives are not required.
|
|
|
|
* 0 - no WebSocket keep-alives
|
|
* 1 - Ping WebSocket keep-alives
|
|
* 2 - Pong WebSocket keep-alives
|
|
|
|
Default value is 1.
|
|
|
|
Example 1.3. Set keepalive_mechanism parameter
|
|
...
|
|
modparam("websocket", "keepalive_mechanism", 0)
|
|
...
|
|
|
|
4.2. keepalive_timeout (integer)
|
|
|
|
The time (in seconds) after which to send a keep-alive on idle
|
|
WebSocket connections.
|
|
|
|
Default value is 180.
|
|
|
|
Example 1.4. Set keepalive_timeout parameter
|
|
...
|
|
modparam("websocket", "keepalive_timeout", 30)
|
|
...
|
|
|
|
4.3. keepalive_processes (integer)
|
|
|
|
The number of processes to start to perform WebSocket connection
|
|
keep-alives.
|
|
|
|
Default value is 1.
|
|
|
|
Example 1.5. Set keepalive_processes parameter
|
|
...
|
|
modparam("websocket", "keepalive_processes", 2)
|
|
...
|
|
|
|
4.4. keepalive_interval (integer)
|
|
|
|
The number of seconds between each keep-alice process run
|
|
|
|
Default value is 1.
|
|
|
|
Example 1.6. Set keepalive_interval parameter
|
|
...
|
|
modparam("websocket", "keepalive_interval", 2)
|
|
...
|
|
|
|
4.5. ping_application_data (string)
|
|
|
|
The application data to use in keep-alive Ping and Pong frames.
|
|
|
|
Default value is Kamailio Server: header content
|
|
|
|
Example 1.7. Set ping_application_data parameter
|
|
...
|
|
modparam("websocket", "ping_application_data", "WebSockets rock")
|
|
...
|
|
|
|
4.6. sub_protocols (integer)
|
|
|
|
A bitmap that allows you to control the sub-protocols supported by the
|
|
WebSocket server.
|
|
* 1 - sip (draft-ietf-sipcore-sip-websocket)
|
|
* 2 - msrp (draft-pd-msrp-websocket) - msrp.so must be loaded before
|
|
websocket.so
|
|
|
|
Default value is 1 when msrp.so is not loaded 3 when msrp.so is loaded.
|
|
|
|
Example 1.8. Set sub_protocols parameter
|
|
...
|
|
modparam("websocket", "sub_protocols", 2)
|
|
...
|
|
|
|
4.7. cors_mode (integer)
|
|
|
|
This parameter lets you set the "Cross-origin resource sharing"
|
|
behaviour of the WebSocket server.
|
|
* 0 - Do not add an "Access-Control-Allow-Origin:" header to the
|
|
response accepting the WebSocket handshake.
|
|
* 1 - Add a "Access-Control-Allow-Origin: *" header to the response
|
|
accepting the WebSocket handshake.
|
|
* 2 - Add a "Access-Control-Allow-Origin:" header containing the same
|
|
body as the "Origin:" header from the request to the response
|
|
accepting the WebSocket handshake. If there is no "Origin:" header
|
|
in the request no header will be added to the response.
|
|
|
|
Default value is 0.
|
|
|
|
Example 1.9. Set cors_mode parameter
|
|
...
|
|
modparam("websocket", "cors_mode", 2)
|
|
...
|
|
|
|
5. Functions
|
|
|
|
5.1. ws_handle_handshake()
|
|
5.2. ws_close([status, reason[, connection_id]])
|
|
|
|
5.1. ws_handle_handshake()
|
|
|
|
This function checks an HTTP GET request for the required headers and
|
|
values, and (if successful) upgrades the connection from HTTP to
|
|
WebSocket.
|
|
|
|
This function can be used from ANY_ROUTE (but will only work in
|
|
event_route[xhttp:request]).
|
|
|
|
Note
|
|
|
|
This function returns 0, stopping all further processing of the
|
|
request, when there is a problem.
|
|
|
|
Example 1.10. ws_handle_handshake usage
|
|
...
|
|
ws_handle_handshake();
|
|
...
|
|
|
|
5.2. ws_close([status, reason[, connection_id]])
|
|
|
|
This function closes a WebSocket connection.
|
|
|
|
The function returns -1 if there is an error and 1 if it succeeds.
|
|
|
|
The meaning of the parameters is as follows:
|
|
* status - an integer indicating the reason for closure.
|
|
* reason - a string describing the reason for closure.
|
|
* connection_id - the connection to close. If not specified the
|
|
connection the current message arrived on will be closed.
|
|
|
|
Note
|
|
|
|
status and reason values SHOULD correspond to the definitions in
|
|
section 7.4 of RFC 6455. If these parameters are not used the defaults
|
|
of "1000" and "Normal closure" will be used.
|
|
|
|
This function can be used from ANY_ROUTE.
|
|
|
|
Example 1.11. ws_close usage
|
|
...
|
|
ws_close(4000, "Because I say so");
|
|
...
|
|
|
|
6. MI Commands
|
|
|
|
6.1. ws.dump
|
|
6.2. ws.close
|
|
6.3. ws.ping
|
|
6.4. ws.pong
|
|
6.5. ws.disable
|
|
6.6. ws.enable
|
|
|
|
6.1. ws.dump
|
|
|
|
Provides the details of the first 50 WebSocket connections.
|
|
|
|
Name: ws.dump
|
|
|
|
Parameters:
|
|
* order (optional) - “id_hash”, “used_desc”, or “used_asc”.
|
|
|
|
Note
|
|
|
|
If no parameter is provided id_hash order is used.
|
|
|
|
MI FIFO Command Format:
|
|
:ws.dump:fifo_reply
|
|
used_asc
|
|
_empty_line_
|
|
|
|
6.2. ws.close
|
|
|
|
Starts the close handshake for the specified WebSocket connection.
|
|
|
|
Name: ws.close
|
|
|
|
Parameters:
|
|
* id - WebSocket connection ID.
|
|
|
|
MI FIFO Command Format:
|
|
:ws.close:fifo_reply
|
|
1
|
|
_empty_line_
|
|
|
|
6.3. ws.ping
|
|
|
|
Sends a Ping frame on the specified WebSocket connection.
|
|
|
|
Name: ws.ping
|
|
|
|
Parameters:
|
|
* id - WebSocket connection ID.
|
|
|
|
MI FIFO Command Format:
|
|
:ws.ping:fifo_reply
|
|
1
|
|
_empty_line_
|
|
|
|
6.4. ws.pong
|
|
|
|
Sends a Pong frame on the specified WebSocket connection.
|
|
|
|
Name: ws.pong
|
|
|
|
Parameters:
|
|
* id - WebSocket connection ID.
|
|
|
|
MI FIFO Command Format:
|
|
:ws.pong:fifo_reply
|
|
1
|
|
_empty_line_
|
|
|
|
6.5. ws.disable
|
|
|
|
Disables WebSockets preventing new connections from being established.
|
|
|
|
Name: ws.disable
|
|
|
|
Parameters: none
|
|
|
|
MI FIFO Command Format:
|
|
:ws.disable:fifo_reply
|
|
_empty_line_
|
|
|
|
6.6. ws.enable
|
|
|
|
Enables WebSockets allowing new connections to be established.
|
|
|
|
Note
|
|
|
|
WebSockets are enabled at start-up.
|
|
|
|
Name: ws.enable
|
|
|
|
Parameters: none
|
|
|
|
MI FIFO Command Format:
|
|
:ws.enable:fifo_reply
|
|
_empty_line_
|
|
|
|
7. Event routes
|
|
|
|
7.1. websocket:closed
|
|
|
|
7.1. websocket:closed
|
|
|
|
When defined, the module calls event_route[websocket:closed] when a
|
|
connection closes. The connection may be identified using the the $si
|
|
and $sp pseudo-variables.
|
|
|
|
Example 1.12. event_route[websocket:closed] usage
|
|
...
|
|
event_route[websocket:closed] {
|
|
xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
|
|
}
|
|
...
|