diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fa36c1b..0b9e273a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1512,6 +1512,10 @@ endif() if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_SERVER) install(FILES ${TEST_SERVER_DATA} DESTINATION share/libwebsockets-test-server + COMPONENT examples) + + install(FILES "${PROJECT_SOURCE_DIR}/test-server/private/index.html" + DESTINATION share/libwebsockets-test-server/private COMPONENT examples) if (LWS_WITH_CGI) set(CGI_TEST_SCRIPT "${PROJECT_SOURCE_DIR}/test-server/lws-cgi-test.sh") diff --git a/README.lwsws.md b/README.lwsws.md index 5ea4a2ab..da790bef 100644 --- a/README.lwsws.md +++ b/README.lwsws.md @@ -370,6 +370,36 @@ If you provide an extra mimetype entry Then any file is served, if the mimetype was not known then it is served without a Content-Type: header. +7) A mount can be protected by HTTP Basic Auth. This only makes sense when using +https, since otherwise the password can be sniffed. + +You can add a `basic-auth` entry on a mount like this` + +``` +{ + "mountpoint": "/basic-auth", + "origin": "file://_lws_ddir_/libwebsockets-test-server/private", + "basic-auth": "/var/www/balogins-private" +} +``` + +Before serving anything, lws will signal to the browser that a username / password +combination is required, and it will pop up a dialog. When the user has filled it +in, lwsws checks the user:password string against the text file named in the `basic-auth` +entry. + +The file should contain user:pass one per line + +``` +testuser:testpass +myuser:hispass +``` + +The file should be readable by lwsws, and for a little bit of extra security not +have a file suffix, so lws would reject to serve it even if it could find it on +a mount. + + @section lwswspl Lwsws Plugins Protcols and extensions may also be provided from "plugins", these are diff --git a/doc/html/functions.html b/doc/html/functions.html index f608df6c..e9f0570c 100644 --- a/doc/html/functions.html +++ b/doc/html/functions.html @@ -84,6 +84,9 @@ $(document).ready(function(){initNavTree('functions.html','');});
#include <lib/libwebsockets.h>
enum lws_client_connect_ssl_connection_flags - flags that may be used with struct lws_client_connect_info ssl_connection member to control if and how SSL checks apply to the client connection being created
-a new file is starting to arrive
client packet payload goes out on wire unmunged only useful for security tests since normal servers cannot decode the content if used
sent the session quit
![]() |
+
+ libwebsockets
+
+ Lightweight C library for HTML5 websockets
+ |
+
CMake is a multi-platform build tool that can generate build files for many different target platforms. See more info at http://www.cmake.org
+CMake also allows/recommends you to do "out of source"-builds, that is, the build files are separated from your sources, so there is no need to create elaborate clean scripts to get a clean source tree, instead you simply remove your build directory.
+Libwebsockets has been tested to build successfully on the following platforms with SSL support (both OpenSSL/wolfSSL):
+The project settings used by CMake to generate the platform specific build files is called CMakeLists.txt. CMake then uses one of its "Generators" to output a Visual Studio project or Make file for instance. To see a list of the available generators for your platform, simply run the "cmake" command.
+Note that by default OpenSSL will be linked, if you don't want SSL support see below on how to toggle compile options.
+build/
directory can have any name and be located anywhere on your filesystem, and that the argument
..` given to cmake is simply the source directory of libwebsockets containing the CMakeLists.txt project file. All examples in this file assumes you use ".."NOTE2: A common option you may want to give is to set the install path, same as –prefix= with autotools. It defaults to /usr/local. You can do this by, eg
NOTE3: On machines that want libraries in lib64, you can also add the following to the cmake line
NOTE4: If you are building against a non-distro OpenSSL (eg, in order to get access to ALPN support only in newer OpenSSL versions) the nice way to express that in one cmake command is eg,
When you run the test apps using non-distro SSL, you have to force them to use your libs, not the distro ones
To get it to build on latest openssl (2016-04-10) it needed this approach
NOTE5: To build with debug info and _DEBUG for lower priority debug messages compiled in, use
NOTE6 To build on Solaris the linker needs to be informed to use lib socket and libnsl, and only builds in 64bit mode.
+When changing cmake options, for some reason the only way to get it to see the changes sometimes is delete the contents of your build directory and do the cmake from scratch.
+Install OpenSSL binaries. http://www.openssl.org/related/binaries.html
+(NOTE: Preferably in the default location to make it easier for CMake to find them)
+NOTE2: Be sure that OPENSSL_CONF environment variable is defined and points at <OpenSSL install="" location>="">.cfg
+(NOTE: There is also a cmake-gui available on Windows if you prefer that)
+NOTE2: See this link to find out the version number corresponding to your Visual Studio edition: http://superuser.com/a/194065
+<path to src>/build
directory, which can be used to build.Install MinGW: http://sourceforge.net/projects/mingw/files
+(NOTE: Preferably in the default location C:)
+Fix up MinGW headers
+a) Add the following lines to C:.h:
b) Create C:.h and copy and paste the content from following link into it:
+http://wine-unstable.sourcearchive.com/documentation/1.1.32/mstcpip_8h-source.html
+Install OpenSSL binaries. http://www.openssl.org/related/binaries.html
+(NOTE: Preferably in the default location to make it easier for CMake to find them)
+NOTE2: Be sure that OPENSSL_CONF environment variable is defined and points at <OpenSSL install="" location>="">.cfg
+Generate the build files (default is Make files) using MSYS shell:
(NOTE: The build/
directory can have any name and be located anywhere on your filesystem, and that the argument
..` given to cmake is simply the source directory of libwebsockets containing the CMakeLists.txt project file. All examples in this file assumes you use "..")
NOTE2: To generate build files allowing to create libwebsockets binaries with debug information set the CMAKE_BUILD_TYPE flag to DEBUG:
MBED3 is a non-posix embedded OS targeted on Cortex M class chips.
+ +It's quite unlike any other Posixy platform since the OS is linked statically in with lws to form one binary.
+At the minute server-only is supported and due to bugs in mbed3 network support, the port is of alpha quality. However it can serve the test html, favicon.ico and logo png and may be able to make ws connections. The binary for that including the OS, test app, lws and all the assets is only 117KB.
+0) Today mbed3 only properly works on FRDM K64F $35 Freescale Dev Board with 1MB Flash, 256KB SRAM and Ethernet.
+ +1) Get a working mbed3 environment with arm-none-eabi-cs toolchain (available in Fedora, Ubuntu and other distros)
+2) Confirm you can build things using yotta by following the getting started guide here
+https://docs.mbed.com/docs/getting-started-mbed-os/en/latest/
+3)
+git clone https://github.com/warmcat/lws-test-server
+and cd into it
+4) mkdir -p yotta_modules ; cd yotta_modules
+5) git clone https://github.com/warmcat/libwebsockets ; mv libwebsockets websockets ; cd ..
+6) yotta target frdm-k64f-gcc
+7) yotta install
+8) yotta build
+To set compile time flags you can either use one of the CMake gui applications or do it via the command line.
+To list available options (omit the H if you don't want the help text):
cmake -LH .. +
Then to set an option and build (for example turn off SSL support):
cmake -DLWS_WITH_SSL=0 .. +
or cmake -DLWS_WITH_SSL:BOOL=OFF ..
+If you have a curses-enabled build you simply type: (not all packages include this, my debian install does not for example).
ccmake +
On windows CMake comes with a gui application: Start -> Programs -> CMake -> CMake (cmake-gui)
+wolfSSL/CyaSSL is a lightweight SSL library targeted at embedded systems: https://www.wolfssl.com/wolfSSL/Products-wolfssl.html
+It contains a OpenSSL compatibility layer which makes it possible to pretty much link to it instead of OpenSSL, giving a much smaller footprint.
+NOTE: wolfssl needs to be compiled using the --enable-opensslextra
flag for this to work.
NOTE: On windows use the .lib file extension for LWS_WOLFSSL_LIBRARIES
instead.
NOTE: On windows use the .lib file extension for LWS_CYASSL_LIBRARIES
instead.
The directory ./plugin-standalone/ shows how easy it is to create plugins outside of lws itself. First build lws itself with -DLWS_WITH_PLUGINS, then use the same flow to build the standalone plugin
if you changed the default plugin directory when you built lws, you must also give the same arguments to cmake here (eg, -DCMAKE_INSTALL_PREFIX:PATH=/usr/something/else...
)
Otherwise if you run lwsws or libwebsockets-test-server-v2.0, it will now find the additional plugin "libprotocol_example_standalone.so"
If you have multiple vhosts, you must enable plugins at the vhost additionally, discovered plugins are not enabled automatically for security reasons. You do this using info->pvo or for lwsws, in the JSON config.
+You must have built and be running lws against a version of openssl that has ALPN / NPN. Most distros still have older versions. You'll know it's right by seeing
at lws startup.
+For non-SSL HTTP2.0 upgrade
For SSL / ALPN HTTP2.0 upgrade
To enable cross-compiling libwebsockets using CMake you need to create a "Toolchain file" that you supply to CMake when generating your build files. CMake will then use the cross compilers and build paths specified in this file to look for dependencies and such.
+Libwebsockets includes an example toolchain file cross-arm-linux-gnueabihf.cmake you can use as a starting point.
+The commandline to configure for cross with this would look like
The example shows how to build with no external cross lib dependencies, you need to provide the cross libraries otherwise.
+NOTE: start from an EMPTY build directory if you had a non-cross build in there before the settings will be cached and your changes ignored.
+Additional information on cross compilation with CMake: http://www.vtk.org/Wiki/CMake_Cross_Compiling
+Embedded server-only configuration without extensions (ie, no compression on websocket connections), but with full v13 websocket features and http server, built on ARM Cortex-A9:
+Update at 8dac94d (2013-02-18)
This shows the impact of the major configuration with/without options at 13ba5bbc633ea962d46d using Ubuntu ARM on a PandaBoard ES.
+These are accounting for static allocations from the library elf, there are additional dynamic allocations via malloc. These are a bit old now but give the right idea for relative "expense" of features.
+Static allocations, ARM9
+.text | .rodata | .data | .bss | |
---|---|---|---|---|
All (no without) | 35024 | 9940 | 336 | 4104 |
without client | 25684 | 7144 | 336 | 4104 |
without client, exts | 21652 | 6288 | 288 | 4104 |
without client, exts, debug[1] | 19756 | 3768 | 288 | 4104 |
without server | 30304 | 8160 | 336 | 4104 |
without server, exts | 25382 | 7204 | 288 | 4104 |
without server, exts, debug[1] | 23712 | 4256 | 288 | 4104 |
[1] --disable-debug
only removes messages below lwsl_notice
. Since that is the default logging level the impact is not noticeable, error, warn and notice logs are all still there.
[2] 1024
fd per process is the default limit (set by ulimit) in at least Fedora and Ubuntu. You can make significant savings tailoring this to actual expected peak fds, ie, at a limit of 20
, context creation allocation reduces to 4432 + 240 = 4672
)
[3] known header content is freed after connection establishment
+![]() |
+
+ libwebsockets
+
+ Lightweight C library for HTML5 websockets
+ |
+
There's a helper api lws_daemonize
built by default that does everything you need to daemonize well, including creating a lock file. If you're making what's basically a daemon, just call this early in your init to fork to a headless background process and exit the starting process.
Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your daemon is headless, so you'll need to sort out alternative logging, by, eg, syslog.
+The maximum number of connections the library can deal with is decided when it starts by querying the OS to find out how many file descriptors it is allowed to open (1024 on Fedora for example). It then allocates arrays that allow up to that many connections, minus whatever other file descriptors are in use by the user code.
+If you want to restrict that allocation, or increase it, you can use ulimit or similar to change the available number of file descriptors, and when restarted libwebsockets will adapt accordingly.
+Libwebsockets works in a serialized event loop, in a single thread.
+Directly performing websocket actions from other threads is not allowed. Aside from the internal data being inconsistent in forked()
processes, the scope of a wsi
(struct websocket
) can end at any time during service with the socket closing and the wsi
freed.
Websocket write activities should only take place in the LWS_CALLBACK_SERVER_WRITEABLE
callback as described below.
[This network-programming necessity to link the issue of new data to the peer taking the previous data is not obvious to all users so let's repeat that in other words:
+***ONLY DO LWS_WRITE FROM THE WRITEABLE CALLBACK***
+There is another network-programming truism that surprises some people which is if the sink for the data cannot accept more:
+***YOU MUST PERFORM RX FLOW CONTROL***
+See the mirror protocol implementations for example code.
+Only live connections appear in the user callbacks, so this removes any possibility of trying to used closed and freed wsis.
+If you need to service other socket or file descriptors as well as the websocket ones, you can combine them together with the websocket ones in one poll loop, see "External Polling Loop support" below, and still do it all in one thread / process context.
+If you insist on trying to use it from multiple threads, take special care if you might simultaneously create more than one context from different threads.
+SSL_library_init() is called from the context create api and it also is not reentrant. So at least create the contexts sequentially.
+You should only send data on a websocket connection from the user callback LWS_CALLBACK_SERVER_WRITEABLE
(or LWS_CALLBACK_CLIENT_WRITEABLE
for clients).
If you want to send something, do not just send it but request a callback when the socket is writeable using
+lws_callback_on_writable(context, wsi)
for a specific wsi
, orlws_callback_on_writable_all_protocol(protocol)
for all connections using that protocol to get a callback when next writeable.Usually you will get called back immediately next time around the service loop, but if your peer is slow or temporarily inactive the callback will be delayed accordingly. Generating what to write and sending it should be done in the ...WRITEABLE callback.
+See the test server code for an example of how to do this.
+Libwebsockets may generate additional LWS_CALLBACK_CLIENT_WRITEABLE
events if it met network conditions where it had to buffer your send data internally.
So your code for LWS_CALLBACK_CLIENT_WRITEABLE
needs to own the decision about what to send, it can't assume that just because the writeable callback came it really is time to send something.
It's quite possible you get an 'extra' writeable callback at any time and just need to return 0
and wait for the expected callback later.
When you want to close a connection, you do it by returning -1
from a callback for that connection.
You can provoke a callback by calling lws_callback_on_writable
on the wsi, then notice in the callback you want to close it and just return -1. But usually, the decision to close is made in a callback already and returning -1 is simple.
If the socket knows the connection is dead, because the peer closed or there was an affirmitive network error like a FIN coming, then libwebsockets will take care of closing the connection automatically.
+If you have a silently dead connection, it's possible to enter a state where the send pipe on the connection is choked but no ack will ever come, so the dead connection will never become writeable. To cover that, you can use TCP keepalives (see later in this document) or pings.
+To support fragmented messages you need to check for the final frame of a message with lws_is_final_fragment
. This check can be combined with libwebsockets_remaining_packet_payload
to gather the whole contents of a message, eg:
The test app libwebsockets-test-fraggle sources also show how to deal with fragmented messages.
+Also using lws_set_log_level
api you may provide a custom callback to actually emit the log string. By default, this points to an internal emit function that sends to stderr. Setting it to NULL
leaves it as it is instead.
A helper function lwsl_emit_syslog()
is exported from the library to simplify logging to syslog. You still need to use setlogmask
, openlog
and closelog
in your user code.
The logging apis are made available for user code.
+lwsl_err(...)
lwsl_warn(...)
lwsl_notice(...)
lwsl_info(...)
lwsl_debug(...)
The difference between notice and info is that notice will be logged by default whereas info is ignored by default.
+If you are not building with _DEBUG defined, ie, without this
+then log levels below notice do not actually get compiled in.
+libwebsockets maintains an internal poll()
array for all of its sockets, but you can instead integrate the sockets into an external polling array. That's needed if libwebsockets will cooperate with an existing poll array maintained by another server.
Four callbacks LWS_CALLBACK_ADD_POLL_FD
, LWS_CALLBACK_DEL_POLL_FD
, LWS_CALLBACK_SET_MODE_POLL_FD
and LWS_CALLBACK_CLEAR_MODE_POLL_FD
appear in the callback for protocol 0 and allow interface code to manage socket descriptors in other poll loops.
You can pass all pollfds that need service to lws_service_fd()
, even if the socket or file does not belong to libwebsockets it is safe.
If libwebsocket handled it, it zeros the pollfd revents
field before returning. So you can let libwebsockets try and if pollfd->revents
is nonzero on return, you know it needs handling by your code.
Also note that when integrating a foreign event loop like libev or libuv where it doesn't natively use poll() semantics, and you must return a fake pollfd reflecting the real event:
+The library is ready for use by C++ apps. You can get started quickly by copying the test server
+and building it in C++ like this
+INSTALL_DATADIR
is only needed because the test server uses it as shipped, if you remove the references to it in your app you don't need to define it on the g++ line either.
HTTP Header information is managed by a pool of "ah" structs. These are a limited resource so there is pressure to free the headers and return the ah to the pool for reuse.
+For that reason header information on HTTP connections that get upgraded to websockets is lost after the ESTABLISHED callback. Anything important that isn't processed by user code before then should be copied out for later.
+For HTTP connections that don't upgrade, header info remains available the whole time.
+It is possible for a connection which is not being used to send to die silently somewhere between the peer and the side not sending. In this case by default TCP will just not report anything and you will never get any more incoming data or sign the link is dead until you try to send.
+To deal with getting a notification of that situation, you can choose to enable TCP keepalives on all libwebsockets sockets, when you create the context.
+To enable keepalive, set the ka_time member of the context creation parameter struct to a nonzero value (in seconds) at context creation time. You should also fill ka_probes and ka_interval in that case.
+With keepalive enabled, the TCP layer will send control packets that should stimulate a response from the peer without affecting link traffic. If the response is not coming, the socket will announce an error at poll()
forcing a close.
Note that BSDs don't support keepalive time / probes / interval per-socket like Linux does. On those systems you can enable keepalive by a nonzero value in ka_time
, but the systemwide kernel settings for the time / probes/ interval are used, regardless of what nonzero value is in ka_time
.
There's a member ssl_cipher_list
in the lws_context_creation_info
struct which allows the user code to restrict the possible cipher selection at context-creation time.
You might want to look into that to stop the ssl peers selecting a cipher which is too computationally expensive. To use it, point it to a string like
`"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"` +
if left NULL
, then the "DEFAULT" set of ciphers are all possible to select.
You can also set it to "ALL"
to allow everything (including insecure ciphers).
When you call lws_client_connect_info(..)
and get a wsi
back, it does not mean your connection is active. It just means it started trying to connect.
Your client connection is actually active only when you receive LWS_CALLBACK_CLIENT_ESTABLISHED
for it.
There's a 5 second timeout for the connection, and it may give up or die for other reasons, if any of that happens you'll get a LWS_CALLBACK_CLIENT_CONNECTION_ERROR
callback on protocol 0 instead for the wsi
.
After attempting the connection and getting back a non-NULL
wsi
you should loop calling lws_service()
until one of the above callbacks occurs.
As usual, see test-client.c for example code.
+Notice that the client connection api tries to progress the connection somewhat before returning. That means it's possible to get callbacks like CONNECTION_ERROR on the new connection before your user code had a chance to get the wsi returned to identify it (in fact if the connection did fail early, NULL will be returned instead of the wsi anyway).
+To avoid that problem, you can fill in pwsi
in the client connection info struct to point to a struct lws that get filled in early by the client connection api with the related wsi. You can then check for that in the callback to confirm the identity of the failing client connection.
lws now exposes his internal platform file abstraction in a way that can be both used by user code to make it platform-agnostic, and be overridden or subclassed by user code. This allows things like handling the URI "directory +space" as a virtual filesystem that may or may not be backed by a regular filesystem. One example use is serving files from inside large compressed archive storage without having to unpack anything except the file being requested.
+The test server shows how to use it, basically the platform-specific part of lws prepares a file operations structure that lives in the lws context.
+The user code can get a pointer to the file operations struct
+and then can use helpers to also leverage these platform-independent file handling apis
+The user code can also override or subclass the file operations, to either wrap or replace them. An example is shown in test server.
+ECDH Certs are now supported. Enable the CMake option
cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1 +
and the info->options flag
LWS_SERVER_OPTION_SSL_ECDH +
to build in support and select it at runtime.
+SMP support is integrated into LWS without any internal threading. It's very simple to use, libwebsockets-test-server-pthread shows how to do it, use -j <n> argument there to control the number of service threads up to 32.
+Two new members are added to the info struct
unsigned int count_threads; + unsigned int fd_limit_per_thread; +
leave them at the default 0 to get the normal singlethreaded service loop.
+Set count_threads to n to tell lws you will have n simultaneous service threads operating on the context.
+There is still a single listen socket on one port, no matter how many service threads.
+When a connection is made, it is accepted by the service thread with the least connections active to perform load balancing.
+The user code is responsible for spawning n threads running the service loop associated to a specific tsi (Thread Service Index, 0 .. n - 1). See the libwebsockets-test-server-pthread for how to do.
+If you leave fd_limit_per_thread at 0, then the process limit of fds is shared between the service threads; if you process was allowed 1024 fds overall then each thread is limited to 1024 / n.
+You can set fd_limit_per_thread to a nonzero number to control this manually, eg the overall supported fd limit is less than the process allowance.
+You can control the context basic data allocation for multithreading from Cmake using -DLWS_MAX_SMP=, if not given it's set to 32. The serv_buf allocation for the threads (currently 4096) is made at runtime only for active threads.
+Because lws will limit the requested number of actual threads supported according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to discover how many threads were actually allowed when the context was created.
+It's required to implement locking in the user code in the same way that libwebsockets-test-server-pthread does it, for the FD locking callbacks.
+There is no knowledge or dependency in lws itself about pthreads. How the locking is implemented is entirely up to the user code.
+You can select either or both
-DLWS_WITH_LIBEV=1 + -DLWS_WITH_LIBUV=1 +
at cmake configure-time. The user application may use one of the context init options flags
LWS_SERVER_OPTION_LIBEV + LWS_SERVER_OPTION_LIBUV +
to indicate it will use either of the event libraries.
+User code may set per-connection extension options now, using a new api lws_set_extension_option()
.
This should be called from the ESTABLISHED callback like this
If the extension is not active (missing or not negotiated for the connection, or extensions are disabled on the library) the call is just returns -1. Otherwise the connection's extension has its named option changed.
+The extension may decide to alter or disallow the change, in the example above permessage-deflate restricts the size of his rx output buffer also considering the protocol's rx_buf_size member.
+You may open a generic http client connection using the same struct lws_client_connect_info used to create client ws[s] connections.
+To stay in http[s], set the optional info member "method" to point to the string "GET" instead of the default NULL.
+After the server headers are processed, when payload from the server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP will be made.
+You can choose whether to process the data immediately, or queue a callback when an outgoing socket is writeable to provide flow control, and process the data in the writable callback.
+Either way you use the api lws_http_client_read()
to access the data, eg
Notice that if you will use SSL client connections on a vhost, you must prepare the client SSL context for the vhost after creating the vhost, since this is not normally done if the vhost was set up to listen / serve. Call the api lws_init_vhost_client_ssl() to also allow client SSL on the vhost.
+If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create your context, it won't create a default vhost using the info struct members for compatibility. Instead you can call lws_create_vhost() afterwards to attach one or more vhosts manually.
+lws_create_vhost() uses the same info struct as lws_create_context(), it ignores members related to context and uses the ones meaningful for vhost (marked with VH in libwebsockets.h).
+When you attach the vhost, if the vhost's port already has a listen socket then both vhosts share it and use SNI (is SSL in use) or the Host: header from the client to select the right one. Or if no other vhost already listening the a new listen socket is created.
+There are some new members but mainly it's stuff you used to set at context creation time.
+LWS first strips any trailing :port number.
+Then it tries to find an exact name match for a vhost listening on the correct port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a vhost named abc.com that is listening on port 1234.
+If there is no exact match, lws will consider wildcard matches, for example if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will accept a vhost "abc.com" listening on port 1234. If there was a better, exact, match, it will have been chosen in preference to this.
+Connections with SSL will still have the client go on to check the certificate allows wildcards and error out if not.
+The last argument to lws_create_vhost() lets you associate a linked list of lws_http_mount structures with that vhost's URL 'namespace', in a similar way that unix lets you mount filesystems into areas of your / filesystem how you like and deal with the contents transparently.
+The last mount structure should have a NULL mount_next, otherwise it should point to the 'next' mount structure in your list.
+Both the mount structures and the strings must persist until the context is destroyed, since they are not copied but used in place.
+.origin_protocol
should be one of
The feature provided by CALLBACK type mounts is binding a part of the URL namespace to a named protocol callback handler.
+This allows protocol plugins to handle areas of the URL namespace. For example in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin providing "protocol-post-demo" like this
+Client access to /formtest[anything] will be passed to the callback registered with the named protocol, which in this case is provided by a protocol plugin.
+Access by all methods, eg, GET and POST are handled by the callback.
+protocol-post-demo deals with accepting and responding to the html form that is in the test server HTML.
+When a connection accesses a URL related to a CALLBACK type mount, the connection protocol is changed until the next access on the connection to a URL outside the same CALLBACK mount area. User space on the connection is arranged to be the size of the new protocol user space allocation as given in the protocol struct.
+This allocation is only deleted / replaced when the connection accesses a URL region with a different protocol (or the default protocols[0] if no CALLBACK area matches it).
+The lws test plugins' html provides useful feedback on the webpage about if it is still connected to the server, by greying out the page if not. You can also add this to your own html easily
+include lws-common.js from your HEAD section
+<script src="/lws-common.js"></script>
+dim the page during initialization, in a script section on your page
+lws_gray_out(true,{'zindex':'499'});
+in your ws onOpen(), remove the dimming
+lws_gray_out(false);
+in your ws onClose(), reapply the dimming
+lws_gray_out(true,{'zindex':'499'});
+![]() |
+
+ libwebsockets
+
+ Lightweight C library for HTML5 websockets
+ |
+
Enable at CMake with -DLWS_WITH_GENERIC_SESSIONS=1
+This also needs sqlite3 (libsqlite3-dev or similar package)
+The generic-sessions protocol plugin provides cookie-based login authentication for lws web and ws connections.
+The plugin handles everything about generic account registration, email verification, lost password, account deletion, and other generic account management.
+Other code, in another eg, ws protocol handler, only needs very high-level state information from generic-sessions, ie, which user the client is authenticated as. Everything underneath is managed in generic-sessions.
+Only three steps are needed to integrate lwsgs in your HTML.
+1) lwsgs HTML UI is bundled with the javascript it uses in lwsgs.js
, so import that script file in your head section
2) define an empty div of id "lwsgs" somewhere
+3) Call lwsgs_initial() in your page
+That's it. An example is below
+When the protocol is initialized, it gets per-vhost information from the config, such as where the sqlite3 databases are to be stored. The admin username and sha-1 of the admin password are also taken from here.
+In the mounts using protocol-generic-sessions, a cookie is maintained against any requests; if no cookie was active on the initial request a new session is created with no attached user.
+So there should always be an active session after any transactions with the server.
+In the example html going to the mount /lwsgs loads a login / register page as the default.
+The <form> in the login page contains 'next url' hidden inputs that let the html 'program' where the form handler will go after a successful admin login, a successful user login and a failed login.
+After a successful login, the sqlite record at the server for the current session is updated to have the logged-in username associated with it.
+"auth-mask" defines the authorization sector bits that must be enabled on the session to gain access.
+"auth-mask" 0 is the default.
+Note that the name of the real application protocol that uses generic-sessions is used, not generic-sessions itself.
+The vhost configures the storage dir, admin credentials and session cookie lifetimes:
+The email- related settings control generation of automatic emails for registration and forgotten password.
+email-from
: The email address automatic emails are sent fromemail-smtp-ip
: Normally 127.0.0.1, if you have a suitable server on port 25 on your lan you can use this instead here.email-expire
: Seconds that links sent in email will work before being deletedemail-helo
: HELO to use when communicating with your SMTP serveremail-contact-person
: mentioned in the automatic emails as a human who can answer questionsemail-confirm-url-base
: the URL to start links with in the emails, so the recipient can get back to the web serverThe real protocol that makes use of generic-sessions must also be listed and any configuration it needs given
+Notice the real application uses his own sqlite db, no details about how generic-sessions works or how it stores data are available to it.
+You can also define a per-vhost confounder shown in the example above, used when aggregating the password with the salt when it is hashed. Any attacker will also need to get the confounder along with the database, which you can make harder by making the config dir only eneterable / readable by root.
+You will have to prepare the db directory so it's suitable for the lwsws user to use, that usually means apache, eg
+lwsgs will can send emails by talking to an SMTP server on localhost:25. That will usually be sendmail or postfix, you should confirm that works first by itself using the mail
application to send on it.
lwsgs has been tested on stock Fedora sendmail and postfix.
+lwsgs is designed to provide sessions and accounts in a standalone and generic way.
+But it's not useful by itself, there will always be the actual application who wants to make use of generic-sessions features.
+We provide the "messageboard" plugin as an example of how to integrate with your actual application protocol.
+The basic approach is the 'real' protocol handler (usually a plugin itself) subclasses the generic-sessions plugin and calls through to it by default.
+The "real" protocol handler entirely deals with ws-related stuff itself, since generic-sessions does not use ws. But for
+the "real" protocol handler checks if it recognizes the activity (eg, his own POST form URL) and if not, passes stuff through to the generic-sessions protocol callback to handle it. To simplify matters the real protocol can just pass through any unhandled messages to generic-sessions.
+The "real" protocol can get a pointer to generic-sessions protocol on the same vhost using
+The "real" protocol must also arrange generic-sessions per_session_data in his own per-session allocation. To allow keeping generic-sessions opaque, the real protocol must allocate that space at runtime, using the pss size the generic-sessions protocol struct exposes
+The allocation reserved for generic-sessions is then used as user_space when the real protocol calls through to the generic-sessions callback
+In that way the "real" protocol can subclass generic-sessions functionality.
+To ease management of these secondary allocations, there are callbacks that occur when a wsi binds to a protocol and when the binding is dropped. These should be used to malloc and free and kind of per-connection secondary allocations.
+#section gsapsib Getting session-specific information from another protocol
+At least at the time when someone tries to upgrade an http(s) connection to ws(s) with your real protocol, it is necessary to confirm the cookie the http(s) connection has with generic-sessions and find out his username and other info.
+Generic sessions lets another protocol check it again by calling his callback, and lws itself provides a generic session info struct to pass the related data
+After the call to generic-sessions, the results can be
+the real protocol can use this to reject attempts to open ws connections from http connections that are not authenticated; afterwards there's no need to check the ws connection auth status again.
+![]() |
+
+ libwebsockets
+
+ Lightweight C library for HTML5 websockets
+ |
+
Generic-table is a JSON schema and client-side JS file that makes it easy to display live, table structured HTML over a ws link.
+An example plugin and index.html using it are provided, but lwsgt itself doesn't have its own plugin, it's just a JSON schema and client-side JS that other plugins can use to simplify displaying live, table-based data without having to reinvent the wheel each time.
+The ws protocol sends JSON describing the table, and then JSON updating the table contents when it chooses, the brower table is updated automatically, live.
+Enable the demo plugin at CMake with -DLWS_WITH_PLUGINS=1
+You can skip this but the result will be less beautiful until some CSS is provided.
+lwsgt JS will put its content there.
+In the callback, you can recover the ws object by window[gt].lwsgt_ws
.
To instantiate the ws link and lwsgt instance, your HTML must call a lwsgt constructor for each region on the page managed by lwsgt.
+var myvar = new lwsgt_initial(title, ws_protocol, div_id, click_cb, myvar);
All of the arguments are strings.
+Parameter | Description |
---|---|
title | Title string to go above the table |
ws_protocol | Protocol name string to use when making ws connection |
div_id | HTML id of div to fill with content |
click_cb | Callback function name string to handle clickable links |
myvar | Name of var used to hold this instantiation globally |
Note "myvar" is needed so it can be passed to the click handling callback.
+When a clickable link produced by lwsgt is clicked, the function named in the click_cb parameter to lwsgt_initial is called.
+That function is expected to take four parameters, eg
+function lwsgt_dir_click(gt, u, col, row)
Parameter | Description |
---|---|
gt | Name of global var holding this lwsgt context (ie, myvar) |
u | Link "url" string |
col | Table column number link is from |
row | Table row number link is from |
When the ws connection is established, the protocol should send a JSON message describing the table columns. For example
+When a view is hierarchical, it's useful to provide a "path" with links back in the "path", known as "breadcrumbs".
+Elements before the last one should provide a "url" member as well as the displayable name, which is used to create the link destination.
+The last element, being the current displayed page should not have a url member and be displayed without link style.
+The actual file data consists of an array of rows, containing the columns mentioned in the original "cols" section.
+The example protocol needs two mounts, one to provide the index.html, js and the protocol itself
+The protocol wants a per-mount option (PMO) to tell it the base directory it is serving from, named "dir".
+The other mount is there to simply serve items that get clicked on from the table in a secure way
+This last bit is not related to using lwsgt itself.
+![]() |
+
+ libwebsockets
+
+ Lightweight C library for HTML5 websockets
+ |
+
lwsws is an implementation of a very lightweight, ws-capable generic web server, which uses libwebsockets to implement everything underneath.
+If you are basically implementing a standalone server with lws, you can avoid reinventing the wheel and use a debugged server including lws.
+Just enable -DLWS_WITH_LWSWS=1 at cmake-time.
+It enables libuv and plugin support automatically.
+NOTICE on Ubuntu, the default libuv package is called "libuv-0.10". This is ancient.
+You should replace this with libuv1 and libuv1-dev before proceeding.
+lwsws uses JSON config files, they're pure JSON except:
+There is a single file intended for global settings
+/etc/lwsws/conf
and a config directory intended to take one file per vhost
+/etc/lwsws/conf.d/warmcat.com
To get started quickly, an example config reproducing the old test server on port 7681, non-SSL is provided. To set it up
reject-service-keywords
allows you to return an HTTP error code and message of your choice if a keyword is found in the user agentOne server can run many vhosts, where SSL is in use SNI is used to match the connection to a vhost and its vhost-specific SSL keys during SSL negotiation.
+Listing multiple vhosts looks something like this
That sets up three vhosts all called "localhost" on ports 443 and 7681 with SSL, and port 80 without SSL but with a forced redirect to https://localhost
+The vhost name field is used to match on incoming SNI or Host: header, so it must always be the host name used to reach the vhost externally.
+Vhosts by default have available the union of any initial protocols from context creation time, and any protocols exposed by plugins.
+Vhosts can select which plugins they want to offer and give them per-vhost settings using this syntax
The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost LWS_CALLBACK_PROTOCOL_INIT ( is a pointer to a linked list of struct lws_protocol_vhost_options containing the name and value pointers).
+To indicate that a protocol should be used when no Protocol: header is sent by the client, you can use "default": "1"
host-ssl-cert
, host-ssl-ca
and host-ssl-key
are given, then the vhost supports SSL.Each vhost may have its own certs, SNI is used during the initial connection negotiation to figure out which certs to use by the server name it's asking for from the request DNS name.
+keeplive-timeout
(in secs) defaults to 60 for lwsws, it may be set as a vhost optioninterface
lets you specify which network interface to listen on, if not given listens on all"enable-client-ssl"
: "1"
enables the vhost's client SSL context, you will need this if you plan to create client conections on the vhost that will use SSL. You don't need it if you only want http / ws client connections.If you need to allow weaker ciphers,you can provide an alternative list here per-vhost.
+The values are derived from /usr/include/openssl/ssl.h
would equate to
+allows you to set arbitrary headers on every file served by the vhost
+recommended vhost headers for good client security are
+Where mounts are given in the vhost definition, then directory contents may be auto-served if it matches the mountpoint.
+Mount protocols are used to control what kind of translation happens
+Eg, with this mountpoint
The uri /file.jpg would serve /var/www/mysite.com/file.jpg, since / matched.
+1) Some protocols may want "per-mount options" in name:value format. You can provide them using "pmo"
{ + "mountpoint": "/stuff", + "origin": "callback://myprotocol", + "pmo": [{ + "myname": "myvalue" + }] + } +
2) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
This allows you to customize one cgi depending on the mountpoint (and / or vhost).
+3) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this
4) callback://
protocol may be used when defining a mount to associate a named protocol callback with the URL namespace area. For example
All handling of client access to /formtest[anything] will be passed to the callback registered to the protocol "protocol-post-demo".
+This is useful for handling POST http body content or general non-cgi http payload generation inside a plugin.
+See the related notes in README.coding.md
+5) Cache policy of the files in the mount can also be set. If no options are given, the content is marked uncacheable.
6) You can also define a list of additional mimetypes per-mount
Normally a file suffix MUST match one of the canned mimetypes or one of the extra mimetypes, or the file is not served. This adds a little bit of security because even if there is a bug somewhere and the mount dirs are circumvented, lws will not serve, eg, /etc/passwd.
+If you provide an extra mimetype entry
"*": "" +
Then any file is served, if the mimetype was not known then it is served without a Content-Type: header.
+7) A mount can be protected by HTTP Basic Auth. This only makes sense when using https, since otherwise the password can be sniffed.
+You can add a basic-auth
entry on a mount like this`
Before serving anything, lws will signal to the browser that a username / password combination is required, and it will pop up a dialog. When the user has filled it in, lwsws checks the user:password string against the text file named in the basic-auth
entry.
The file should contain user:pass one per line
+The file should be readable by lwsws, and for a little bit of extra security not have a file suffix, so lws would reject to serve it even if it could find it on a mount.
+Protcols and extensions may also be provided from "plugins", these are lightweight dynamic libraries. They are scanned for at init time, and any protocols and extensions found are added to the list given at context creation time.
+Protocols receive init (LWS_CALLBACK_PROTOCOL_INIT) and destruction (LWS_CALLBACK_PROTOCOL_DESTROY) callbacks per-vhost, and there are arrangements they can make per-vhost allocations and get hold of the correct pointer from the wsi at the callback.
+This allows a protocol to choose to strictly segregate data on a per-vhost basis, and also allows the plugin to handle its own initialization and context storage.
+To help that happen conveniently, there are some new apis
+dumb increment, mirror and status protocol plugins are provided as examples.
+Packages that have their own lws plugins can install them in their own preferred dir and ask lwsws to scan there by using a config fragment like this, in its own conf.d/ file managed by the other package
One provided protocol can be used to monitor the server status.
+Enable the protocol like this on a vhost's ws-protocols section
"update-ms" is used to control how often updated JSON is sent on a ws link.
+And map the provided HTML into the vhost in the mounts section
You might choose to put it on its own vhost which has "interface": "lo", so it's not externally visible.
+lwsws needs a service file like this as /usr/lib/systemd/system/lwsws.service
You can find this prepared in ./lwsws/usr-lib-systemd-system-lwsws.service
For correct operation with logrotate, /etc/logrotate.d/lwsws
(if that's where we're putting the logs) should contain
You can find this prepared in /lwsws/etc-logrotate.d-lwsws
Prepare the log directory like this
+![]() |
+
+ libwebsockets
+
+ Lightweight C library for HTML5 websockets
+ |
+
As a library, lws is always just a component in a bigger application.
+When users have a problem involving lws, what is happening in the bigger application is usually critical to understand what is going on (and where the solution lies).
+Many users are able to share their sources, but others decide not to, for presumed "commercial advantage" or whatever. (In any event, it can be painful looking through large chunks of someone else's sources for problems when that is not the library author's responsibility.)
+This makes answering questions like "what is wrong with my code I am not +going to show you?" or even "what is wrong with my code?" very difficult.
+Even if it's clear there is a problem somewhere, it cannot be understood or reproduced by anyone else if it needs user code that isn't provided.
+The biggest question is, "is this an lws problem actually"?
+The test server and client are extremely useful for sanity checks and debugging guidance.
+![]() |
+
+ libwebsockets
+
+ Lightweight C library for HTML5 websockets
+ |
+
Are you building a client? You just need to look at the test client libwebsockets-test-client.
+If you are building a standalone server, there are three choices, in order of preferability.
+1) lwsws + protocol plugins
+Lws provides a generic web server app that can be configured with JSON config files. https://libwebsockets.org itself uses this method.
+With lwsws handling the serving part, you only need to write an lws protocol plugin. See [plugin-standalone](plugin-standalone) for an example of how to do that outside lws itself, using lws public apis.
+$ cmake .. -DLWS_WITH_LWSWS=1
+See README.lwsws.md for information on how to configure lwsws.
+NOTE this method implies libuv is used by lws, to provide crossplatform implementations of timers, dynamic lib loading etc for plugins and lwsws.
+2) test-server-v2.0.c
+This method lets you configure web serving in code, instead of using lwsws.
+Plugins are still used, which implies libuv needed.
+$ cmake .. -DLWS_WITH_PLUGINS=1
+ +3) protocols in the server app
+This is the original way lws implemented servers, plugins and libuv are not required, but without plugins separating the protocol code directly, the combined code is all squidged together and is much less maintainable.
+This method is still supported in lws but all ongoing and future work is being done in protocol plugins only.
+If you run libwebsockets-test-server and point your browser (eg, Chrome) to
http://127.0.0.1:7681 +
It will fetch a script in the form of test.html
, and then run the script in there on the browser to open a websocket connection. Incrementing numbers should appear in the browser display.
By default the test server logs to both stderr and syslog, you can control what is logged using -d <log level>
, see later.
You can use the -D option on the test server to have it fork into the background and return immediately. In this daemonized mode all stderr is disabled and logging goes only to syslog, eg, /var/log/messages
or similar.
The server maintains a lockfile at /tmp/.lwsts-lock
that contains the pid of the master process, and deletes this file when the master process terminates.
To stop the daemon, do
If it finds a stale lock (the pid mentioned in the file does not exist any more) it will delete the lock and create a new one during startup.
+If the lock is valid, the daemon will exit with a note on stderr that it was already running.
+To test it using SSL/WSS, just run the test server with
and use the URL
The connection will be entirely encrypted using some generated certificates that your browser will not accept, since they are not signed by any real Certificate Authority. Just accept the certificates in the browser and the connection will proceed in first https and then websocket wss, acting exactly the same.
+test-server.c is all that is needed to use libwebsockets for serving both the script html over http and websockets.
+If you run the test server as described above, you can also connect to it using the test client as well as a browser.
+will by default connect to the test server on localhost:7681 and print the dumb increment number from the server at the same time as drawing random circles in the mirror protocol; if you connect to the test server using a browser at the same time you will be able to see the circles being drawn.
+The test client supports SSL too, use
+the -s tells it to accept the default self-signed cert from the server, otherwise it will strictly fail the connection if there is no CA cert to validate the server's certificate.
+If you will be doing standalone serving with lws, ideally you should avoid making your own server at all, and use lwsws with your own protocol plugins.
+The second best option is follow test-server-v2.0.c, which uses a mount to autoserve a directory, and lws protocol plugins for ws, without needing any user callback code (other than what's needed in the protocol plugin).
+For those two options libuv is needed to support the protocol plugins, if that's not possible then the other variations with their own protocol code should be considered.
+You can test against echo.websockets.org
as a sanity test like this (the client connects to port 80
by default):
This echo test is of limited use though because it doesn't negotiate any protocol. You can run the same test app as a local server, by default on localhost:7681
and do the echo test against the local echo server
If you add the --ssl
switch to both the client and server, you can also test with an encrypted link.
To test SSL/WSS client action, just run the client test with
By default the client test applet is set to accept self-signed certificates used by the test server, this is indicated by the use_ssl
var being set to 2
. Set it to 1
to reject any server certificate that it doesn't have a trusted CA cert for.
libwebsockets-test-ping connects as a client to a remote websocket server and pings it like the normal unix ping utility.
By default it sends 64 byte payload packets using the 04 PING packet opcode type. You can change the payload size using the -s=
flag, up to a maximum of 125 mandated by the 04 standard.
Using the lws-mirror protocol that is provided by the test server, libwebsockets-test-ping can also use larger payload sizes up to 4096 is BINARY packets; lws-mirror will copy them back to the client and they appear as a PONG. Use the -m
flag to select this operation.
The default interval between pings is 1s, you can use the -i= flag to set this, including fractions like -i=0.01
for 10ms interval.
Before you can even use the PING opcode that is part of the standard, you must complete a handshake with a specified protocol. By default lws-mirror-protocol is used which is supported by the test server. But if you are using it on another server, you can specify the protocol to handshake with by --protocol=protocolname
By default it runs in server mode
You need to run a second session in client mode, you have to give the -c
switch and the server address at least:
The fraggle test sends a random number up to 1024 fragmented websocket frames each of a random size between 1 and 2001 bytes in a single message, then sends a checksum and starts sending a new randomly sized and fragmented message.
+The fraggle test client receives the same message fragments and computes the same checksum using websocket framing to see when the message has ended. It then accepts the server checksum message and compares that to its checksum.
+The http_proxy environment variable is respected by the client connection code for both ws://
and wss://
. It doesn't support authentication.
You use it like this
By default logging of severity "notice", "warn" or "err" is enabled to stderr.
+Again by default other logging is compiled in but disabled from printing.
+By default debug logs below "notice" in severity are not compiled in. To get them included, add this option in CMAKE
+If you want to see more detailed debug logs, you can control a bitfield to select which logs types may print using the lws_set_log_level()
api, in the test apps you can use -d <number>
to control this. The types of logging available are (OR together the numbers to select multiple)
The final IETF standard is supported for both client and server, protocol version 13.
+Since libwebsockets runs using poll()
and a single threaded approach, any unexpected latency coming from system calls would be bad news. There's now a latency tracking scheme that can be built in with --with-latency
at configure-time, logging the time taken for system calls to complete and if the whole action did complete that time or was deferred.
You can see the detailed data by enabling logging level 512 (eg, -d 519
on the test server to see that and the usual logs), however even without that the "worst" latency is kept and reported to the logs with NOTICE severity when the context is destroyed.
Some care is needed interpreting them, if the action completed the first figure (in us) is the time taken for the whole action, which may have retried through the poll loop many times and will depend on network roundtrip times. High figures here don't indicate a problem. The figure in us reported after "lat" in the logging is the time taken by this particular attempt. High figures here may indicate a problem, or if you system is loaded with another app at that time, such as the browser, it may simply indicate the OS gave preferential treatment to the other app during that call.
+Lws can be tested against the autobahn websocket fuzzer.
+1) pip install autobahntestsuite
+2) wstest -m fuzzingserver
+3) Run tests like this
+libwebsockets-test-echo –client localhost –port 9001 -u "/runCase?case=20&agent=libwebsockets" -v -d 65535 -n 1
+(this runs test 20)
+4) In a browser, go here
+http://localhost:8080/test_browser.html
+fill in "libwebsockets" in "User Agent Identifier" and press "Update Reports (Manual)"
+5) In a browser go to the directory you ran wstest in (eg, /projects/libwebsockets)
+file:///projects/libwebsockets/reports/clients/index.html
+to see the results
+1) Autobahn tests the user code + lws implementation. So to get the same results, you need to follow test-echo.c in terms of user implementation.
+2) Two of the tests make no sense for Libwebsockets to support and we fail them.
+bits set here must be set for authorized client session
+const char* lws_http_mount::basic_auth_login_file | +
NULL, or filepath to use to check basic auth logins against
+