123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- <?xml version="1.0" encoding='ISO-8859-1'?>
- <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
- "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
- <!-- Include general documentation entities -->
- <!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
- %docentities;
- ]>
- <!-- Module User's Guide -->
- <chapter>
-
- <title>&adminguide;</title>
-
- <section>
- <title>Overview</title>
- <para>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).</para>
- <para>The module supports WebSockets (ws) and secure WebSockets (wss)
- </para>
- </section>
- <section>
- <title>How it works</title>
- <section>
- <title>Initiating a connection</title>
- <para>A WebSocket connection is initiated with an HTTP GET. The
- <emphasis>xhttp</emphasis> module is used to handle this GET and
- call the <xref linkend="websocket.f.ws_handle_handshake"/> exported function.
- </para>
- <para><emphasis>event_route[xhttp:request]</emphasis> should perform
- some validation of the HTTP headers before calling
- <xref linkend="websocket.f.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
- <emphasis>Origin</emphasis> header (RFC 6454) to ensure a
- browser-based SIP UA or MSRP client has been downloaded from the
- correct location.</para>
- <example>
- <title>event_route[xhttp:request]</title>
- <programlisting><![CDATA[
- ...
- 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", "", "");
- }
- ...
- ]]></programlisting>
- </example>
- </section>
- <section>
- <title>SIP message routing</title>
- <para>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.
- </para>
- <para>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.</para>
- <para>The <emphasis>nathelper</emphasis> module functions
- (<emphasis>nat_uac_test()</emphasis>,
- <emphasis>fix_nated_register()</emphasis>,
- <emphasis>add_contact_alias()</emphasis>, and
- <emphasis>handle_ruri_alias()</emphasis>) and the Kamailio core
- <emphasis>force_rport()</emphasis> can be used to ensure correct
- routing of SIP WebSocket requests without using Outbound and Path.
- </para>
- <example>
- <title>WebSocket SIP Routing</title>
- <programlisting><![CDATA[
- ...
- 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();
- }
- }
- ...
- ]]></programlisting>
- </example>
- </section>
- <section>
- <title>MSRP message routing</title>
- <para>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).</para>
- </section>
- </section>
- <section>
- <title>Dependencies</title>
- <section>
- <title>&kamailio; Modules</title>
- <para>
- The following module must be loaded before this module:
- <itemizedlist>
- <listitem>
- <para><emphasis>sl</emphasis>.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The following modules are required to make proper use of this
- module:
- <itemizedlist>
- <listitem>
- <para><emphasis>nathelper</emphasis> or
- <emphasis>outbound</emphasis>.</para>
- </listitem>
- <listitem>
- <para><emphasis>xhttp</emphasis>.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The following module is required to use the secure WebSocket
- (wss) scheme:
- <itemizedlist>
- <listitem>
- <para><emphasis>tls</emphasis>.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The following module is required to support MSRP over
- WebSockets:
- <itemizedlist>
- <listitem>
- <para><emphasis>msrp</emphasis>.</para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- <section>
- <title>External Libraries or Applications</title>
- <para>
- The following libraries must be installed before running
- &kamailio; with this module loaded:
- <itemizedlist>
- <listitem>
- <para><emphasis>OpenSSL</emphasis>.</para>
- </listitem>
- <listitem>
- <para><emphasis>GNU libunistring</emphasis>.</para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- </section>
- <section>
- <title>Parameters</title>
- <section id="websocket.p.keepalive_mechanism">
- <title><varname>keepalive_mechanism</varname> (integer)</title>
- <para>The keep-alive mechanism to use for WebSocket connections.
- </para>
- <note><para>If <emphasis>nathelper</emphasis> is only being used
- for WebSocket connections then <emphasis>nathelper NAT
- pinging</emphasis> is not required. If
- <emphasis>nathelper</emphasis> is used for WebSocket connections
- and TCP/TLS aliasing/NAT-traversal then WebSocket keep-alives
- are not required.</para></note>
- <para>
- <itemizedlist>
- <listitem><para> 0 - no WebSocket keep-alives</para></listitem>
- <listitem><para> 1 - Ping WebSocket
- keep-alives</para></listitem>
- <listitem><para> 2 - Pong WebSocket
- keep-alives</para></listitem>
- </itemizedlist>
- </para>
- <para><emphasis>Default value is 1.</emphasis></para>
- <example>
- <title>Set <varname>keepalive_mechanism</varname>
- parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("websocket", "keepalive_mechanism", 0)
- ...
- </programlisting>
- </example>
- </section>
- <section id="websocket.p.keepalive_timeout">
- <title><varname>keepalive_timeout</varname> (integer)</title>
- <para>The time (in seconds) after which to send a keep-alive on
- idle WebSocket connections.</para>
- <para><emphasis>Default value is 180.</emphasis></para>
- <example>
- <title>Set <varname>keepalive_timeout</varname>
- parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("websocket", "keepalive_timeout", 30)
- ...
- </programlisting>
- </example>
- </section>
- <section id="websocket.p.keepalive.processes">
- <title><varname>keepalive_processes</varname> (integer)</title>
- <para>The number of processes to start to perform WebSocket
- connection keep-alives.</para>
- <para><emphasis>Default value is 1.</emphasis></para>
- <example>
- <title>Set <varname>keepalive_processes</varname>
- parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("websocket", "keepalive_processes", 2)
- ...
- </programlisting>
- </example>
- </section>
- <section id="websocket.p.keepalive_interval">
- <title><varname>keepalive_interval</varname> (integer)</title>
- <para>The number of seconds between each keep-alice process run
- </para>
- <para><emphasis>Default value is 1.</emphasis></para>
- <example>
- <title>Set <varname>keepalive_interval</varname>
- parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("websocket", "keepalive_interval", 2)
- ...
- </programlisting>
- </example>
- </section>
- <section id="websocket.p.ping_application_data">
- <title><varname>ping_application_data</varname> (string)</title>
- <para>The application data to use in keep-alive Ping and Pong
- frames.</para>
- <para><emphasis>Default value is &kamailio; Server: header
- content</emphasis></para>
- <example>
- <title>Set <varname>ping_application_data</varname>
- parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("websocket", "ping_application_data", "WebSockets rock")
- ...
- </programlisting>
- </example>
- </section>
- <section id="websocket.p.sub_protocols">
- <title><varname>sub_protocols</varname> (integer)</title>
- <para>A bitmap that allows you to control the sub-protocols
- supported by the WebSocket server.</para>
- <itemizedlist>
- <listitem><para>
- <emphasis>1</emphasis> - sip (draft-ietf-sipcore-sip-websocket)
- </para></listitem>
- <listitem><para>
- <emphasis>2</emphasis> - msrp (draft-pd-msrp-websocket) -
- msrp.so must be loaded before websocket.so
- </para></listitem>
- </itemizedlist>
- <para><emphasis>Default value is 1 when msrp.so is not loaded
- 3 when msrp.so is loaded.</emphasis></para>
- <example>
- <title>Set <varname>sub_protocols</varname>
- parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("websocket", "sub_protocols", 2)
- ...
- </programlisting>
- </example>
- </section>
- <section id="websocket.p.cors_mode">
- <title><varname>cors_mode</varname> (integer)</title>
- <para>This parameter lets you set the "Cross-origin
- resource sharing" behaviour of the WebSocket server.</para>
- <itemizedlist>
- <listitem><para>
- <emphasis>0</emphasis> - Do not add an
- "Access-Control-Allow-Origin:" header to the response
- accepting the WebSocket handshake.
- </para></listitem>
- <listitem><para>
- <emphasis>1</emphasis> - Add a
- "Access-Control-Allow-Origin: *" header to the
- response accepting the WebSocket handshake.
- </para></listitem>
- <listitem><para>
- <emphasis>2</emphasis> - 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.
- </para></listitem>
- </itemizedlist>
- <para><emphasis>Default value is 0.</emphasis></para>
- <example>
- <title>Set <varname>cors_mode</varname>
- parameter</title>
- <programlisting format="linespecific">
- ...
- modparam("websocket", "cors_mode", 2)
- ...
- </programlisting>
- </example>
- </section>
- </section>
- <section>
- <title>Functions</title>
- <section id="websocket.f.ws_handle_handshake">
- <title>
- <function moreinfo="none">ws_handle_handshake()</function>
- </title>
- <para>This function checks an HTTP GET request for the required
- headers and values, and (if successful) upgrades the connection
- from HTTP to WebSocket.</para>
- <para>This function can be used from ANY_ROUTE (but will only
- work in <emphasis>event_route[xhttp:request]</emphasis>).</para>
- <note><para>This function returns 0, stopping all further
- processing of the request, when there is a problem.</para></note>
- <example>
- <title><function>ws_handle_handshake</function> usage</title>
- <programlisting format="linespecific">
- ...
- ws_handle_handshake();
- ...
- </programlisting>
- </example>
- </section>
- <section id="websocket.f.ws_close">
- <title>
- <function moreinfo="none">ws_close([status,
- reason[, connection_id]])</function>
- </title>
- <para>This function closes a WebSocket connection.</para>
- <para>The function returns -1 if there is an error and 1 if
- it succeeds.</para>
- <para>The meaning of the parameters is as follows:</para>
- <itemizedlist>
- <listitem><para><emphasis>status</emphasis> - an
- integer indicating the reason for closure.</para>
- </listitem>
- <listitem><para><emphasis>reason</emphasis> - a
- string describing the reason for closure.</para>
- </listitem>
- <listitem><para><emphasis>connection_id</emphasis> - the
- connection to close. If not specified the connection the
- current message arrived on will be closed.</para>
- </listitem>
- </itemizedlist>
- <note><para><emphasis>status</emphasis> and
- <emphasis>reason</emphasis> 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.</para></note>
- <para>This function can be used from ANY_ROUTE.</para>
- <example>
- <title><function>ws_close</function> usage</title>
- <programlisting format="linespecific">
- ...
- ws_close(4000, "Because I say so");
- ...
- </programlisting>
- </example>
- </section>
- </section>
- <section>
- <title>MI Commands</title>
- <section id="websocket.m.ws.dump">
- <title><function moreinfo="none">ws.dump</function></title>
- <para>Provides the details of the first 50 WebSocket
- connections.</para>
- <para>Name: <emphasis>ws.dump</emphasis></para>
- <para>Parameters:</para>
- <itemizedlist>
- <listitem>
- <para>order (optional) -
- <quote>id_hash</quote>,
- <quote>used_desc</quote>, or
- <quote>used_asc</quote>.</para>
- </listitem>
- </itemizedlist>
- <note><para>If no parameter is provided id_hash order is
- used.</para></note>
- <para>MI FIFO Command Format:</para>
- <programlisting format="linespecific">
- :ws.dump:fifo_reply
- used_asc
- _empty_line_
- </programlisting>
- </section>
- <section id="websocket.m.ws.close">
- <title><function moreinfo="none">ws.close</function></title>
- <para>Starts the close handshake for the specified
- WebSocket connection.</para>
- <para>Name: <emphasis>ws.close</emphasis></para>
- <para>Parameters:</para>
- <itemizedlist>
- <listitem>
- <para>id - WebSocket connection ID.</para>
- </listitem>
- </itemizedlist>
- <para>MI FIFO Command Format:</para>
- <programlisting format="linespecific">
- :ws.close:fifo_reply
- 1
- _empty_line_
- </programlisting>
- </section>
- <section id="websocket.m.ping">
- <title><function moreinfo="none">ws.ping</function></title>
- <para>Sends a Ping frame on the specified WebSocket
- connection.</para>
- <para>Name: <emphasis>ws.ping</emphasis></para>
- <para>Parameters:</para>
- <itemizedlist>
- <listitem>
- <para>id - WebSocket connection ID.</para>
- </listitem>
- </itemizedlist>
- <para>MI FIFO Command Format:</para>
- <programlisting format="linespecific">
- :ws.ping:fifo_reply
- 1
- _empty_line_
- </programlisting>
- </section>
- <section id="websocket.m.ws.pong">
- <title><function moreinfo="none">ws.pong</function></title>
- <para>Sends a Pong frame on the specified WebSocket
- connection.</para>
- <para>Name: <emphasis>ws.pong</emphasis></para>
- <para>Parameters:</para>
- <itemizedlist>
- <listitem>
- <para>id - WebSocket connection ID.</para>
- </listitem>
- </itemizedlist>
- <para>MI FIFO Command Format:</para>
- <programlisting format="linespecific">
- :ws.pong:fifo_reply
- 1
- _empty_line_
- </programlisting>
- </section>
- <section id="websocket.m.ws.disable">
- <title><function moreinfo="none">ws.disable</function></title>
- <para>Disables WebSockets preventing new connections from
- being established.</para>
- <para>Name: <emphasis>ws.disable</emphasis></para>
- <para>Parameters: <emphasis>none</emphasis></para>
- <para>MI FIFO Command Format:</para>
- <programlisting format="linespecific">
- :ws.disable:fifo_reply
- _empty_line_
- </programlisting>
- </section>
- <section id="websocket.m.ws.enable">
- <title><function moreinfo="none">ws.enable</function></title>
- <para>Enables WebSockets allowing new connections to be
- established.</para>
- <note><para>WebSockets are enabled at start-up.</para></note>
- <para>Name: <emphasis>ws.enable</emphasis></para>
- <para>Parameters: <emphasis>none</emphasis></para>
- <para>MI FIFO Command Format:</para>
- <programlisting format="linespecific">
- :ws.enable:fifo_reply
- _empty_line_
- </programlisting>
- </section>
- </section>
- <section>
- <title>Event routes</title>
- <section id="websocket.e.closed">
- <title>
- <function moreinfo="none">websocket:closed</function>
- </title>
- <para>
- 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.
- </para>
- <example>
- <title><function moreinfo="none">event_route[websocket:closed]</function> usage</title>
- <programlisting format="linespecific">
- ...
- event_route[websocket:closed] {
- xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
- }
- ...
- </programlisting>
- </example>
- </section>
- </section>
- </chapter>
|