README.async-dns.md
1# Asynchronous DNS
2
3## Introduction
4
5Lws now features optional asynchronous, ie, nonblocking recursive DNS
6resolution done on the event loop, enable `-DLWS_WITH_SYS_ASYNC_DNS=1`
7at cmake to build it in.
8
9## Description
10
11The default libc name resolution is via libc `getaddrinfo()`, which is
12blocking, possibly for quite long periods (seconds). If you are
13taking care about latency, but want to create outgoing connections,
14you can't tolerate this exception from the rule that everything in
15lws is nonblocking.
16
17Lws' asynchronous DNS resolver creates a caching name resolver
18that directly queries the configured nameserver itself over UDP,
19from the event loop.
20
21It supports both ipv4 / A records and ipv6 / AAAA records (see later
22for a description about how). One server supported over UDP :53,
23and the nameserver is autodicovered on linux, windows, and freertos.
24
25Other features
26
27 - lws-style paranoid response parsing
28 - random unique tid generation to increase difficulty of poisoning
29 - it's really integrated with the lws event loop, it does not spawn
30 threads or use the libc resolver, and of course no blocking at all
31 - platform-specific server address capturing (from /etc/resolv.conf
32 on linux, windows apis on windows)
33 - LRU caching
34 - piggybacking (multiple requests before the first completes go on
35 a list on the first request, not spawn multiple requests)
36 - observes TTL in cache
37 - TTL and timeout use `lws_sul` timers on the event loop
38 - Uses CNAME resolution inside the same response if present, otherwise
39 recurses to resolve the CNAME (up to 3 deep)
40 - ipv6 pieces only built if cmake `LWS_IPV6` enabled
41
42## Api
43
44If enabled at cmake, the async DNS implementation is used automatically
45for lws client connections. It's also possible to call it directly, see
46the api-test-async-dns example for how.
47
48The Api follows that of `getaddrinfo()` but results are not created on
49the heap. Instead a single, const cached copy of the addrinfo struct
50chain is reference-counted, with `lws_async_dns_freeaddrinfo()` provided
51to deduct from the reference count. Cached items with a nonzero
52reference count can't be destroyed from the cache, so it's safe to keep
53a pointer to the results and iterate through them.
54
55## Dealing with IPv4 and IPv6
56
57DNS is a very old standard that has some quirks... one of them is that
58multiple queries are not supported in one packet, even though the protocol
59suggests it is. This creates problems on ipv6 enabled systems, where
60it may prefer to have AAAA results, but the server may only have A records.
61
62To square the circle, for ipv4 only systems (`LWS_IPV6=0`) the resolver
63requests only A records. For ipv6-capable systems, it always requests
64first A and then immediately afterwards AAAA records.
65
66To simplify the implementation, the tid b0 is used to differentiate
67between A (b0 = 0) and AAAA (b0 = 1) requests and responses using the
68same query body.
69
70The first response to come back is parsed, and a cache entry made...
71it leaves a note in the query about the address of the last `struct addrinfo`
72record. When the second response comes, a second allocation is made,
73but not added to the logical cache... instead it's chained on to the
74first cache entry and the `struct addrinfo` linked-list from the
75first cache entry is extended into the second one. At the time the
76second result arrives, the query is destroyed and the cached results
77provided on the result callback.
78
79## Recursion
80
81Where CNAMEs are returned, DNS servers may take two approaches... if the
82CNAME is also resolved by the same server and so it knows what it should
83resolve to, it may provide the CNAME resolution in the same response
84packet.
85
86In the case the CNAME is actually resolved by a different name server,
87the server with the CNAME does not have the information to hand to also
88resolve the CNAME in the same response. So it just leaves it for the
89client to sort out.
90
91The lws implementation can deal with both of these, first it "recurses"
92(it does not recurse on the process stack but uses its own manual stack)
93to look for results in the same packet that told it about the CNAME. If
94there are no results, it resets the query to look instead for the CNAME,
95and restarts it. It allows this to happen for 3 CNAME deep.
96
97At the end, either way, the cached result is set using the original
98query name and the results from the last CNAME in the chain.
99
100
101
README.build-windows.md
1# Some notes for the windows jungle
2
3This was how I compiled libwebsockets in windows March 2020.
4
5## OpenSSL
6
7### Installing prebuilt libs
8
9I used the 1.1.1d (the latest) libs from here, as recommended on the OpenSSL site
10
11[overbyte.eu](https:..wiki.overbyte.eu/wiki/index.php/ICS_Download#Download_OpenSSL_Binaries_.28required_for_SSL-enabled_components.29)
12
13I had to use procmon64 (windows' strace) to establish that these libraries are
14looking for a cert bundle at "C:\Program Files\Common Files\SSL\cert.pem"... it's not
15included in the zip file from the above, so...
16
17### Installing a cert bundle
18
19You can get a trusted cert bundle from here
20
21[drwetter/testssl cert bundle](https://raw.githubusercontent.com/drwetter/testssl.sh/3.1dev/etc/Microsoft.pem)
22
23Save it into `C:\Program Files\Common Files\SSL\cert.pem` where openssl will be able to see it.
24
25### Installing cmake
26
27CMake have a windows installer thing downloadable from here
28
29[cmake](https://cmake.org/download/)
30
31after that you can use `cmake` from the terminal OK.
32
33### Installing git
34
35Visit the canonical git site to download their windows installer thing
36
37[git](https://git-scm.com/download/win)
38
39after that `git` from the terminal is working.
40
41### Install the free "community" visual studio
42
43You can do this through "windows store" by searching for "visual studio"
44
45I installed as little as possible, we just want the C "C++" tools.
46
47It still wouldn't link without the "mt" helper tool from the
48huge windows SDK, so you have to install GB of that as well.
49
50### Building
51
52Somehow windows cmake seems slightly broken, some of the plugins and
53examples are conditional on `if (NOT WIN32)`, but it configures them
54anyway. For this reason (it seems "only", it worked when I commented the
55cmake entries for the related plugins) `-DLWS_WITH_MINIMAL_EXAMPLES=1`
56
57Instead I followed how appveyor builds the stuff in CI... clone libwebsockets then
58
59```
60> git clone https://libwebsockets.org/repo/libwebsockets
61> cd libwebsockets
62> mkdir build
63> cd build
64> cmake ..
65> cmake --build . --config DEBUG
66```
67
68Installing requires admin privs, I opened a second cmd window as admin and did it
69there.
70
71```
72> cmake --install . --config DEBUG
73```
74
75After that you can run the test apps OK.
76
README.build.md
1Notes about building lws
2========================
3
4You can download and install lws using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
5```
6git clone https://github.com/microsoft/vcpkg.git
7cd vcpkg
8./bootstrap-vcpkg.sh
9./vcpkg integrate install
10vcpkg install libwebsockets
11```
12The lws port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg/) on the vcpkg repository.
13
14@section cm Introduction to CMake
15
16CMake is a multi-platform build tool that can generate build files for many
17different target platforms. See more info at http://www.cmake.org
18
19CMake also allows/recommends you to do "out of source"-builds, that is,
20the build files are separated from your sources, so there is no need to
21create elaborate clean scripts to get a clean source tree, instead you
22simply remove your build directory.
23
24Libwebsockets has been tested to build successfully on the following platforms
25with SSL support (for OpenSSL/wolfSSL/BoringSSL):
26
27- Windows (Visual Studio)
28- Windows (MinGW)
29- Linux (x86 and ARM)
30- OSX
31- NetBSD
32
33
34@section build1 Building the library and test apps
35
36The project settings used by CMake to generate the platform specific build
37files is called [CMakeLists.txt](../CMakeLists.txt). CMake then uses one of its "Generators" to
38output a Visual Studio project or Make file for instance. To see a list of
39the available generators for your platform, simply run the "cmake" command.
40
41Note that by default OpenSSL will be linked, if you don't want SSL support
42see below on how to toggle compile options.
43
44
45@section bu Building on Unix:
46
471. Install CMake 2.8 or greater: http://cmake.org/cmake/resources/software.html
48 (Most Unix distributions comes with a packaged version also)
49
502. Install OpenSSL.
51
523. Generate the build files (default is Make files):
53```
54 $ cd /path/to/src
55 $ mkdir build
56 $ cd build
57 $ cmake ..
58```
59
604. Finally you can build using the generated Makefile:
61```
62 $ make && sudo make install
63```
64**NOTE**: The `build/`` directory can have any name and be located anywhere
65 on your filesystem, and that the argument `..` given to cmake is simply
66 the source directory of **libwebsockets** containing the [CMakeLists.txt](../CMakeLists.txt)
67 project file. All examples in this file assumes you use ".."
68
69**NOTE2**:
70A common option you may want to give is to set the install path, same
71as --prefix= with autotools. It defaults to /usr/local.
72You can do this by, eg
73```
74 $ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .
75```
76
77**NOTE3**:
78On machines that want libraries in lib64, you can also add the
79following to the cmake line
80```
81 -DLIB_SUFFIX=64
82```
83
84**NOTE4**:
85If you are building against a non-distro OpenSSL (eg, in order to get
86access to ALPN support only in newer OpenSSL versions) the nice way to
87express that in one cmake command is eg,
88```
89 $ cmake .. -DOPENSSL_ROOT_DIR=/usr/local/ssl \
90 -DCMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE=/usr/local/ssl \
91 -DLWS_WITH_HTTP2=1
92```
93
94When you run the test apps using non-distro SSL, you have to force them
95to use your libs, not the distro ones
96```
97 $ LD_LIBRARY_PATH=/usr/local/ssl/lib libwebsockets-test-server --ssl
98```
99
100To get it to build on latest openssl (2016-04-10) it needed this approach
101```
102 cmake .. -DLWS_WITH_HTTP2=1 -DLWS_OPENSSL_INCLUDE_DIRS=/usr/local/include/openssl -DLWS_OPENSSL_LIBRARIES="/usr/local/lib64/libssl.so;/usr/local/lib64/libcrypto.so"
103```
104
105Mac users have reported
106
107```
108 $ export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2k; cmake ..; make -j4
109```
110
111worked for them when using "homebrew" OpenSSL
112
113**NOTE5**:
114To build with debug info and _DEBUG for lower priority debug messages
115compiled in, use
116```
117 $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG
118```
119
120**NOTE6**
121To build on Solaris the linker needs to be informed to use lib socket
122and libnsl, and only builds in 64bit mode.
123
124```bash
125 $ cmake .. -DCMAKE_C_FLAGS=-m64 -DCMAKE_EXE_LINKER_FLAGS="-lsocket -lnsl"
126```
127
128**NOTE7**
129
130Build and test flow against boringssl. Notice `LWS_WITH_GENHASH` is currently
131unavailable with boringssl due to their removing the necessary apis.
132
133Build current HEAD boringssl
134
135```
136 $ cd /projects
137 $ git clone https://boringssl.googlesource.com/boringssl
138 $ cd boringssl
139 $ mkdir build
140 $ cd build
141 $ cmake .. -DBUILD_SHARED_LIBS=1
142 $ make -j8
143```
144
145Build and test lws against it
146
147```
148 $ cd /projects/libwebsockets/build
149 $ cmake .. -DOPENSSL_LIBRARIES="/projects/boringssl/build/ssl/libssl.so;\
150 /projects/boringssl/build/crypto/libcrypto.so" \
151 -DOPENSSL_INCLUDE_DIRS=/projects/boringssl/include \
152 -DLWS_WITH_BORINGSSL=1 -DCMAKE_BUILD_TYPE=DEBUG
153 $ make -j8 && sudo make install
154 $ LD_PRELOAD="/projects/boringssl/build/ssl/libssl.so \
155 /projects/boringssl/build/crypto/libcrypto.so" \
156 /usr/local/bin/libwebsockets-test-server -s
157```
158
1594. Finally you can build using the generated Makefile:
160
161```bash
162 $ make
163 ```
164
165@section lcap Linux Capabilities
166
167On Linux, lws now lets you retain selected root capabilities when dropping
168privileges. If libcap-dev or similar package is installed providing
169sys/capabilities.h, and libcap or similar package is installed providing
170libcap.so, CMake will enable the capability features.
171
172The context creation info struct .caps[] and .count_caps members can then
173be set by user code to enable selected root capabilities to survive the
174transition to running under an unprivileged user.
175
176@section cmq Quirk of cmake
177
178When changing cmake options, for some reason the only way to get it to see the
179changes sometimes is delete the contents of your build directory and do the
180cmake from scratch.
181
182deleting build/CMakeCache.txt may be enough.
183
184
185@section cmw Building on Windows (Visual Studio)
186
1871. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html
188
1892. Install OpenSSL binaries. https://wiki.openssl.org/index.php/Binaries
190
191 (**NOTE**: Preferably in the default location to make it easier for CMake to find them)
192
193 **NOTE2**:
194 Be sure that OPENSSL_CONF environment variable is defined and points at
195 <OpenSSL install location>\bin\openssl.cfg
196
1973. Generate the Visual studio project by opening the Visual Studio cmd prompt:
198
199```
200 cd <path to src>
201 md build
202 cd build
203 cmake -G "Visual Studio 10" ..
204```
205
206 (**NOTE**: There is also a cmake-gui available on Windows if you prefer that)
207
208 **NOTE2**:
209 See this link to find out the version number corresponding to your Visual Studio edition:
210 http://superuser.com/a/194065
211
2124. Now you should have a generated Visual Studio Solution in your
213 `<path to src>/build` directory, which can be used to build.
214
2155. Some additional deps may be needed
216
217 - iphlpapi.lib
218 - psapi.lib
219 - userenv.lib
220
2216. If you're using libuv, you must make sure to compile libuv with the same multithread-dll / Mtd attributes as libwebsockets itself
222
223
224@section cmwmgw Building on Windows (MinGW)
225
2261. Install MinGW
227
228 For Fedora, it's, eg, `dnf install mingw64-gcc`
229
2302. Install current CMake package
231
232 For Fedora, it's `dnf install cmake`
233
2343. Instal mingw-built OpenSSL pieces
235
236 For Fedora, it's `mingw64-openssl.noarch mingw64-openssl-static.noarch`
237
238 mingw64-cmake as described below will auto-find the libs and includes
239 for build. But to execute the apps, they either need to go into the same
240 `/usr/x86_64-w64-mingw32/sys-root/mingw/bin/` as the dlls are installed to,
241 or the dlls have to be copied into the same dir as your app executable.
242
2434. Generate the build files (default is Make files) using MSYS shell.
244
245 For Fedora, they provide a `mingw64-cmake` wrapper in the package
246 `mingw64-filesystem`, with this you can run that instead of cmake directly
247 and don't have to get involved with setting the cmake generator.
248
249 Otherwise doing it by hand is like this:
250
251```
252 $ cd /drive/path/to/src
253 $ mkdir build
254 $ cd build
255 $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW ..
256```
257
258 To generate build files allowing to create libwebsockets binaries with debug information
259 set the CMAKE_BUILD_TYPE flag to DEBUG:
260```
261 $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW -DCMAKE_BUILD_TYPE=DEBUG ..
262```
2635. Finally you can build using the generated Makefile and get the results deployed into your MinGW installation:
264
265```
266 $ make && make install
267```
268
269@section distro Selecting CMake options useful for distros
270
271Distro packagers should select the CMake option "LWS_WITH_DISTRO_RECOMMENDED",
272which selects common additional options like support for various event libraries,
273plugins and lwsws.
274
275@section ssllib Choosing Your TLS Poison
276
277 - If you are really restricted on memory, code size, or don't care about TLS
278 speed, mbedTLS is a good choice: `cmake .. -DLWS_WITH_MBEDTLS=1`
279
280 - If cpu and memory is not super restricted and you care about TLS speed,
281 OpenSSL or a directly compatible variant like Boring SSL is a good choice.
282
283Just building lws against stock Fedora OpenSSL or stock Fedora mbedTLS, for
284SSL handhake mbedTLS takes ~36ms and OpenSSL takes ~1ms on the same x86_64
285build machine here, with everything else the same. Over the 144 connections of
286h2spec compliance testing for example, this ends up completing in 400ms for
287OpenSSL and 5.5sec for mbedTLS on x86_64. In other words mbedTLS is very slow
288compared to OpenSSL under the (fairly typical) conditions I tested it.
289
290This isn't an inefficiency in the mbedtls interface implementation, it's just
291mbedTLS doing the crypto much slower than OpenSSL, which has accelerated
292versions of common crypto operations it automatically uses for platforms
293supporting it. As of Oct 2017 mbedTLS itself has no such optimizations for any
294platform that I could find. It's just pure C running on the CPU.
295
296Lws supports both almost the same, so instead of taking my word for it you are
297invited to try it both ways and see which the results (including, eg, binary
298size and memory usage as well as speed) suggest you use.
299
300NOTE: one major difference with mbedTLS is it does not load the system trust
301store by default. That has advantages and disadvantages, but the disadvantage
302is you must provide the CA cert to lws built against mbedTLS for it to be able
303to validate it, ie, use -A with the test client. The minimal test clients
304have the CA cert for warmcat.com and libwebsockets.org and use it if they see
305they were built with mbedTLS.
306
307@section optee Building for OP-TEE
308
309OP-TEE is a "Secure World" Trusted Execution Environment.
310
311Although lws is only part of the necessary picture to have an https-enabled
312TA, it does support OP-TEE as a platform and if you provide the other
313pieces, does work very well.
314
315Select it in cmake with `-DLWS_PLAT_OPTEE=1`
316
317
318@section cmco Setting compile options
319
320To set compile time flags you can either use one of the CMake gui applications
321or do it via the command line.
322
323@subsection cmcocl Command line
324
325To list available options (omit the H if you don't want the help text):
326
327 cmake -LH ..
328
329Then to set an option and build (for example turn off SSL support):
330
331 cmake -DLWS_WITH_SSL=0 ..
332or
333 cmake -DLWS_WITH_SSL:BOOL=OFF ..
334
335@subsection cmcoug Unix GUI
336
337If you have a curses-enabled build you simply type:
338(not all packages include this, my debian install does not for example).
339
340 ccmake
341
342@subsection cmcowg Windows GUI
343
344On windows CMake comes with a gui application:
345 Start -> Programs -> CMake -> CMake (cmake-gui)
346
347
348@section wolf wolfSSL/CyaSSL replacement for OpenSSL
349
350wolfSSL/CyaSSL is a lightweight SSL library targeted at embedded systems:
351https://www.wolfssl.com/wolfSSL/Products-wolfssl.html
352
353It contains a OpenSSL compatibility layer which makes it possible to pretty
354much link to it instead of OpenSSL, giving a much smaller footprint.
355
356**NOTE**: wolfssl needs to be compiled using the `--enable-opensslextra` flag for
357this to work.
358
359@section wolf1 Compiling libwebsockets with wolfSSL
360
361```
362 cmake .. -DLWS_WITH_WOLFSSL=1 \
363 -DLWS_WOLFSSL_INCLUDE_DIRS=/path/to/wolfssl \
364 -DLWS_WOLFSSL_LIBRARIES=/path/to/wolfssl/wolfssl.a ..
365```
366
367**NOTE**: On windows use the .lib file extension for `LWS_WOLFSSL_LIBRARIES` instead.
368
369@section cya Compiling libwebsockets with CyaSSL
370
371```
372 cmake .. -DLWS_WITH_CYASSL=1 \
373 -DLWS_CYASSL_INCLUDE_DIRS=/path/to/cyassl \
374 -DLWS_CYASSL_LIBRARIES=/path/to/wolfssl/cyassl.a ..
375```
376
377**NOTE**: On windows use the .lib file extension for `LWS_CYASSL_LIBRARIES` instead.
378
379@section gzip Selecting GZIP or MINIZ
380
381By default lws supports gzip when compression is needed. But you can tell it to use
382MINIZ instead by using `-DLWS_WITH_MINIZ=1`.
383
384For native build cmake will try to find an existing libminiz.so or .a and build
385against that and the found includes automatically.
386
387For cross-build or building against local miniz, you need the following kind of
388cmake to tell it where to get miniz
389
390```
391cmake .. -DLWS_WITH_MINIZ=1 -DLWS_WITH_ZIP_FOPS=1 -DMINIZ_INCLUDE_DIRS="/projects/miniz;/projects/miniz/build" -DMINIZ_LIBRARIES=/projects/miniz/build/libminiz.so.2.1.0
392```
393
394@section esp32 Building for ESP32
395
396Building for ESP32 requires the ESP-IDF framework. It can be built under Linux, OSX or Windows (MSYS2).
397
3981. Install ESP-IDF, follow the getting started guide here - http://esp-idf.readthedocs.io/en/latest/get-started/
3992. Set ESP-IDF to last known working version (assuming ESP-IDF is in `~/esp/esp-idf`) :
400```
401 cd ~/esp/esp-idf
402 git checkout 0c50b65a34cd6b3954f7435193411a88adb49cb0
403 git submodule update --recursive
404```
4053. Add `libwebsockets` as a submodule in the `components` folder of your ESP-IDF project:
406```
407 git submodule add https://github.com/warmcat/libwebsockets.git components/libwebsockets
408```
4094. If on Windows (MSYS2) you will need to install CMake in the MSYS2 environment:
410```
411 pacman -S mingw-w64-i686-cmake
412```
413If you're on Linux or OSX ensure CMake version is at least 3.7.
414
415@section extplugins Building plugins outside of lws itself
416
417The directory ./plugin-standalone/ shows how easy it is to create plugins
418outside of lws itself. First build lws itself with -DLWS_WITH_PLUGINS,
419then use the same flow to build the standalone plugin
420```
421 cd ./plugin-standalone
422 mkdir build
423 cd build
424 cmake ..
425 make && sudo make install
426```
427
428if you changed the default plugin directory when you built lws, you must
429also give the same arguments to cmake here (eg,
430` -DCMAKE_INSTALL_PREFIX:PATH=/usr/something/else...` )
431
432Otherwise if you run lwsws or libwebsockets-test-server-v2.0, it will now
433find the additional plugin "libprotocol_example_standalone.so"
434```
435 lwsts[21257]: Plugins:
436 lwsts[21257]: libprotocol_dumb_increment.so
437 lwsts[21257]: libprotocol_example_standalone.so
438 lwsts[21257]: libprotocol_lws_mirror.so
439 lwsts[21257]: libprotocol_lws_server_status.so
440 lwsts[21257]: libprotocol_lws_status.so
441```
442If you have multiple vhosts, you must enable plugins at the vhost
443additionally, discovered plugins are not enabled automatically for security
444reasons. You do this using info->pvo or for lwsws, in the JSON config.
445
446
447@section http2rp Reproducing HTTP/2 tests
448
449Enable `-DLWS_WITH_HTTP2=1` in cmake to build with http/2 support enabled.
450
451You must have built and be running lws against a version of openssl that has
452ALPN. At the time of writing, recent distros have started upgrading to OpenSSL
4531.1+ that supports this already. You'll know it's right by seeing
454
455```
456 lwsts[4752]: Compiled with OpenSSL support
457 lwsts[4752]: Using SSL mode
458 lwsts[4752]: HTTP2 / ALPN enabled
459```
460at lws startup.
461
462Recent Firefox and Chrome also support HTTP/2 by ALPN, so these should just work
463with the test server running in -s / ssl mode.
464
465For testing with nghttp client:
466
467```
468 $ nghttp -nvas https://localhost:7681/test.html
469```
470
471Testing with h2spec (https://github.com/summerwind/h2spec)
472
473```
474 $ h2spec -h 127.0.0.1 -p 7681 -t -k -v -o 1
475```
476
477```
478145 tests, 145 passed, 0 skipped, 0 failed
479
480```
481
482@section coverage Automated Coverage Testing
483
484./test-apps/attack.sh contains scripted tests that are the basis
485of the automated test coverage assessment available for gcc and clang.
486
487To reproduce
488
489 $ cd build
490 $ cmake .. -DLWS_WITH_GCOV=1 -DCMAKE_BUILD_TYPE=DEBUG
491 $ ../scripts/build-gcov.sh
492 $ ../test-apps/attack.sh
493 $ ../scripts/gcov.sh
494...
495Lines executed:51.24% of 8279
496
497@section windowsprebuilt Using Windows binary builds on Appveyor
498
499The CI builds on Appveyor now produce usable binary outputs. Visit
500
501[lws on Appveyor](https://ci.appveyor.com/project/lws-team/libwebsockets)
502
503and select one of the builds, then click on ARTIFACTS at the top right. The zip file
504want to be unpacked into `C:\Program Files (x86)/libwebsockets`, after that, you should be able to run the test server, by running it from `bin/Release/libwebsockets-test-server.exe` and opening a browser on http://127.0.0.1:7681
505
506@section cross Cross compiling
507
508To enable cross-compiling **libwebsockets** using CMake you need to create
509a "Toolchain file" that you supply to CMake when generating your build files.
510CMake will then use the cross compilers and build paths specified in this file
511to look for dependencies and such.
512
513**Libwebsockets** includes an example toolchain file [cross-arm-linux-gnueabihf.cmake](../contrib/cross-arm-linux-gnueabihf.cmake)
514you can use as a starting point.
515
516The commandline to configure for cross with this would look like
517```
518 $ cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr/lib/my-cross-root \
519 -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-arm-linux-gnueabihf.cmake \
520 -DLWS_WITHOUT_EXTENSIONS=1 -DLWS_WITH_SSL=0 \
521 -DLWS_WITH_ZIP_FOPS=0 -DLWS_WITH_ZLIB=0
522```
523The example shows how to build with no external cross lib dependencies, you
524need to provide the cross libraries otherwise.
525
526**NOTE**: start from an EMPTY build directory if you had a non-cross build in there
527 before the settings will be cached and your changes ignored.
528 Delete `build/CMakeCache.txt` at least before trying a new cmake config
529 to ensure you are really building the options you think you are.
530
531Additional information on cross compilation with CMake:
532 http://www.vtk.org/Wiki/CMake_Cross_Compiling
533
534@section cross_example Complex Cross compiling example
535
536Here are step by step instructions for cross-building the external projects needed for lws with lwsws + mbedtls as an example.
537
538In the example, my toolchain lives in `/projects/aist-tb/arm-tc` and is named `arm-linux-gnueabihf`. So you will need to adapt those to where your toolchain lives and its name where you see them here.
539
540Likewise I do all this in /tmp but it has no special meaning, you can adapt that to somewhere else.
541
542All "foreign" cross-built binaries are sent into `/tmp/cross` so they cannot be confused for 'native' x86_64 stuff on your host machine in /usr/[local/]....
543
544## Prepare the cmake toolchain file
545
5461) `cd /tmp`
547
5482) `wget -O mytoolchainfile https://raw.githubusercontent.com/warmcat/libwebsockets/master/contrib/cross-arm-linux-gnueabihf.cmake`
549
5503) Edit `/tmp/mytoolchainfile` adapting `CROSS_PATH`, `CMAKE_C_COMPILER` and `CMAKE_CXX_COMPILER` to reflect your toolchain install dir and path to your toolchain C and C++ compilers respectively. For my case:
551
552```
553set(CROSS_PATH /projects/aist-tb/arm-tc/)
554set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-gcc")
555set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-g++")
556```
557
558## 1/4: Building libuv cross:
559
5601) `export PATH=/projects/aist-tb/arm-tc/bin:$PATH` Notice there is a **/bin** on the end of the toolchain path
561
5622) `cd /tmp ; mkdir cross` we will put the cross-built libs in /tmp/cross
563
5643) `git clone https://github.com/libuv/libuv.git` get libuv
565
5664) `cd libuv`
567
5685) `./autogen.sh`
569
570```
571+ libtoolize --copy
572libtoolize: putting auxiliary files in '.'.
573libtoolize: copying file './ltmain.sh'
574libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
575libtoolize: copying file 'm4/libtool.m4'
576libtoolize: copying file 'm4/ltoptions.m4'
577libtoolize: copying file 'm4/ltsugar.m4'
578libtoolize: copying file 'm4/ltversion.m4'
579libtoolize: copying file 'm4/lt~obsolete.m4'
580+ aclocal -I m4
581+ autoconf
582+ automake --add-missing --copy
583configure.ac:38: installing './ar-lib'
584configure.ac:25: installing './compile'
585configure.ac:22: installing './config.guess'
586configure.ac:22: installing './config.sub'
587configure.ac:21: installing './install-sh'
588configure.ac:21: installing './missing'
589Makefile.am: installing './depcomp'
590```
591If it has problems, you will need to install `automake`, `libtool` etc.
592
5936) `./configure --host=arm-linux-gnueabihf --prefix=/tmp/cross`
594
5957) `make && make install` this will install to `/tmp/cross/...`
596
5978) `file /tmp/cross/lib/libuv.so.1.0.0` Check it's really built for ARM
598```
599/tmp/cross/lib/libuv.so.1.0.0: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=cdde0bc945e51db6001a9485349c035baaec2b46, with debug_info, not stripped
600```
601
602## 2/4: Building zlib cross
603
6041) `cd /tmp`
605
6062) `git clone https://github.com/madler/zlib.git`
607
6083) `CC=arm-linux-gnueabihf-gcc ./configure --prefix=/tmp/cross`
609```
610Checking for shared library support...
611Building shared library libz.so.1.2.11 with arm-linux-gnueabihf-gcc.
612Checking for size_t... Yes.
613Checking for off64_t... Yes.
614Checking for fseeko... Yes.
615Checking for strerror... Yes.
616Checking for unistd.h... Yes.
617Checking for stdarg.h... Yes.
618Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf().
619Checking for vsnprintf() in stdio.h... Yes.
620Checking for return value of vsnprintf()... Yes.
621Checking for attribute(visibility) support... Yes.
622```
623
6244) `make && make install`
625```
626arm-linux-gnueabihf-gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -c -o example.o test/example.c
627...
628rm -f /tmp/cross/include/zlib.h /tmp/cross/include/zconf.h
629cp zlib.h zconf.h /tmp/cross/include
630chmod 644 /tmp/cross/include/zlib.h /tmp/cross/include/zconf.h
631```
632
6335) `file /tmp/cross/lib/libz.so.1.2.11` This is just to confirm we built an ARM lib as expected
634```
635/tmp/cross/lib/libz.so.1.2.11: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=6f8ffef84389b1417d2fd1da1bd0c90f748f300d, with debug_info, not stripped
636```
637
638## 3/4: Building mbedtls cross
639
6401) `cd /tmp`
641
6422) `git clone https://github.com/ARMmbed/mbedtls.git`
643
6443) `cd mbedtls ; mkdir build ; cd build`
645
6463) `cmake .. -DCMAKE_TOOLCHAIN_FILE=/tmp/mytoolchainfile -DCMAKE_INSTALL_PREFIX:PATH=/tmp/cross -DCMAKE_BUILD_TYPE=RELEASE -DUSE_SHARED_MBEDTLS_LIBRARY=1` mbedtls also uses cmake, so you can simply reuse the toolchain file you used for libwebsockets. That is why you shouldn't put project-specific options in the toolchain file, it should just describe the toolchain.
647
6484) `make && make install`
649
6505) `file /tmp/cross/lib/libmbedcrypto.so.2.6.0`
651```
652/tmp/cross/lib/libmbedcrypto.so.2.6.0: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=bcca195e78bd4fd2fb37f36ab7d72d477d609d87, with debug_info, not stripped
653```
654
655## 4/4: Building libwebsockets with everything
656
6571) `cd /tmp`
658
6592) `git clone ssh://git@github.com/warmcat/libwebsockets`
660
6613) `cd libwebsockets ; mkdir build ; cd build`
662
6634) (this is all one line on the commandline)
664```
665cmake .. -DCMAKE_TOOLCHAIN_FILE=/tmp/mytoolchainfile \
666-DCMAKE_INSTALL_PREFIX:PATH=/tmp/cross \
667-DLWS_WITH_LWSWS=1 \
668-DLWS_WITH_MBEDTLS=1 \
669-DLWS_MBEDTLS_LIBRARIES="/tmp/cross/lib/libmbedcrypto.so;/tmp/cross/lib/libmbedtls.so;/tmp/cross/lib/libmbedx509.so" \
670-DLWS_MBEDTLS_INCLUDE_DIRS=/tmp/cross/include \
671-DLWS_LIBUV_LIBRARIES=/tmp/cross/lib/libuv.so \
672-DLWS_LIBUV_INCLUDE_DIRS=/tmp/cross/include \
673-DLWS_ZLIB_LIBRARIES=/tmp/cross/lib/libz.so \
674-DLWS_ZLIB_INCLUDE_DIRS=/tmp/cross/include
675```
676
6773) `make && make install`
678
6794) `file /tmp/cross/lib/libwebsockets.so.11`
680```
681/tmp/cross/lib/libwebsockets.so.11: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=81e59c6534f8e9629a9fc9065c6e955ce96ca690, with debug_info, not stripped
682```
683
6845) `arm-linux-gnueabihf-objdump -p /tmp/cross/lib/libwebsockets.so.11 | grep NEEDED` Confirm that the lws library was linked against everything we expect (libm / libc are provided by your toolchain)
685```
686 NEEDED libz.so.1
687 NEEDED libmbedcrypto.so.0
688 NEEDED libmbedtls.so.10
689 NEEDED libmbedx509.so.0
690 NEEDED libuv.so.1
691 NEEDED libm.so.6
692 NEEDED libc.so.6
693```
694
695You will also find the lws test apps in `/tmp/cross/bin`... to run lws on the target you will need to copy the related things from /tmp/cross... all the .so from /tmp/cross/lib and anything from /tmp/cross/bin you want.
696
697@section mem Memory efficiency
698
699Embedded server-only configuration without extensions (ie, no compression
700on websocket connections), but with full v13 websocket features and http
701server, built on ARM Cortex-A9:
702
703Update at 8dac94d (2013-02-18)
704```
705 $ ./configure --without-client --without-extensions --disable-debug --without-daemonize
706
707 Context Creation, 1024 fd limit[2]: 16720 (includes 12 bytes per fd)
708 Per-connection [3]: 72 bytes, +1328 during headers
709
710 .text .rodata .data .bss
711 11512 2784 288 4
712```
713This shows the impact of the major configuration with/without options at
71413ba5bbc633ea962d46d using Ubuntu ARM on a PandaBoard ES.
715
716These are accounting for static allocations from the library elf, there are
717additional dynamic allocations via malloc. These are a bit old now but give
718the right idea for relative "expense" of features.
719
720Static allocations, ARM9
721
722| | .text | .rodata | .data | .bss |
723|--------------------------------|---------|---------|-------|------|
724| All (no without) | 35024 | 9940 | 336 | 4104 |
725| without client | 25684 | 7144 | 336 | 4104 |
726| without client, exts | 21652 | 6288 | 288 | 4104 |
727| without client, exts, debug[1] | 19756 | 3768 | 288 | 4104 |
728| without server | 30304 | 8160 | 336 | 4104 |
729| without server, exts | 25382 | 7204 | 288 | 4104 |
730| without server, exts, debug[1] | 23712 | 4256 | 288 | 4104 |
731
732[1] `--disable-debug` only removes messages below `lwsl_notice`. Since that is
733the default logging level the impact is not noticeable, error, warn and notice
734logs are all still there.
735
736[2] `1024` fd per process is the default limit (set by ulimit) in at least Fedora
737and Ubuntu. You can make significant savings tailoring this to actual expected
738peak fds, ie, at a limit of `20`, context creation allocation reduces to `4432 +
739240 = 4672`)
740
741[3] known header content is freed after connection establishment
742
README.ci.md
1## Need for CI
2
3Generally if we're adding something that's supposed to work ongoing, the stuff
4should be exercised in CI (at least Travis).
5
6If there are few users for a particular feature, experience has shown that
7refactors or other upheaval can easily break it into a state of uselessness
8without anyone noticing until later.
9
10Therefore here's a description of how to add something to the CI tests... this
11is certainly a nonproductive PITA and I have never been thanked for the work
12involved. But if the promise of the various features working is going to
13remain alive, it's necessary to include CI test where possible with new
14nontrivial code.
15
16## Integration points
17
18### cmake
19
20`.travis.yml` maps the various test activities to CMake options needed.
21
22### including dependent packages into travis
23
24See `./scripts/travis_install.sh`
25
26### performing prepared test actions
27
28See `./scripts/travis_control.sh`
29
30
README.coding.md
1Notes about coding with lws
2===========================
3
4@section era Old lws and lws v2.0
5
6Originally lws only supported the "manual" method of handling everything in the
7user callback found in test-server.c / test-server-http.c.
8
9Since v2.0, the need for most or all of this manual boilerplate has been
10eliminated: the protocols[0] http stuff is provided by a generic lib export
11`lws_callback_http_dummy()`. You can serve parts of your filesystem at part of
12the URL space using mounts, the dummy http callback will do the right thing.
13
14It's much preferred to use the "automated" v2.0 type scheme, because it's less
15code and it's easier to support.
16
17The minimal examples all use the modern, recommended way.
18
19If you just need generic serving capability, without the need to integrate lws
20to some other app, consider not writing any server code at all, and instead use
21the generic server `lwsws`, and writing your special user code in a standalone
22"plugin". The server is configured for mounts etc using JSON, see
23./READMEs/README.lwsws.md.
24
25Although the "plugins" are dynamically loaded if you use lwsws or lws built
26with libuv, actually they may perfectly well be statically included if that
27suits your situation better, eg, ESP32 test server, where the platform does
28not support processes or dynamic loading, just #includes the plugins
29one after the other and gets the same benefit from the same code.
30
31Isolating and collating the protocol code in one place also makes it very easy
32to maintain and understand.
33
34So it if highly recommended you put your protocol-specific code into the
35form of a "plugin" at the source level, even if you have no immediate plan to
36use it dynamically-loaded.
37
38@section writeable Only send data when socket writeable
39
40You should only send data on a websocket connection from the user callback
41`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for
42clients).
43
44If you want to send something, do NOT just send it but request a callback
45when the socket is writeable using
46
47 - `lws_callback_on_writable(wsi)` for a specific `wsi`, or
48
49 - `lws_callback_on_writable_all_protocol(protocol)` for all connections
50using that protocol to get a callback when next writeable.
51
52Usually you will get called back immediately next time around the service
53loop, but if your peer is slow or temporarily inactive the callback will be
54delayed accordingly. Generating what to write and sending it should be done
55in the ...WRITEABLE callback.
56
57See the test server code for an example of how to do this.
58
59Otherwise evolved libs like libuv get this wrong, they will allow you to "send"
60anything you want but it only uses up your local memory (and costs you
61memcpys) until the socket can actually accept it. It is much better to regulate
62your send action by the downstream peer readiness to take new data in the first
63place, avoiding all the wasted buffering.
64
65Libwebsockets' concept is that the downstream peer is truly the boss, if he,
66or our connection to him, cannot handle anything new, we should not generate
67anything new for him. This is how unix shell piping works, you may have
68`cat a.txt | grep xyz > remote", but actually that does not cat anything from
69a.txt while remote cannot accept anything new.
70
71@section oneper Only one lws_write per WRITEABLE callback
72
73From v2.5, lws strictly enforces only one lws_write() per WRITEABLE callback.
74
75You will receive a message about "Illegal back-to-back write of ... detected"
76if there is a second lws_write() before returning to the event loop.
77
78This is because with http/2, the state of the network connection carrying a
79wsi is unrelated to any state of the wsi. The situation on http/1 where a
80new request implied a new tcp connection and new SSL buffer, so you could
81assume some window for writes is no longer true. Any lws_write() can fail
82and be buffered for completion by lws; it will be auto-completed by the
83event loop.
84
85Note that if you are handling your own http responses, writing the headers
86needs to be done with a separate lws_write() from writing any payload. That
87means after writing the headers you must call `lws_callback_on_writable(wsi)`
88and send any payload from the writable callback.
89
90@section otherwr Do not rely on only your own WRITEABLE requests appearing
91
92Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events
93if it met network conditions where it had to buffer your send data internally.
94
95So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision
96about what to send, it can't assume that just because the writeable callback
97came something is ready to send.
98
99It's quite possible you get an 'extra' writeable callback at any time and
100just need to `return 0` and wait for the expected callback later.
101
102@section dae Daemonization
103
104There's a helper api `lws_daemonize` built by default that does everything you
105need to daemonize well, including creating a lock file. If you're making
106what's basically a daemon, just call this early in your init to fork to a
107headless background process and exit the starting process.
108
109Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your
110daemon is headless, so you'll need to sort out alternative logging, by, eg,
111syslog via `lws_set_log_level(..., lwsl_emit_syslog)`.
112
113@section conns Maximum number of connections
114
115The maximum number of connections the library can deal with is decided when
116it starts by querying the OS to find out how many file descriptors it is
117allowed to open (1024 on Fedora for example). It then allocates arrays that
118allow up to that many connections, minus whatever other file descriptors are
119in use by the user code.
120
121If you want to restrict that allocation, or increase it, you can use ulimit or
122similar to change the available number of file descriptors, and when restarted
123**libwebsockets** will adapt accordingly.
124
125@section peer_limits optional LWS_WITH_PEER_LIMITS
126
127If you select `LWS_WITH_PEER_LIMITS` at cmake, then lws will track peer IPs
128and monitor how many connections and ah resources they are trying to use
129at one time. You can choose to limit these at context creation time, using
130`info.ip_limit_ah` and `info.ip_limit_wsi`.
131
132Note that although the ah limit is 'soft', ie, the connection will just wait
133until the IP is under the ah limit again before attaching a new ah, the
134wsi limit is 'hard', lws will drop any additional connections from the
135IP until it's under the limit again.
136
137If you use these limits, you should consider multiple clients may simultaneously
138try to access the site through NAT, etc. So the limits should err on the side
139of being generous, while still making it impossible for one IP to exhaust
140all the server resources.
141
142@section evtloop Libwebsockets is singlethreaded
143
144Libwebsockets works in a serialized event loop, in a single thread. It supports
145the default poll() backend, and libuv, libev, and libevent event loop
146libraries that also take this locking-free, nonblocking event loop approach that
147is not threadsafe. There are several advantages to this technique, but one
148disadvantage, it doesn't integrate easily if there are multiple threads that
149want to use libwebsockets.
150
151However integration to multithreaded apps is possible if you follow some guidelines.
152
1531) Aside from two APIs, directly calling lws apis from other threads is not allowed.
154
1552) If you want to keep a list of live wsi, you need to use lifecycle callbacks on
156the protocol in the service thread to manage the list, with your own locking.
157Typically you use an ESTABLISHED callback to add ws wsi to your list and a CLOSED
158callback to remove them.
159
1603) LWS regulates your write activity by being able to let you know when you may
161write more on a connection. That reflects the reality that you cannot succeed to
162send data to a peer that has no room for it, so you should not generate or buffer
163write data until you know the peer connection can take more.
164
165Other libraries pretend that the guy doing the writing is the boss who decides
166what happens, and absorb as much as you want to write to local buffering. That does
167not scale to a lot of connections, because it will exhaust your memory and waste
168time copying data around in memory needlessly.
169
170The truth is the receiver, along with the network between you, is the boss who
171decides what will happen. If he stops accepting data, no data will move. LWS is
172designed to reflect that.
173
174If you have something to send, you call `lws_callback_on_writable()` on the
175connection, and when it is writeable, you will get a `LWS_CALLBACK_SERVER_WRITEABLE`
176callback, where you should generate the data to send and send it with `lws_write()`.
177
178You cannot send data using `lws_write()` outside of the WRITEABLE callback.
179
1804) For multithreaded apps, this corresponds to a need to be able to provoke the
181`lws_callback_on_writable()` action and to wake the service thread from its event
182loop wait (sleeping in `poll()` or `epoll()` or whatever). The rules above
183mean directly sending data on the connection from another thread is out of the
184question.
185
186Therefore the two apis mentioned above that may be used from another thread are
187
188 - For LWS using the default poll() event loop, `lws_callback_on_writable()`
189
190 - For LWS using libuv/libev/libevent event loop, `lws_cancel_service()`
191
192If you are using the default poll() event loop, one "foreign thread" at a time may
193call `lws_callback_on_writable()` directly for a wsi. You need to use your own
194locking around that to serialize multiple thread access to it.
195
196If you implement LWS_CALLBACK_GET_THREAD_ID in protocols[0], then LWS will detect
197when it has been called from a foreign thread and automatically use
198`lws_cancel_service()` to additionally wake the service loop from its wait.
199
200For libuv/libev/libevent event loop, they cannot handle being called from other
201threads. So there is a slightly different scheme, you may call `lws_cancel_service()`
202to force the event loop to end immediately. This then broadcasts a callback (in the
203service thread context) `LWS_CALLBACK_EVENT_WAIT_CANCELLED`, to all protocols on all
204vhosts, where you can perform your own locking and walk a list of wsi that need
205`lws_callback_on_writable()` calling on them.
206
207`lws_cancel_service()` is very cheap to call.
208
2095) The obverse of this truism about the receiver being the boss is the case where
210we are receiving. If we get into a situation we actually can't usefully
211receive any more, perhaps because we are passing the data on and the guy we want
212to send to can't receive any more, then we should "turn off RX" by using the
213RX flow control API, `lws_rx_flow_control(wsi, 0)`. When something happens where we
214can accept more RX, (eg, we learn our onward connection is writeable) we can call
215it again to re-enable it on the incoming wsi.
216
217LWS stops calling back about RX immediately you use flow control to disable RX, it
218buffers the data internally if necessary. So you will only see RX when you can
219handle it. When flow control is disabled, LWS stops taking new data in... this makes
220the situation known to the sender by TCP "backpressure", the tx window fills and the
221sender finds he cannot write any more to the connection.
222
223See the mirror protocol implementations for example code.
224
225If you need to service other socket or file descriptors as well as the
226websocket ones, you can combine them together with the websocket ones
227in one poll loop, see "External Polling Loop support" below, and
228still do it all in one thread / process context. If the need is less
229architectural, you can also create RAW mode client and serving sockets; this
230is how the lws plugin for the ssh server works.
231
232@section anonprot Working without a protocol name
233
234Websockets allows connections to negotiate without a protocol name...
235in that case by default it will bind to the first protocol in your
236vhost protocols[] array.
237
238You can tell the vhost to use a different protocol by attaching a
239pvo (per-vhost option) to the
240
241```
242/*
243 * this sets a per-vhost, per-protocol option name:value pair
244 * the effect is to set this protocol to be the default one for the vhost,
245 * ie, selected if no Protocol: header is sent with the ws upgrade.
246 */
247
248static const struct lws_protocol_vhost_options pvo_opt = {
249 NULL,
250 NULL,
251 "default",
252 "1"
253};
254
255static const struct lws_protocol_vhost_options pvo = {
256 NULL,
257 &pvo_opt,
258 "my-protocol",
259 ""
260};
261
262...
263
264 context_info.pvo = &pvo;
265...
266
267```
268
269Will select "my-protocol" from your protocol list (even if it came
270in by plugin) as being the target of client connections that don't
271specify a protocol.
272
273@section closing Closing connections from the user side
274
275When you want to close a connection, you do it by returning `-1` from a
276callback for that connection.
277
278You can provoke a callback by calling `lws_callback_on_writable` on
279the wsi, then notice in the callback you want to close it and just return -1.
280But usually, the decision to close is made in a callback already and returning
281-1 is simple.
282
283If the socket knows the connection is dead, because the peer closed or there
284was an affirmitive network error like a FIN coming, then **libwebsockets** will
285take care of closing the connection automatically.
286
287If you have a silently dead connection, it's possible to enter a state where
288the send pipe on the connection is choked but no ack will ever come, so the
289dead connection will never become writeable. To cover that, you can use TCP
290keepalives (see later in this document) or pings.
291
292@section gzip Serving from inside a zip file
293
294Lws now supports serving gzipped files from inside a zip container. Thanks to
295Per Bothner for contributing the code.
296
297This has the advtantage that if the client can accept GZIP encoding, lws can
298simply send the gzip-compressed file from inside the zip file with no further
299processing, saving time and bandwidth.
300
301In the case the client can't understand gzip compression, lws automatically
302decompressed the file and sends it normally.
303
304Clients with limited storage and RAM will find this useful; the memory needed
305for the inflate case is constrained so that only one input buffer at a time
306is ever in memory.
307
308To use this feature, ensure LWS_WITH_ZIP_FOPS is enabled at CMake.
309
310`libwebsockets-test-server-v2.0` includes a mount using this technology
311already, run that test server and navigate to http://localhost:7681/ziptest/candide.html
312
313This will serve the book Candide in html, together with two jpgs, all from
314inside a .zip file in /usr/[local/]share-libwebsockets-test-server/candide.zip
315
316Usage is otherwise automatic, if you arrange a mount that points to the zipfile,
317eg, "/ziptest" -> "mypath/test.zip", then URLs like `/ziptest/index.html` will be
318servied from `index.html` inside `mypath/test.zip`
319
320@section frags Fragmented messages
321
322To support fragmented messages you need to check for the final
323frame of a message with `lws_is_final_fragment`. This
324check can be combined with `libwebsockets_remaining_packet_payload`
325to gather the whole contents of a message, eg:
326
327```
328 case LWS_CALLBACK_RECEIVE:
329 {
330 Client * const client = (Client *)user;
331 const size_t remaining = lws_remaining_packet_payload(wsi);
332
333 if (!remaining && lws_is_final_fragment(wsi)) {
334 if (client->HasFragments()) {
335 client->AppendMessageFragment(in, len, 0);
336 in = (void *)client->GetMessage();
337 len = client->GetMessageLength();
338 }
339
340 client->ProcessMessage((char *)in, len, wsi);
341 client->ResetMessage();
342 } else
343 client->AppendMessageFragment(in, len, remaining);
344 }
345 break;
346```
347
348The test app libwebsockets-test-fraggle sources also show how to
349deal with fragmented messages.
350
351
352@section debuglog Debug Logging
353
354Also using `lws_set_log_level` api you may provide a custom callback to actually
355emit the log string. By default, this points to an internal emit function
356that sends to stderr. Setting it to `NULL` leaves it as it is instead.
357
358A helper function `lwsl_emit_syslog()` is exported from the library to simplify
359logging to syslog. You still need to use `setlogmask`, `openlog` and `closelog`
360in your user code.
361
362The logging apis are made available for user code.
363
364- `lwsl_err(...)`
365- `lwsl_warn(...)`
366- `lwsl_notice(...)`
367- `lwsl_info(...)`
368- `lwsl_debug(...)`
369
370The difference between notice and info is that notice will be logged by default
371whereas info is ignored by default.
372
373If you are not building with _DEBUG defined, ie, without this
374
375```
376 $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG
377```
378
379then log levels below notice do not actually get compiled in.
380
381@section asan Building with ASAN
382
383Under GCC you can select for the build to be instrumented with the Address
384Sanitizer, using `cmake .. -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_ASAN=1`. LWS is routinely run during development with valgrind, but ASAN is capable of finding different issues at runtime, like operations which are not strictly defined in the C
385standard and depend on platform behaviours.
386
387Run your application like this
388
389```
390 $ sudo ASAN_OPTIONS=verbosity=2:halt_on_error=1 /usr/local/bin/lwsws
391```
392
393and attach gdb to catch the place it halts.
394
395@section extpoll External Polling Loop support
396
397**libwebsockets** maintains an internal `poll()` array for all of its
398sockets, but you can instead integrate the sockets into an
399external polling array. That's needed if **libwebsockets** will
400cooperate with an existing poll array maintained by another
401server.
402
403Three callbacks `LWS_CALLBACK_ADD_POLL_FD`, `LWS_CALLBACK_DEL_POLL_FD`
404and `LWS_CALLBACK_CHANGE_MODE_POLL_FD` appear in the callback for protocol 0
405and allow interface code to manage socket descriptors in other poll loops.
406
407You can pass all pollfds that need service to `lws_service_fd()`, even
408if the socket or file does not belong to **libwebsockets** it is safe.
409
410If **libwebsocket** handled it, it zeros the pollfd `revents` field before returning.
411So you can let **libwebsockets** try and if `pollfd->revents` is nonzero on return,
412you know it needs handling by your code.
413
414Also note that when integrating a foreign event loop like libev or libuv where
415it doesn't natively use poll() semantics, and you must return a fake pollfd
416reflecting the real event:
417
418 - be sure you set .events to .revents value as well in the synthesized pollfd
419
420 - check the built-in support for the event loop if possible (eg, ./lib/libuv.c)
421 to see how it interfaces to lws
422
423 - use LWS_POLLHUP / LWS_POLLIN / LWS_POLLOUT from libwebsockets.h to avoid
424 losing windows compatibility
425
426You also need to take care about "forced service" somehow... these are cases
427where the network event was consumed, incoming data was all read, for example,
428but the work arising from it was not completed. There will not be any more
429network event to trigger the remaining work, Eg, we read compressed data, but
430we did not use up all the decompressed data before returning to the event loop
431because we had to write some of it.
432
433Lws provides an API to determine if anyone is waiting for forced service,
434`lws_service_adjust_timeout(context, 1, tsi)`, normally tsi is 0. If it returns
4350, then at least one connection has pending work you can get done by calling
436`lws_service_tsi(context, -1, tsi)`, again normally tsi is 0.
437
438For eg, the default poll() event loop, or libuv/ev/event, lws does this
439checking for you and handles it automatically. But in the external polling
440loop case, you must do it explicitly. Handling it after every normal service
441triggered by the external poll fd should be enough, since the situations needing
442it are initially triggered by actual network events.
443
444An example of handling it is shown in the test-server code specific to
445external polling.
446
447@section cpp Using with in c++ apps
448
449The library is ready for use by C++ apps. You can get started quickly by
450copying the test server
451
452```
453 $ cp test-apps/test-server.c test.cpp
454```
455
456and building it in C++ like this
457
458```
459 $ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets
460```
461
462`INSTALL_DATADIR` is only needed because the test server uses it as shipped, if
463you remove the references to it in your app you don't need to define it on
464the g++ line either.
465
466
467@section headerinfo Availability of header information
468
469HTTP Header information is managed by a pool of "ah" structs. These are a
470limited resource so there is pressure to free the headers and return the ah to
471the pool for reuse.
472
473For that reason header information on HTTP connections that get upgraded to
474websockets is lost after the ESTABLISHED callback. Anything important that
475isn't processed by user code before then should be copied out for later.
476
477For HTTP connections that don't upgrade, header info remains available the
478whole time.
479
480@section http2compat Code Requirements for HTTP/2 compatibility
481
482Websocket connections only work over http/1, so there is nothing special to do
483when you want to enable -DLWS_WITH_HTTP2=1.
484
485The internal http apis already follow these requirements and are compatible with
486http/2 already. So if you use stuff like mounts and serve stuff out of the
487filesystem, there's also nothing special to do.
488
489However if you are getting your hands dirty with writing response headers, or
490writing bulk data over http/2, you need to observe these rules so that it will
491work over both http/1.x and http/2 the same.
492
4931) LWS_PRE requirement applies on ALL lws_write(). For http/1, you don't have
494to take care of LWS_PRE for http data, since it is just sent straight out.
495For http/2, it will write up to LWS_PRE bytes behind the buffer start to create
496the http/2 frame header.
497
498This has implications if you treated the input buffer to lws_write() as const...
499it isn't any more with http/2, up to 9 bytes behind the buffer will be trashed.
500
5012) Headers are encoded using a sophisticated scheme in http/2. The existing
502header access apis are already made compatible for incoming headers,
503for outgoing headers you must:
504
505 - observe the LWS_PRE buffer requirement mentioned above
506
507 - Use `lws_add_http_header_status()` to add the transaction status (200 etc)
508
509 - use lws apis `lws_add_http_header_by_name()` and `lws_add_http_header_by_token()`
510 to put the headers into the buffer (these will translate what is actually
511 written to the buffer depending on if the connection is in http/2 mode or not)
512
513 - use the `lws api lws_finalize_http_header()` api after adding the last
514 response header
515
516 - write the header using lws_write(..., `LWS_WRITE_HTTP_HEADERS`);
517
518 3) http/2 introduces per-stream transmit credit... how much more you can send
519 on a stream is decided by the peer. You start off with some amount, as the
520 stream sends stuff lws will reduce your credit accordingly, when it reaches
521 zero, you must not send anything further until lws receives "more credit" for
522 that stream the peer. Lws will suppress writable callbacks if you hit 0 until
523 more credit for the stream appears, and lws built-in file serving (via mounts
524 etc) already takes care of observing the tx credit restrictions. However if
525 you write your own code that wants to send http data, you must consult the
526 `lws_get_peer_write_allowance()` api to find out the state of your tx credit.
527 For http/1, it will always return (size_t)-1, ie, no limit.
528
529 This is orthogonal to the question of how much space your local side's kernel
530 will make to buffer your send data on that connection. So although the result
531 from `lws_get_peer_write_allowance()` is "how much you can send" logically,
532 and may be megabytes if the peer allows it, you should restrict what you send
533 at one time to whatever your machine will generally accept in one go, and
534 further reduce that amount if `lws_get_peer_write_allowance()` returns
535 something smaller. If it returns 0, you should not consume or send anything
536 and return having asked for callback on writable, it will only come back when
537 more tx credit has arrived for your stream.
538
539 4) Header names with captital letters are illegal in http/2. Header names in
540 http/1 are case insensitive. So if you generate headers by name, change all
541 your header name strings to lower-case to be compatible both ways.
542
543 5) Chunked Transfer-encoding is illegal in http/2, http/2 peers will actively
544 reject it. Lws takes care of removing the header and converting CGIs that
545 emit chunked into unchunked automatically for http/2 connections.
546
547If you follow these rules, your code will automatically work with both http/1.x
548and http/2.
549
550@section ka TCP Keepalive
551
552It is possible for a connection which is not being used to send to die
553silently somewhere between the peer and the side not sending. In this case
554by default TCP will just not report anything and you will never get any more
555incoming data or sign the link is dead until you try to send.
556
557To deal with getting a notification of that situation, you can choose to
558enable TCP keepalives on all **libwebsockets** sockets, when you create the
559context.
560
561To enable keepalive, set the ka_time member of the context creation parameter
562struct to a nonzero value (in seconds) at context creation time. You should
563also fill ka_probes and ka_interval in that case.
564
565With keepalive enabled, the TCP layer will send control packets that should
566stimulate a response from the peer without affecting link traffic. If the
567response is not coming, the socket will announce an error at `poll()` forcing
568a close.
569
570Note that BSDs don't support keepalive time / probes / interval per-socket
571like Linux does. On those systems you can enable keepalive by a nonzero
572value in `ka_time`, but the systemwide kernel settings for the time / probes/
573interval are used, regardless of what nonzero value is in `ka_time`.
574
575
576@section sslopt Optimizing SSL connections
577
578There's a member `ssl_cipher_list` in the `lws_context_creation_info` struct
579which allows the user code to restrict the possible cipher selection at
580context-creation time.
581
582You might want to look into that to stop the ssl peers selecting a cipher which
583is too computationally expensive. To use it, point it to a string like
584
585 `"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"`
586
587if left `NULL`, then the "DEFAULT" set of ciphers are all possible to select.
588
589You can also set it to `"ALL"` to allow everything (including insecure ciphers).
590
591
592@section sslcerts Passing your own cert information direct to SSL_CTX
593
594For most users it's enough to pass the SSL certificate and key information by
595giving filepaths to the info.ssl_cert_filepath and info.ssl_private_key_filepath
596members when creating the vhost.
597
598If you want to control that from your own code instead, you can do so by leaving
599the related info members NULL, and setting the info.options flag
600LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX at vhost creation time. That will create
601the vhost SSL_CTX without any certificate, and allow you to use the callback
602LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS to add your certificate to
603the SSL_CTX directly. The vhost SSL_CTX * is in the user parameter in that
604callback.
605
606@section clientasync Async nature of client connections
607
608When you call `lws_client_connect_info(..)` and get a `wsi` back, it does not
609mean your connection is active. It just means it started trying to connect.
610
611Your client connection is actually active only when you receive
612`LWS_CALLBACK_CLIENT_ESTABLISHED` for it.
613
614There's a 5 second timeout for the connection, and it may give up or die for
615other reasons, if any of that happens you'll get a
616`LWS_CALLBACK_CLIENT_CONNECTION_ERROR` callback on protocol 0 instead for the
617`wsi`.
618
619After attempting the connection and getting back a non-`NULL` `wsi` you should
620loop calling `lws_service()` until one of the above callbacks occurs.
621
622As usual, see [test-client.c](../test-apps/test-client.c) for example code.
623
624Notice that the client connection api tries to progress the connection
625somewhat before returning. That means it's possible to get callbacks like
626CONNECTION_ERROR on the new connection before your user code had a chance to
627get the wsi returned to identify it (in fact if the connection did fail early,
628NULL will be returned instead of the wsi anyway).
629
630To avoid that problem, you can fill in `pwsi` in the client connection info
631struct to point to a struct lws that get filled in early by the client
632connection api with the related wsi. You can then check for that in the
633callback to confirm the identity of the failing client connection.
634
635
636@section fileapi Lws platform-independent file access apis
637
638lws now exposes his internal platform file abstraction in a way that can be
639both used by user code to make it platform-agnostic, and be overridden or
640subclassed by user code. This allows things like handling the URI "directory
641space" as a virtual filesystem that may or may not be backed by a regular
642filesystem. One example use is serving files from inside large compressed
643archive storage without having to unpack anything except the file being
644requested.
645
646The test server shows how to use it, basically the platform-specific part of
647lws prepares a file operations structure that lives in the lws context.
648
649The user code can get a pointer to the file operations struct
650
651```
652 LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
653 `lws_get_fops`(struct lws_context *context);
654```
655
656and then can use helpers to also leverage these platform-independent
657file handling apis
658
659```
660 lws_fop_fd_t
661 `lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename,
662 lws_fop_flags_t *flags)
663 int
664 `lws_plat_file_close`(lws_fop_fd_t fop_fd)
665
666 unsigned long
667 `lws_plat_file_seek_cur`(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
668
669 int
670 `lws_plat_file_read`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
671 uint8_t *buf, lws_filepos_t len)
672
673 int
674 `lws_plat_file_write`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
675 uint8_t *buf, lws_filepos_t len )
676```
677
678Generic helpers are provided which provide access to generic fops information or
679call through to the above fops
680
681```
682lws_filepos_t
683lws_vfs_tell(lws_fop_fd_t fop_fd);
684
685lws_filepos_t
686lws_vfs_get_length(lws_fop_fd_t fop_fd);
687
688uint32_t
689lws_vfs_get_mod_time(lws_fop_fd_t fop_fd);
690
691lws_fileofs_t
692lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
693
694lws_fileofs_t
695lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
696```
697
698
699The user code can also override or subclass the file operations, to either
700wrap or replace them. An example is shown in test server.
701
702### Changes from v2.1 and before fops
703
704There are several changes:
705
7061) Pre-2.2 fops directly used platform file descriptors. Current fops returns and accepts a wrapper type lws_fop_fd_t which is a pointer to a malloc'd struct containing information specific to the filesystem implementation.
707
7082) Pre-2.2 fops bound the fops to a wsi. This is completely removed, you just give a pointer to the fops struct that applies to this file when you open it. Afterwards, the operations in the fops just need the lws_fop_fd_t returned from the open.
709
7103) Everything is wrapped in typedefs. See lws-plat-unix.c for examples of how to implement.
711
7124) Position in the file, File Length, and a copy of Flags left after open are now generically held in the fop_fd.
713VFS implementation must set and manage this generic information now. See the implementations in lws-plat-unix.c for
714examples.
715
7165) The file length is no longer set at a pointer provided by the open() fop. The api `lws_vfs_get_length()` is provided to
717get the file length after open.
718
7196) If your file namespace is virtual, ie, is not reachable by platform fops directly, you must set LWS_FOP_FLAG_VIRTUAL
720on the flags during open.
721
7227) There is an optional `mod_time` uint32_t member in the generic fop_fd. If you are able to set it during open, you
723should indicate it by setting `LWS_FOP_FLAG_MOD_TIME_VALID` on the flags.
724
725@section rawfd RAW file descriptor polling
726
727LWS allows you to include generic platform file descriptors in the lws service / poll / event loop.
728
729Open your fd normally and then
730
731```
732 lws_sock_file_fd_type u;
733
734 u.filefd = your_open_file_fd;
735
736 if (!lws_adopt_descriptor_vhost(vhost, 0, u,
737 "protocol-name-to-bind-to",
738 optional_wsi_parent_or_NULL)) {
739 // failed
740 }
741
742 // OK
743```
744
745A wsi is created for the file fd that acts like other wsi, you will get these
746callbacks on the named protocol
747
748```
749 LWS_CALLBACK_RAW_ADOPT_FILE
750 LWS_CALLBACK_RAW_RX_FILE
751 LWS_CALLBACK_RAW_WRITEABLE_FILE
752 LWS_CALLBACK_RAW_CLOSE_FILE
753```
754
755starting with LWS_CALLBACK_RAW_ADOPT_FILE.
756
757The minimal example `raw/minimal-raw-file` demonstrates how to use it.
758
759`protocol-lws-raw-test` plugin also provides a method for testing this with
760`libwebsockets-test-server-v2.0`:
761
762The plugin creates a FIFO on your system called "/tmp/lws-test-raw"
763
764You can feed it data through the FIFO like this
765
766```
767 $ sudo sh -c "echo hello > /tmp/lws-test-raw"
768```
769
770This plugin simply prints the data. But it does it through the lws event
771loop / service poll.
772
773@section rawsrvsocket RAW server socket descriptor polling
774
775You can also enable your vhost to accept RAW socket connections, in addition to
776HTTP[s] and WS[s]. If the first bytes written on the connection are not a
777valid HTTP method, then the connection switches to RAW mode.
778
779This is disabled by default, you enable it by setting the `.options` flag
780LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG, and setting
781`.listen_accept_role` to `"raw-skt"` when creating the vhost.
782
783RAW mode socket connections receive the following callbacks
784
785```
786 LWS_CALLBACK_RAW_ADOPT
787 LWS_CALLBACK_RAW_RX
788 LWS_CALLBACK_RAW_WRITEABLE
789 LWS_CALLBACK_RAW_CLOSE
790```
791
792You can control which protocol on your vhost handles these RAW mode
793incoming connections by setting the vhost info struct's `.listen_accept_protocol`
794to the vhost protocol name to use.
795
796`protocol-lws-raw-test` plugin provides a method for testing this with
797`libwebsockets-test-server-v2.0`:
798
799Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg
800
801```
802 $ telnet 127.0.0.1 7681
803```
804
805type something that isn't a valid HTTP method and enter, before the
806connection times out. The connection will switch to RAW mode using this
807protocol, and pass the unused rx as a raw RX callback.
808
809The test protocol echos back what was typed on telnet to telnet.
810
811@section rawclientsocket RAW client socket descriptor polling
812
813You can now also open RAW socket connections in client mode.
814
815Follow the usual method for creating a client connection, but set the
816`info.method` to "RAW". When the connection is made, the wsi will be
817converted to RAW mode and operate using the same callbacks as the
818server RAW sockets described above.
819
820The libwebsockets-test-client supports this using raw:// URLS. To
821test, open a netcat listener in one window
822
823```
824 $ nc -l 9999
825```
826
827and in another window, connect to it using the test client
828
829```
830 $ libwebsockets-test-client raw://127.0.0.1:9999
831```
832
833The connection should succeed, and text typed in the netcat window (including a CRLF)
834will be received in the client.
835
836@section rawudp RAW UDP socket integration
837
838Lws provides an api to create, optionally bind, and adopt a RAW UDP
839socket (RAW here means an uninterpreted normal UDP socket, not a
840"raw socket").
841
842```
843LWS_VISIBLE LWS_EXTERN struct lws *
844lws_create_adopt_udp(struct lws_vhost *vhost, int port, int flags,
845 const char *protocol_name, struct lws *parent_wsi);
846```
847
848`flags` should be `LWS_CAUDP_BIND` if the socket will receive packets.
849
850The callbacks `LWS_CALLBACK_RAW_ADOPT`, `LWS_CALLBACK_RAW_CLOSE`,
851`LWS_CALLBACK_RAW_RX` and `LWS_CALLBACK_RAW_WRITEABLE` apply to the
852wsi. But UDP is different than TCP in some fundamental ways.
853
854For receiving on a UDP connection, data becomes available at
855`LWS_CALLBACK_RAW_RX` as usual, but because there is no specific
856connection with UDP, it is necessary to also get the source address of
857the data separately, using `struct lws_udp * lws_get_udp(wsi)`.
858You should take a copy of the `struct lws_udp` itself (not the
859pointer) and save it for when you want to write back to that peer.
860
861Writing is also a bit different for UDP. By default, the system has no
862idea about the receiver state and so asking for a `callback_on_writable()`
863always believes that the socket is writeable... the callback will
864happen next time around the event loop.
865
866With UDP, there is no single "connection". You need to write with sendto() and
867direct the packets to a specific destination. To return packets to a
868peer who sent something earlier and you copied his `struct lws_udp`, you
869use the .sa and .salen members as the last two parameters of the sendto().
870
871The kernel may not accept to buffer / write everything you wanted to send.
872So you are responsible to watch the result of sendto() and resend the
873unsent part next time (which may involve adding new protocol headers to
874the remainder depending on what you are doing).
875
876@section ecdh ECDH Support
877
878ECDH Certs are now supported. Enable the CMake option
879
880 cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1
881
882**and** the info->options flag
883
884 LWS_SERVER_OPTION_SSL_ECDH
885
886to build in support and select it at runtime.
887
888@section sslinfo SSL info callbacks
889
890OpenSSL allows you to receive callbacks for various events defined in a
891bitmask in openssl/ssl.h. The events include stuff like TLS Alerts.
892
893By default, lws doesn't register for these callbacks.
894
895However if you set the info.ssl_info_event_mask to nonzero (ie, set some
896of the bits in it like `SSL_CB_ALERT` at vhost creation time, then
897connections to that vhost will call back using LWS_CALLBACK_SSL_INFO
898for the wsi, and the `in` parameter will be pointing to a struct of
899related args:
900
901```
902struct lws_ssl_info {
903 int where;
904 int ret;
905};
906```
907
908The default callback handler in lws has a handler for LWS_CALLBACK_SSL_INFO
909which prints the related information, You can test it using the switch
910-S -s on `libwebsockets-test-server-v2.0`.
911
912Returning nonzero from the callback will close the wsi.
913
914@section smp SMP / Multithreaded service
915
916SMP support is integrated into LWS without any internal threading. It's
917very simple to use, libwebsockets-test-server-pthread shows how to do it,
918use -j n argument there to control the number of service threads up to 32.
919
920Two new members are added to the info struct
921
922 unsigned int count_threads;
923 unsigned int fd_limit_per_thread;
924
925leave them at the default 0 to get the normal singlethreaded service loop.
926
927Set count_threads to n to tell lws you will have n simultaneous service threads
928operating on the context.
929
930There is still a single listen socket on one port, no matter how many
931service threads.
932
933When a connection is made, it is accepted by the service thread with the least
934connections active to perform load balancing.
935
936The user code is responsible for spawning n threads running the service loop
937associated to a specific tsi (Thread Service Index, 0 .. n - 1). See
938the libwebsockets-test-server-pthread for how to do.
939
940If you leave fd_limit_per_thread at 0, then the process limit of fds is shared
941between the service threads; if you process was allowed 1024 fds overall then
942each thread is limited to 1024 / n.
943
944You can set fd_limit_per_thread to a nonzero number to control this manually, eg
945the overall supported fd limit is less than the process allowance.
946
947You can control the context basic data allocation for multithreading from Cmake
948using -DLWS_MAX_SMP=, if not given it's set to 1. The serv_buf allocation
949for the threads (currently 4096) is made at runtime only for active threads.
950
951Because lws will limit the requested number of actual threads supported
952according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to
953discover how many threads were actually allowed when the context was created.
954
955See the test-server-pthreads.c sample for how to use.
956
957@section smplocking SMP Locking Helpers
958
959Lws provide a set of pthread mutex helpers that reduce to no code or
960variable footprint in the case that LWS_MAX_SMP == 1.
961
962Define your user mutex like this
963
964```
965 lws_pthread_mutex(name);
966```
967
968If LWS_MAX_SMP > 1, this produces `pthread_mutex_t name;`. In the case
969LWS_MAX_SMP == 1, it produces nothing.
970
971Likewise these helpers for init, destroy, lock and unlock
972
973
974```
975 void lws_pthread_mutex_init(pthread_mutex_t *lock)
976 void lws_pthread_mutex_destroy(pthread_mutex_t *lock)
977 void lws_pthread_mutex_lock(pthread_mutex_t *lock)
978 void lws_pthread_mutex_unlock(pthread_mutex_t *lock)
979```
980
981resolve to nothing if LWS_MAX_SMP == 1, otherwise produce the equivalent
982pthread api.
983
984pthreads is required in lws only if LWS_MAX_SMP > 1.
985
986
987@section libevuv libev / libuv / libevent support
988
989You can select either or both
990
991 -DLWS_WITH_LIBEV=1
992 -DLWS_WITH_LIBUV=1
993 -DLWS_WITH_LIBEVENT=1
994
995at cmake configure-time. The user application may use one of the
996context init options flags
997
998 LWS_SERVER_OPTION_LIBEV
999 LWS_SERVER_OPTION_LIBUV
1000 LWS_SERVER_OPTION_LIBEVENT
1001
1002to indicate it will use one of the event libraries at runtime.
1003
1004libev and libevent headers conflict, they both define critical constants like
1005EV_READ to different values. Attempts to discuss clearing that up with both
1006libevent and libev did not get anywhere useful. Therefore CMakeLists.txt will
1007error out if you enable both LWS_WITH_LIBEV and LWS_WITH_LIBEVENT.
1008
1009In addition depending on libev / compiler version, building anything with libev
1010apis using gcc may blow strict alias warnings (which are elevated to errors in
1011lws). I did some googling at found these threads related to it, the issue goes
1012back at least to 2010 on and off
1013
1014https://github.com/redis/hiredis/issues/434
1015https://bugs.gentoo.org/show_bug.cgi?id=615532
1016http://lists.schmorp.de/pipermail/libev/2010q1/000916.html
1017http://lists.schmorp.de/pipermail/libev/2010q1/000920.html
1018http://lists.schmorp.de/pipermail/libev/2010q1/000923.html
1019
1020We worked around this problem by disabling -Werror on the parts of lws that
1021use libev. FWIW as of Dec 2019 using Fedora 31 libev 4.27.1 and its gcc 9.2.1
1022doesn't seem to trigger the problem even without the workaround.
1023
1024For these reasons and the response I got trying to raise these issues with
1025them, if you have a choice about event loop, I would gently encourage you
1026to avoid libev. Where lws uses an event loop itself, eg in lwsws, we use
1027libuv.
1028
1029@section extopts Extension option control from user code
1030
1031User code may set per-connection extension options now, using a new api
1032`lws_set_extension_option()`.
1033
1034This should be called from the ESTABLISHED callback like this
1035```
1036 lws_set_extension_option(wsi, "permessage-deflate",
1037 "rx_buf_size", "12"); /* 1 << 12 */
1038```
1039
1040If the extension is not active (missing or not negotiated for the
1041connection, or extensions are disabled on the library) the call is
1042just returns -1. Otherwise the connection's extension has its
1043named option changed.
1044
1045The extension may decide to alter or disallow the change, in the
1046example above permessage-deflate restricts the size of his rx
1047output buffer also considering the protocol's rx_buf_size member.
1048
1049
1050@section httpsclient Client connections as HTTP[S] rather than WS[S]
1051
1052You may open a generic http client connection using the same
1053struct lws_client_connect_info used to create client ws[s]
1054connections.
1055
1056To stay in http[s], set the optional info member "method" to
1057point to the string "GET" instead of the default NULL.
1058
1059After the server headers are processed, when payload from the
1060server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP
1061will be made.
1062
1063You can choose whether to process the data immediately, or
1064queue a callback when an outgoing socket is writeable to provide
1065flow control, and process the data in the writable callback.
1066
1067Either way you use the api `lws_http_client_read()` to access the
1068data, eg
1069
1070```
1071 case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
1072 {
1073 char buffer[1024 + LWS_PRE];
1074 char *px = buffer + LWS_PRE;
1075 int lenx = sizeof(buffer) - LWS_PRE;
1076
1077 lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n");
1078
1079 /*
1080 * Often you need to flow control this by something
1081 * else being writable. In that case call the api
1082 * to get a callback when writable here, and do the
1083 * pending client read in the writeable callback of
1084 * the output.
1085 */
1086 if (lws_http_client_read(wsi, &px, &lenx) < 0)
1087 return -1;
1088 while (lenx--)
1089 putchar(*px++);
1090 }
1091 break;
1092```
1093
1094Notice that if you will use SSL client connections on a vhost, you must
1095prepare the client SSL context for the vhost after creating the vhost, since
1096this is not normally done if the vhost was set up to listen / serve. Call
1097the api lws_init_vhost_client_ssl() to also allow client SSL on the vhost.
1098
1099@section clipipe Pipelining Client Requests to same host
1100
1101If you are opening more client requests to the same host and port, you
1102can give the flag LCCSCF_PIPELINE on `info.ssl_connection` to indicate
1103you wish to pipeline them.
1104
1105Without the flag, the client connections will occur concurrently using a
1106socket and tls wrapper if requested for each connection individually.
1107That is fast, but resource-intensive.
1108
1109With the flag, lws will queue subsequent client connections on the first
1110connection to the same host and port. When it has confirmed from the
1111first connection that pipelining / keep-alive is supported by the server,
1112it lets the queued client pipeline connections send their headers ahead
1113of time to create a pipeline of requests on the server side.
1114
1115In this way only one tcp connection and tls wrapper is required to transfer
1116all the transactions sequentially. It takes a little longer but it
1117can make a significant difference to resources on both sides.
1118
1119If lws learns from the first response header that keepalive is not possible,
1120then it marks itself with that information and detaches any queued clients
1121to make their own individual connections as a fallback.
1122
1123Lws can also intelligently combine multiple ongoing client connections to
1124the same host and port into a single http/2 connection with multiple
1125streams if the server supports it.
1126
1127Unlike http/1 pipelining, with http/2 the client connections all occur
1128simultaneously using h2 stream multiplexing inside the one tcp + tls
1129connection.
1130
1131You can turn off the h2 client support either by not building lws with
1132`-DLWS_WITH_HTTP2=1` or giving the `LCCSCF_NOT_H2` flag in the client
1133connection info struct `ssl_connection` member.
1134
1135@section vhosts Using lws vhosts
1136
1137If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create
1138your context, it won't create a default vhost using the info struct
1139members for compatibility. Instead you can call lws_create_vhost()
1140afterwards to attach one or more vhosts manually.
1141
1142```
1143 LWS_VISIBLE struct lws_vhost *
1144 lws_create_vhost(struct lws_context *context,
1145 struct lws_context_creation_info *info);
1146```
1147
1148lws_create_vhost() uses the same info struct as lws_create_context(),
1149it ignores members related to context and uses the ones meaningful
1150for vhost (marked with VH in libwebsockets.h).
1151
1152```
1153 struct lws_context_creation_info {
1154 int port; /* VH */
1155 const char *iface; /* VH */
1156 const struct lws_protocols *protocols; /* VH */
1157 const struct lws_extension *extensions; /* VH */
1158 ...
1159```
1160
1161When you attach the vhost, if the vhost's port already has a listen socket
1162then both vhosts share it and use SNI (is SSL in use) or the Host: header
1163from the client to select the right one. Or if no other vhost already
1164listening the a new listen socket is created.
1165
1166There are some new members but mainly it's stuff you used to set at
1167context creation time.
1168
1169
1170@section sni How lws matches hostname or SNI to a vhost
1171
1172LWS first strips any trailing :port number.
1173
1174Then it tries to find an exact name match for a vhost listening on the correct
1175port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a
1176vhost named abc.com that is listening on port 1234.
1177
1178If there is no exact match, lws will consider wildcard matches, for example
1179if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will
1180accept a vhost "abc.com" listening on port 1234. If there was a better, exact,
1181match, it will have been chosen in preference to this.
1182
1183Connections with SSL will still have the client go on to check the
1184certificate allows wildcards and error out if not.
1185
1186
1187
1188@section mounts Using lws mounts on a vhost
1189
1190The last argument to lws_create_vhost() lets you associate a linked
1191list of lws_http_mount structures with that vhost's URL 'namespace', in
1192a similar way that unix lets you mount filesystems into areas of your /
1193filesystem how you like and deal with the contents transparently.
1194
1195```
1196 struct lws_http_mount {
1197 struct lws_http_mount *mount_next;
1198 const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */
1199 const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */
1200 const char *def; /* default target, eg, "index.html" */
1201
1202 struct lws_protocol_vhost_options *cgienv;
1203
1204 int cgi_timeout;
1205 int cache_max_age;
1206
1207 unsigned int cache_reusable:1;
1208 unsigned int cache_revalidate:1;
1209 unsigned int cache_intermediaries:1;
1210
1211 unsigned char origin_protocol;
1212 unsigned char mountpoint_len;
1213 };
1214```
1215
1216The last mount structure should have a NULL mount_next, otherwise it should
1217point to the 'next' mount structure in your list.
1218
1219Both the mount structures and the strings must persist until the context is
1220destroyed, since they are not copied but used in place.
1221
1222`.origin_protocol` should be one of
1223
1224```
1225 enum {
1226 LWSMPRO_HTTP,
1227 LWSMPRO_HTTPS,
1228 LWSMPRO_FILE,
1229 LWSMPRO_CGI,
1230 LWSMPRO_REDIR_HTTP,
1231 LWSMPRO_REDIR_HTTPS,
1232 LWSMPRO_CALLBACK,
1233 };
1234```
1235
1236 - LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and
1237serve it automatically.
1238
1239 - LWSMPRO_CGI associates the url namespace with the given CGI executable, which
1240runs when the URL is accessed and the output provided to the client.
1241
1242 - LWSMPRO_REDIR_HTTP and LWSMPRO_REDIR_HTTPS auto-redirect clients to the given
1243origin URL.
1244
1245 - LWSMPRO_CALLBACK causes the http connection to attach to the callback
1246associated with the named protocol (which may be a plugin).
1247
1248
1249@section mountcallback Operation of LWSMPRO_CALLBACK mounts
1250
1251The feature provided by CALLBACK type mounts is binding a part of the URL
1252namespace to a named protocol callback handler.
1253
1254This allows protocol plugins to handle areas of the URL namespace. For example
1255in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin
1256providing "protocol-post-demo" like this
1257
1258```
1259 static const struct lws_http_mount mount_post = {
1260 NULL, /* linked-list pointer to next*/
1261 "/formtest", /* mountpoint in URL namespace on this vhost */
1262 "protocol-post-demo", /* handler */
1263 NULL, /* default filename if none given */
1264 NULL,
1265 0,
1266 0,
1267 0,
1268 0,
1269 0,
1270 LWSMPRO_CALLBACK, /* origin points to a callback */
1271 9, /* strlen("/formtest"), ie length of the mountpoint */
1272 };
1273```
1274
1275Client access to /formtest[anything] will be passed to the callback registered
1276with the named protocol, which in this case is provided by a protocol plugin.
1277
1278Access by all methods, eg, GET and POST are handled by the callback.
1279
1280protocol-post-demo deals with accepting and responding to the html form that
1281is in the test server HTML.
1282
1283When a connection accesses a URL related to a CALLBACK type mount, the
1284connection protocol is changed until the next access on the connection to a
1285URL outside the same CALLBACK mount area. User space on the connection is
1286arranged to be the size of the new protocol user space allocation as given in
1287the protocol struct.
1288
1289This allocation is only deleted / replaced when the connection accesses a
1290URL region with a different protocol (or the default protocols[0] if no
1291CALLBACK area matches it).
1292
1293This "binding connection to a protocol" lifecycle in managed by
1294`LWS_CALLBACK_HTTP_BIND_PROTOCOL` and `LWS_CALLBACK_HTTP_DROP_PROTOCOL`.
1295Because of HTTP/1.1 connection pipelining, one connection may perform
1296many transactions, each of which may map to different URLs and need
1297binding to different protocols. So these messages are used to
1298create the binding of the wsi to your protocol including any
1299allocations, and to destroy the binding, at which point you should
1300destroy any related allocations.
1301
1302@section BINDTODEV SO_BIND_TO_DEVICE
1303
1304The .bind_iface flag in the context / vhost creation struct lets you
1305declare that you want all traffic for listen and transport on that
1306vhost to be strictly bound to the network interface named in .iface.
1307
1308This Linux-only feature requires SO_BIND_TO_DEVICE, which in turn
1309requires CAP_NET_RAW capability... root has this capability.
1310
1311However this feature needs to apply the binding also to accepted
1312sockets during normal operation, which implies the server must run
1313the whole time as root.
1314
1315You can avoid this by using the Linux capabilities feature to have
1316the unprivileged user inherit just the CAP_NET_RAW capability.
1317
1318You can confirm this with the test server
1319
1320
1321```
1322 $ sudo /usr/local/bin/libwebsockets-test-server -u agreen -i eno1 -k
1323```
1324
1325The part that ensures the capability is inherited by the unprivileged
1326user is
1327
1328```
1329#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
1330 info.caps[0] = CAP_NET_RAW;
1331 info.count_caps = 1;
1332#endif
1333```
1334
1335
1336@section dim Dimming webpage when connection lost
1337
1338The lws test plugins' html provides useful feedback on the webpage about if it
1339is still connected to the server, by greying out the page if not. You can
1340also add this to your own html easily
1341
1342 - include lws-common.js from your HEAD section
1343
1344 \<script src="/lws-common.js">\</script>
1345
1346 - dim the page during initialization, in a script section on your page
1347
1348 lws_gray_out(true,{'zindex':'499'});
1349
1350 - in your ws onOpen(), remove the dimming
1351
1352 lws_gray_out(false);
1353
1354 - in your ws onClose(), reapply the dimming
1355
1356 lws_gray_out(true,{'zindex':'499'});
1357
1358@section errstyle Styling http error pages
1359
1360In the code, http errors should be handled by `lws_return_http_status()`.
1361
1362There are basically two ways... the vhost can be told to redirect to an "error
1363page" URL in response to specifically a 404... this is controlled by the
1364context / vhost info struct (`struct lws_context_creation_info`) member
1365`.error_document_404`... if non-null the client is redirected to this string.
1366
1367If it wasn't redirected, then the response code html is synthesized containing
1368the user-selected text message and attempts to pull in `/error.css` for styling.
1369
1370If this file exists, it can be used to style the error page. See
1371https://libwebsockets.org/git/badrepo for an example of what can be done (
1372and https://libwebsockets.org/error.css for the corresponding css).
1373
1374
README.content-security-policy.md
1## Using Content Security Policy (CSP)
2
3### What is it?
4
5Modern browsers have recently implemented a new feature providing
6a sort of "selinux for your web page". If the server sends some
7new headers describing the security policy for the content, then
8the browser strictly enforces it.
9
10### Why would we want to do that?
11
12Scripting on webpages is pretty universal, sometimes the scripts
13come from third parties, and sometimes attackers find a way to
14inject scripts into the DOM, eg, through scripts in content.
15
16CSP lets the origin server define what is legitimate for the page it
17served and everything else is denied.
18
19The CSP for warmcat.com and libwebsockets.org looks like this,
20I removed a handful of whitelisted image sources like travis
21status etc for clarity...
22
23```
24"content-security-policy": "default-src 'none'; img-src 'self' data:; script-src 'self'; font-src 'self'; style-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none';",
25"x-content-type-options": "nosniff",
26"x-xss-protection": "1; mode=block",
27"x-frame-options": "deny",
28"referrer-policy": "no-referrer"
29```
30
31The result of this is the browser won't let the site content be iframed, and it
32will reject any inline styles or inline scripts. Fonts, css, ajax, ws and
33images are only allowed to come from 'self', ie, the server that served the
34page. You may inject your script, or deceptive styles: it won't run or be shown.
35
36Because inline scripts are banned, the usual methods for XSS are dead;
37the attacker can't even load js from another server. So these rules
38provide a very significant increase in client security.
39
40### Implications of strict CSP
41
42Halfhearted CSP isn't worth much. The only useful approach is to start
43with `default-src 'none'` which disables everything, and then whitelist the
44minimum needed for the pages to operate.
45
46"Minimum needed for the pages to operate" doesn't mean defeat the protections
47necessary so everything in the HTML can stay the same... it means adapt the
48pages to want the minimum and then enable the minimum.
49
50The main point is segregation of styles and script away from the content, in
51files referenced in the document `<head>` section, along these lines:
52
53```
54<head>
55 <meta charset=utf-8 http-equiv="Content-Language" content="en"/>
56 <link rel="stylesheet" type="text/css" href="test.css"/>
57 <script type='text/javascript' src="/lws-common.js"></script>
58 <script type='text/javascript' src='test.js'></script>
59 <title>Minimal Websocket test app</title>
60</head>
61```
62
63#### Inline styles must die
64
65All styling must go in one or more `.css` file(s) best served by the same
66server... while you can whitelist other sources in the CSP if you have to,
67unless you control that server as well, you are allowing whoever gains
68access to that server access to your users.
69
70Inline styles are no longer allowed (eg, "style='font-size:120%'" in the
71HTML)... they must be replaced by reference to one or more CSS class, which
72in this case includes "font-size:120%". This has always been the best
73practice anyway, and your pages will be cleaner and more maintainable.
74
75#### Inline scripts must die
76
77Inline scripts need to be placed in a `.js` file and loaded in the page head
78section, again it should only be from the server that provided the page.
79
80Then, any kind of inline script, yours or injected or whatever, will be
81completely rejected by the browser.
82
83#### onXXX must be replaced by eventListener
84
85Inline `onclick()` etc are kinds of inline scripting and are banned.
86
87Modern browsers have offered a different system called ["EventListener" for
88a while](https://developer.mozilla.org/en-US/docs/Web/API/EventListener)
89which allows binding of events to DOM elements in JS.
90
91A bunch of different named events are possible to listen on, commonly the
92`.js` file will ask for one or both of
93
94```
95window.addEventListener("load", function() {
96...
97}, false);
98
99document.addEventListener("DOMContentLoaded", function() {
100...
101}, false);
102```
103
104These give the JS a way to trigger when either everything on the page has
105been "loaded" or the DOM has been populated from the initial HTML. These
106can set up other event listeners on the DOM objects and aftwards the
107events will drive what happens on the page from user interaction and / or
108timers etc.
109
110If you have `onclick` in your HTML today, you would replace it with an id
111for the HTML element, then eg in the DOMContentLoaded event listener,
112apply
113
114```
115 document.getElementById("my-id").addEventListener("click", function() {
116 ...
117 }, false);
118```
119
120ie the .js file becomes the only place with the "business logic" of the
121elements mentioned in the HTML, applied at runtime.
122
123#### Do you really need external sources?
124
125Do your scripts and fonts really need to come from external sources?
126If your caching policy is liberal, they are not actually that expensive
127to serve once and then the user is using his local copy for the next
128days.
129
130Some external sources are marked as anti-privacy in modern browsers, meaning
131they track your users, in turn meaning if your site refers to them, you
132will lose your green padlock in the browser. If the content license allows
133it, hosting them on "self", ie, the same server that provided the HTML,
134will remove that problem.
135
136Bringing in scripts from external sources is actually quite scary from the
137security perspective. If someone hacks the `ajax.googleapis.com` site to serve
138a hostile, modified jquery, half the Internet will instantly
139become malicious. However if you serve it yourself, unless your server
140was specifically targeted you know it will continue to serve what you
141expect.
142
143Since these scripts are usually sent with cache control headers for local
144caching duration of 1 year, the cost of serving them yourself under the same
145conditions is small but your susceptibility to attack is reduced to only taking
146care of your own server. And there is a privacy benefit that google is not
147informed of your users' IPs and activities on your site.
148
149
README.contributing.md
1## Contributing to lws
2
3### How to contribute
4
5Sending a patch with a bug report is very welcome.
6
7For nontrivial problems, it's probably best to discuss on the mailing list,
8or on github if you prefer, how to best solve it.
9
10However your contribution is coming is fine:
11
12 - paste a `git diff`
13
14 - send a patch series by mail or mailing list
15
16 - paste in a github issue
17
18 - github PR
19
20are all OK.
21
22### Coding Standards
23
24Code should look roughly like the existing code, which follows linux kernel
25coding style.
26
27If there are non-functional problems I will clean them out when I apply the
28patch.
29
30If there are functional problems (eg broken error paths etc) if they are
31small compared to the working part I will also clean them. If there are
32larger problems, or consequences to the patch will have to discuss how to
33solve them with a retry.
34
35### Funding specific work
36
37If there is a feature you wish was supported in lws, consider paying for the
38work to be done. The maintainer is a consultant and if we can agree the
39task, you can quickly get a high quality result that does just what you need,
40maintained ongoing along with the rest of lws.
41
42
README.crypto-apis.md
1# Lws Crypto Apis
2
3## Overview
4
5![lws crypto overview](/doc-assets/lws-crypto-overview.svg)
6
7Lws provides a "generic" crypto layer on top of both OpenSSL and
8compatible tls library, and mbedtls. Using this layer, your code
9can work without any changes on both types of tls library crypto
10backends... it's as simple as rebuilding lws with `-DLWS_WITH_MBEDTLS=0`
11or `=1` at cmake.
12
13The generic layer can be used directly (as in, eg, the sshd plugin),
14or via another layer on top, which processes JOSE JSON objects using
15JWS (JSON Web Signatures), JWK (JSON Web Keys), and JWE (JSON Web
16Encryption).
17
18The `JW` apis use the generic apis (`lws_genrsa_`, etc) to get the crypto tasks
19done, so anything they can do you can also get done using the generic apis.
20The main difference is that with the generic apis, you must instantiate the
21correct types and use type-specfic apis. With the `JW` apis, there is only
22one interface for all operations, with the details hidden in the api and
23controlled by the JSON objects.
24
25Because of this, the `JW` apis are often preferred because they give you
26"crypto agility" cheaply... to change your crypto to another supported algorithm
27once it's working, you literally just change your JSON defining the keys and
28JWE or JWS algorithm. (It's up to you to define your policy for which
29combinations are acceptable by querying the parsed JW structs).
30
31## Crypto supported in generic layer
32
33### Generic Hash
34
35 - SHA1
36 - SHA256
37 - SHA384
38 - SHA512
39
40### Generic HMAC
41
42 - SHA256
43 - SHA384
44 - SHA512
45
46### Generic AES
47
48 - CBC
49 - CFB128
50 - CFB8
51 - CTR
52 - ECB
53 - OFB
54 - XTS
55 - GCM
56 - KW (Key Wrap)
57
58### Generic RSA
59
60 - PKCS 1.5
61 - OAEP / PSS
62
63### Generic EC
64
65 - ECDH
66 - ECDSA
67 - P256 / P384 / P521 (sic) curves
68
69## Using the generic layer
70
71All the necessary includes are part of `libwebsockets.h`.
72
73Enable `-DLWS_WITH_GENCRYPTO=1` at cmake.
74
75|api|header|Functionality|
76|---|---|---|
77|genhash|[./include/libwebsockets/lws-genhash.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genhash.h)|Provides SHA1 + SHA2 hashes and hmac|
78|genrsa|[./include/libwebsockets/lws-genrsa.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genrsa.h)|Provides RSA encryption, decryption, signing, verification, key generation and creation|
79|genaes|[./include/libwebsockets/lws-genaes.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genaes.h)|Provides AES in all common variants for encryption and decryption|
80|genec|[./include/libwebsockets/lws-genec.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genec.h)|Provides Elliptic Curve for encryption, decryption, signing, verification, key generation and creation|
81|x509|[./include/libwebsockets/lws-x509.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-x509.h)|Apis for X.509 Certificate loading, parsing, and stack verification, plus JWK key extraction from PEM X.509 certificate / private key|
82
83Unit tests for these apis, which serve as usage examples, can be found in [./minimal-examples/api-tests/api-test-gencrypto](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-gencrypto)
84
85### Keys in the generic layer
86
87The necessary types and defines are brought in by `libwebsockets.h`.
88
89Keys are represented only by an array of `struct lws_jwk_elements`... the
90length of the array is defined by the cipher... it's one of
91
92|key elements count|definition|
93|---|---|
94|`LWS_COUNT_OCT_KEY_ELEMENTS`|1|
95|`LWS_COUNT_RSA_KEY_ELEMENTS`|8|
96|`LWS_COUNT_EC_KEY_ELEMENTS`|4|
97|`LWS_COUNT_AES_KEY_ELEMENTS`|1|
98
99`struct lws_jwk_elements` is a simple pointer / length combination used to
100store arbitrary octets that make up the key element's binary representation.
101
102## Using the JOSE layer
103
104The JOSE (JWK / JWS / JWE) stuff is a crypto-agile JSON-based layer
105that uses the gencrypto support underneath.
106
107"Crypto Agility" means the JSON structs include information about the
108algorithms and ciphers used in that particular object, making it easy to
109upgrade system crypto strength or cycle keys over time while supporting a
110transitional period where the old and new keys or algorithms + ciphers
111are also valid.
112
113Uniquely lws generic support means the JOSE stuff also has "tls library
114agility", code written to the lws generic or JOSE apis is completely unchanged
115even if the underlying tls library changes between OpenSSL and mbedtls, meaning
116sharing code between server and client sides is painless.
117
118All the necessary includes are part of `libwebsockets.h`.
119
120Enable `-DLWS_WITH_JOSE=1` at CMake.
121
122|api|header|Functionality|
123|---|---|---|
124|JOSE|[./include/libwebsockets/lws-jose.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jose.h)|Provides crypto agility for JWS / JWE|
125|JWE|[./include/libwebsockets/lws-jwe.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jwe.h)|Provides Encryption and Decryption services for RFC7516 JWE JSON|
126|JWS|[./include/libwebsockets/lws-jws.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jws.h)|Provides signature and verifcation services for RFC7515 JWS JSON|
127|JWK|[./include/libwebsockets/lws-jwk.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jwk.h)|Provides signature and verifcation services for RFC7517 JWK JSON, both "keys" arrays and singletons|
128
129Minimal examples are provided in the form of commandline tools for JWK / JWS / JWE / x509 handling:
130
131 - [JWK minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwk)
132 - [JWS minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jws)
133 - [JWE minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwe)
134 - [X509 minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-x509)
135
136Unit tests for these apis, which serve as usage examples, can be found in [./minimal-examples/api-tests/api-test-jose](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose)
137
138## Crypto supported in the JOSE layer
139
140The JOSE RFCs define specific short names for different algorithms
141
142### JWS
143
144|JSOE name|Hash|Signature|
145---|---|---
146|RS256, RS384, RS512|SHA256/384/512|RSA
147|ES256, ES384, ES521|SHA256/384/512|EC
148
149### JWE
150
151|Key Encryption|Payload authentication + crypt|
152|---|---|
153|`RSAES-PKCS1-v1.5` 2048b & 4096b|`AES_128_CBC_HMAC_SHA_256`|
154|`RSAES-PKCS1-v1.5` 2048b|`AES_192_CBC_HMAC_SHA_384`|
155|`RSAES-PKCS1-v1.5` 2048b|`AES_256_CBC_HMAC_SHA_512`|
156|`RSAES-OAEP`|`AES_256_GCM`|
157|`AES128KW`, `AES192KW`, `AES256KW`|`AES_128_CBC_HMAC_SHA_256`|
158|`AES128KW`, `AES192KW`, `AES256KW`|`AES_192_CBC_HMAC_SHA_384`|
159|`AES128KW`, `AES192KW`, `AES256KW`|`AES_256_CBC_HMAC_SHA_512`|
160|`ECDH-ES` (P-256/384/521 key)|`AES_128/192/256_GCM`|
161|`ECDH-ES+A128/192/256KW` (P-256/384/521 key)|`AES_128/192/256_GCM`|
162
163### Keys in the JOSE layer
164
165Keys in the JOSE layer use a `struct lws_jwk`, this contains two arrays of
166`struct lws_jwk_elements` sized for the worst case (currently RSA). One
167array contains the key elements as described for the generic case, and the
168other contains various nonencrypted key metadata taken from JWK JSON.
169
170|metadata index|function|
171|---|---|
172|`JWK_META_KTY`|Key type, eg, "EC"|
173|`JWK_META_KID`|Arbitrary ID string|
174|`JWK_META_USE`|What the public key may be used to validate, "enc" or "sig"|
175|`JWK_META_KEY_OPS`|Which operations the key is authorized for, eg, "encrypt"|
176|`JWK_META_X5C`|Optional X.509 cert version of the key|
177|`JWK_META_ALG`|Optional overall crypto algorithm the key is intended for use with|
178
179`lws_jwk_destroy()` should be called when the jwk is going out of scope... this
180takes care to zero down any key element data in the jwk.
181
182
README.detailed-latency.md
1# lws detailed latency
2
3![lws detailed latency example plot](../doc-assets/lws-detailed-latency-example.png)
4
5## Introduction
6
7lws has the capability to make detailed latency measurements and
8report them in realtime to a specified callback.
9
10A default callback is provided that renders the data as text in
11space-separated format suitable for gnuplot, to a specified file.
12
13## Configuring
14
15Enable `LWS_WITH_DETAILED_LATENCY` at cmake.
16
17Create your context with something similar to this
18
19```
20#if defined(LWS_WITH_DETAILED_LATENCY)
21 info.detailed_latency_cb = lws_det_lat_plot_cb;
22 info.detailed_latency_filepath = "/tmp/lws-latency-results";
23#endif
24```
25
26`lws_det_lat_plot_cb` is provided by lws as a convenience to convert
27the stuct data provided at the callback interface to space-separated
28text data that is easy to process with shell commands and gnuplot.
29
30## `lws_det_lat_plot_cb` format
31
32```
33728239173547 N 23062 0 0 23062 0 0 0
34728239192554 C 18879 0 0 18879 0 0 0
35728239217894 T 25309 0 0 25309 0 0 0
36728239234998 r 0 0 0 0 271 172 256
37728239250611 r 0 0 0 0 69 934 4096
38728239255679 w 19 122 18 159 20 80 80
39728239275718 w 20 117 15 152 18 80 80
40728239295578 w 10 73 7 90 7 80 80
41728239315567 w 9 67 5 81 7 80 80
42728239335745 w 23 133 9 165 14 80 80
43...
44```
45
46Each event is shown in 9 columns
47
48 - unix time in us
49 - event type
50 - N = Name resolution
51 - C = TCP Connection
52 - T = TLS negotiation server
53 - t = TLS negotiation client
54 - r = Read
55 - w = Write
56 - us duration, for w time client spent waiting to write
57 - us duration, for w time data spent in transit to proxy
58 - us duration, for w time proxy waited to send data
59 - as a convenience, sum of last 3 columns above
60 - us duration, time spent in callback
61 - last 2 are actual / requested size in bytes
62
63## Processing captured data with ministat
64
65Eg, to summarize overall latencies on all captured writes
66
67```
68 $ cat /tmp/lws-latency-results | grep " w " | cut -d' ' -f6 | ministat
69...
70 N Min Max Median Avg Stddev
71x 1000 43 273 141 132.672 32.471693
72```
73
74## Processing captured data with gnuplot
75
76### Gnuplot plotting script
77
78Create a gnuplot script, eg myscript.gp
79
80```
81reset
82set term pngcairo enhanced nocrop font "OpenSans, 12" size 800,600#output terminal and file
83set output "lws-latency.png"
84#set yrange [0:10000]
85#to put an empty boundary around the
86#data inside an autoscaled graph.
87set offset graph 0.05,0.05,0.05,0.0
88set style fill transparent solid 0.5 #fillstyle
89set tics out nomirror
90set xlabel "event"
91set ylabel "latency (us)"
92set format x ""
93set title "Write latency"
94set key invert reverse Right inside nobox
95set key autotitle columnheader
96set style data histogram
97set style histogram rowstacked
98set style fill solid border -1
99set boxwidth 0.75
100set style fill solid 1.00 noborder
101set tic scale 0
102set grid ytics lc rgb "#505050"
103unset border
104unset xtics
105
106plot '/tmp/1' \
107 using ($3 + $4 + $5):xtic(1) w boxes lt rgbcolor "blue" title 'prox wr wait', \
108 '' using ($3 + $4):xtic(1) w boxes lt rgbcolor "green" title 'txfr to prox', \
109 '' using 3:xtic(1) w boxes lt rgbcolor "red" title 'cli wri wait'
110```
111
112### gnuplot invocation
113
114```
115 $ cat /tmp/lws-latency-results | grep " w " \>/tmp/1 ; gnuplot myscript.gp && eog lws-latency.png
116```
117
118
README.esp32.md
1ESP32 Support
2=============
3
4See \ref esp32 for details on how to build lws as a component in an ESP-IDF project.
5
6Lws provides a "factory" application
7
8https://github.com/warmcat/lws-esp32-factory
9
10and a test application which implements the generic lws server test apps
11
12https://github.com/warmcat/lws-esp32-test-server-demos
13
14The behaviours of the generic factory are are quite rich, and cover uploading SSL certs through factory and user configuration, AP selection and passphrase entry, and managing a switch to allow the user to force entry to user setup mode at boot subsequently.
15
16The factory app comes with partitioning for a 1MB factory partition containing that app and data, and a single 2.9MB OTA partition containing the main app.
17
18The factory app is able to do OTA updates for both the factory and OTA partition slots; updating the factory slot first writes the new image to the OTA slot and copies it into place at the next boot, after which the user can reload the OTA slot.
19
20State|Image|AP SSID|Port|URL|Mode
21---|---|---|---|---|---
22Factory Reset or Uninitialized|Factory|AP: ESP_012345|80|http://192.168.4.1|factory.html - to set certificates and serial
23User configuration|Factory|AP: config-model-serial|443|https://192.168.4.1|index.html - user set up his AP information
24Operation|OTA|Station only|443|https://model-serial.local|OTA application
25
26## Basic Auth
27
28The lws-esp32-test-server-demos app also demos basic auth.
29
30On a normal platform this is done by binding a mount to a text file somewhere in the filesystem, which
31contains user:password information one per line.
32
33On ESP32 there is not necessarily any generic VFS in use. So instead, the basic auth lookup is bound to
34a given nvs domain, where the username is the key and the password the value. main/main.c in the test
35demos app shows how to both make the mount use basic auth, and how to set a user:password combination
36using nvs.
37
38
README.generic-sessions.md
1Notes about generic-sessions Plugin
2===================================
3
4@section gseb Enabling lwsgs for build
5
6Enable at CMake with -DLWS_WITH_GENERIC_SESSIONS=1
7
8This also needs sqlite3 (libsqlite3-dev or similar package)
9
10
11@section gsi lwsgs Introduction
12
13The generic-sessions protocol plugin provides cookie-based login
14authentication for lws web and ws connections.
15
16The plugin handles everything about generic account registration,
17email verification, lost password, account deletion, and other generic account
18management.
19
20Other code, in another eg, ws protocol handler, only needs very high-level
21state information from generic-sessions, ie, which user the client is
22authenticated as. Everything underneath is managed in generic-sessions.
23
24
25 - random 20-byte session id managed in a cookie
26
27 - all information related to the session held at the server, nothing managed clientside
28
29 - sqlite3 used at the server to manage active sessions and users
30
31 - defaults to creating anonymous sessions with no user associated
32
33 - admin account (with user-selectable username) is defined in config with a SHA-1 of the password; rest of the accounts are in sqlite3
34
35 - user account passwords stored as salted SHA-1 with additional confounder
36 only stored in the JSON config, not the database
37
38 - login, logout, register account + email verification built-in with examples
39
40 - in a mount, some file suffixes (ie, .js) can be associated with a protocol for the purposes of rewriting symbolnames. These are read-only copies of logged-in server state.
41
42 - When your page fetches .js or other rewritten files from that mount, "$lwsgs_user" and so on are rewritten on the fly using chunked transfer encoding
43
44 - Eliminates server-side scripting with a few rewritten symbols and
45 javascript on client side
46
47 - 32-bit bitfield for authentication sectoring, mounts can provide a mask on the loggin-in session's associated server-side bitfield that must be set for access.
48
49 - No code (just config) required for, eg, private URL namespace that requires login to access.
50
51
52@section gsin Lwsgs Integration to HTML
53
54Only three steps are needed to integrate lwsgs in your HTML.
55
561) lwsgs HTML UI is bundled with the javascript it uses in `lwsgs.js`, so
57import that script file in your head section
58
592) define an empty div of id "lwsgs" somewhere
60
613) Call lwsgs_initial() in your page
62
63That's it. An example is below
64
65```
66 <html>
67 <head>
68 <script src="lwsgs.js"></script>
69 <style>
70 .body { font-size: 12 }
71 .gstitle { font-size: 18 }
72 </style>
73 </head>
74 <body style="background-image:url(seats.jpg)">
75 <table style="width:100%;transition: max-height 2s;">
76 <tr>
77 <td style="vertical-align:top;text-align:left;width=200px">
78 <img src="lwsgs-logo.png">
79 </td>
80 <td style="vertical-align:top;float:right">
81 <div id=lwsgs style="text-align:right;background-color: rgba(255, 255, 255, 0.8);"></div>
82 </td>
83 </tr>
84 </table>
85 </form>
86
87 <script>lwsgs_initial();</script>
88
89 </body>
90 </html>
91```
92
93@section gsof Lwsgs Overall Flow@
94
95When the protocol is initialized, it gets per-vhost information from the config, such
96as where the sqlite3 databases are to be stored. The admin username and sha-1 of the
97admin password are also taken from here.
98
99In 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
100created with no attached user.
101
102So there should always be an active session after any transactions with the server.
103
104In the example html going to the mount /lwsgs loads a login / register page as the default.
105
106The <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.
107
108After a successful login, the sqlite record at the server for the current session is updated to have the logged-in username associated with it.
109
110
111
112@section gsconf Lwsgs Configuration
113
114"auth-mask" defines the authorization sector bits that must be enabled on the session to gain access.
115
116"auth-mask" 0 is the default.
117
118 - b0 is set if you are logged in as a user at all.
119 - b1 is set if you are logged in with the user configured to be admin
120 - b2 is set if the account has been verified (the account configured for admin is always verified)
121 - b3 is set if your session just did the forgot password flow successfully
122
123```
124 {
125 # things in here can always be served
126 "mountpoint": "/lwsgs",
127 "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions",
128 "origin": "callback://protocol-lws-messageboard",
129 "default": "generic-sessions-login-example.html",
130 "auth-mask": "0",
131 "interpret": {
132 ".js": "protocol-lws-messageboard"
133 }
134 }, {
135 # things in here can only be served if logged in as a user
136 "mountpoint": "/lwsgs/needauth",
137 "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needauth",
138 "origin": "callback://protocol-lws-messageboard",
139 "default": "generic-sessions-login-example.html",
140 "auth-mask": "5", # logged in as a verified user
141 "interpret": {
142 ".js": "protocol-lws-messageboard"
143 }
144 }, {
145 # things in here can only be served if logged in as admin
146 "mountpoint": "/lwsgs/needadmin",
147 "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needadmin",
148 "origin": "callback://protocol-lws-messageboard",
149 "default": "generic-sessions-login-example.html",
150 "auth-mask": "7", # b2 = verified (by email / or admin), b1 = admin, b0 = logged in with any user name
151 "interpret": {
152 ".js": "protocol-lws-messageboard"
153 }
154 }
155```
156Note that the name of the real application protocol that uses generic-sessions
157is used, not generic-sessions itself.
158
159The vhost configures the storage dir, admin credentials and session cookie lifetimes:
160
161```
162 "ws-protocols": [{
163 "protocol-generic-sessions": {
164 "status": "ok",
165 "admin-user": "admin",
166
167 # create the pw hash like this (for the example pw, "jipdocesExunt" )
168 # $ echo -n "jipdocesExunt" | sha1sum
169 # 046ce9a9cca769e85798133be06ef30c9c0122c9 -
170 #
171 # Obviously ** change this password hash to a secret one before deploying **
172 #
173 "admin-password-sha1": "046ce9a9cca769e85798133be06ef30c9c0122c9",
174 "session-db": "/var/www/sessions/lws.sqlite3",
175 "timeout-idle-secs": "600",
176 "timeout-anon-idle-secs": "1200",
177 "timeout-absolute-secs": "6000",
178 # the confounder is part of the salted password hashes. If this config
179 # file is in a 0700 root:root dir, an attacker with apache credentials
180 # will have to get the confounder out of the process image to even try
181 # to guess the password hashes.
182 "confounder": "Change to <=31 chars of junk",
183
184 "email-from": "noreply@example.com",
185 "email-smtp-ip": "127.0.0.1",
186 "email-expire": "3600",
187 "email-helo": "myhost.com",
188 "email-contact-person": "Set Me <real-person@email.com>",
189 "email-confirm-url-base": "http://localhost:7681/lwsgs"
190 }
191```
192
193The email- related settings control generation of automatic emails for
194registration and forgotten password.
195
196 - `email-from`: The email address automatic emails are sent from
197
198 - `email-smtp-ip`: Normally 127.0.0.1, if you have a suitable server on port
199 25 on your lan you can use this instead here.
200
201 - `email-expire`: Seconds that links sent in email will work before being
202 deleted
203
204 - `email-helo`: HELO to use when communicating with your SMTP server
205
206 - `email-contact-person`: mentioned in the automatic emails as a human who can
207 answer questions
208
209 - `email-confirm-url-base`: the URL to start links with in the emails, so the
210 recipient can get back to the web server
211
212The real protocol that makes use of generic-sessions must also be listed and
213any configuration it needs given
214
215```
216 "protocol-lws-messageboard": {
217 "status": "ok",
218 "message-db": "/var/www/sessions/messageboard.sqlite3"
219 },
220```
221
222Notice the real application uses his own sqlite db, no details about how
223generic-sessions works or how it stores data are available to it.
224
225
226@section gspwc Lwsgs Password Confounder
227
228You can also define a per-vhost confounder shown in the example above, used
229when aggregating the password with the salt when it is hashed. Any attacker
230will also need to get the confounder along with the database, which you can
231make harder by making the config dir only eneterable / readable by root.
232
233
234@section gsprep Lwsgs Preparing the db directory
235
236You will have to prepare the db directory so it's suitable for the lwsws user to use,
237that usually means apache, eg
238
239```
240 # mkdir -p /var/www/sessions
241 # chown root:apache /var/www/sessions
242 # chmod 770 /var/www/sessions
243```
244
245@section gsrmail Lwsgs Email configuration
246
247lwsgs will can send emails by talking to an SMTP server on localhost:25. That
248will usually be sendmail or postfix, you should confirm that works first by
249itself using the `mail` application to send on it.
250
251lwsgs has been tested on stock Fedora sendmail and postfix.
252
253
254@section gsap Lwsgs Integration with another protocol
255
256lwsgs is designed to provide sessions and accounts in a standalone and generic way.
257
258But it's not useful by itself, there will always be the actual application who wants
259to make use of generic-sessions features.
260
261We provide the "messageboard" plugin as an example of how to integrate with
262your actual application protocol.
263
264The basic approach is the 'real' protocol handler (usually a plugin itself)
265subclasses the generic-sessions plugin and calls through to it by default.
266
267The "real" protocol handler entirely deals with ws-related stuff itself, since
268generic-sessions does not use ws. But for
269
270 - LWS_CALLBACK_HTTP
271 - LWS_CALLBACK_HTTP_BODY
272 - LWS_CALLBACK_HTTP_BODY_COMPLETION
273 - LWS_CALLBACK_HTTP_DROP_PROTOCOL
274
275the "real" protocol handler checks if it recognizes the activity (eg, his own
276POST 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
277through any unhandled messages to generic-sessions.
278
279The "real" protocol can get a pointer to generic-sessions protocol on the
280same vhost using
281
282```
283 vhd->gsp = lws_vhost_name_to_protocol(vhd->vh, "protocol-generic-sessions");
284```
285
286The "real" protocol must also arrange generic-sessions per_session_data in his
287own per-session allocation. To allow keeping generic-sessions opaque, the
288real protocol must allocate that space at runtime, using the pss size
289the generic-sessions protocol struct exposes
290
291```
292 struct per_session_data__myapp {
293 void *pss_gs;
294 ...
295
296 pss->pss_gs = malloc(vhd->gsp->per_session_data_size);
297```
298
299The allocation reserved for generic-sessions is then used as user_space when
300the real protocol calls through to the generic-sessions callback
301
302```
303 vhd->gsp->callback(wsi, reason, &pss->pss_gs, in, len);
304```
305
306In that way the "real" protocol can subclass generic-sessions functionality.
307
308
309To ease management of these secondary allocations, there are callbacks that
310occur when a wsi binds to a protocol and when the binding is dropped. These
311should be used to malloc and free and kind of per-connection
312secondary allocations.
313
314```
315 case LWS_CALLBACK_HTTP_BIND_PROTOCOL:
316 if (!pss || pss->pss_gs)
317 break;
318
319 pss->pss_gs = malloc(vhd->gsp->per_session_data_size);
320 if (!pss->pss_gs)
321 return -1;
322
323 memset(pss->pss_gs, 0, vhd->gsp->per_session_data_size);
324 break;
325
326 case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
327 if (vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len))
328 return -1;
329
330 if (pss->pss_gs) {
331 free(pss->pss_gs);
332 pss->pss_gs = NULL;
333 }
334 break;
335```
336
337
338#section gsapsib Getting session-specific information from another protocol
339
340At least at the time when someone tries to upgrade an http(s) connection to
341ws(s) with your real protocol, it is necessary to confirm the cookie the http(s)
342connection has with generic-sessions and find out his username and other info.
343
344Generic sessions lets another protocol check it again by calling his callback,
345and lws itself provides a generic session info struct to pass the related data
346
347```
348 struct lws_session_info {
349 char username[32];
350 char email[100];
351 char ip[72];
352 unsigned int mask;
353 char session[42];
354 };
355
356 struct lws_session_info sinfo;
357 ...
358 vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO,
359 &pss->pss_gs, &sinfo, 0);
360```
361
362After the call to generic-sessions, the results can be
363
364 - all the strings will be zero-length and .mask zero, there is no usable cookie
365
366 - only .ip and .session are set: the cookie is OK but no user logged in
367
368 - all the strings contain information about the logged-in user
369
370the real protocol can use this to reject attempts to open ws connections from
371http connections that are not authenticated; afterwards there's no need to
372check the ws connection auth status again.
373
374
README.generic-table.md
1Notes about generic-table
2=========================
3
4@section gtint What is generic-table?
5
6Generic-table is a JSON schema and client-side JS file that makes it easy to
7display live, table structured HTML over a ws link.
8
9An example plugin and index.html using it are provided, but lwsgt itself doesn't
10have its own plugin, it's just a JSON schema and client-side JS that other
11plugins can use to simplify displaying live, table-based data without having
12to reinvent the wheel each time.
13
14The ws protocol sends JSON describing the table, and then JSON updating the table
15contents when it chooses, the brower table is updated automatically, live.
16
17\image html lwsgt-overview.png
18
19 - Example protocol plugin (displays directory contents): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/protocol_table_dirlisting.c
20
21 - Example HTML: https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/index.html
22
23 - lwsgt.js (client-side table rendering / ws link management): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/lwsgt.js
24
25
26@section gteb Enabling for build
27
28Enable the demo plugin at CMake with -DLWS_WITH_PLUGINS=1
29
30
31@section gtinth Integrating with your html
32
33 - In your HEAD section, include lwsgt.js
34
35```
36 <script src="lwsgt.js"></script>
37```
38
39 - Also in your HEAD section, style the lwsgt CSS, eg
40
41```
42 <style>
43 .lwsgt_title { font-size: 24; text-align:center }
44 .lwsgt_breadcrumbs { font-size: 18; text-align:left }
45 .lwsgt_table { font-size: 14; padding:12px; margin: 12px; align:center }
46 .lwsgt_hdr { font-size: 18; text-align:center;
47 background-color: rgba(40, 40, 40, 0.8); color: white }
48 .lwsgt_tr { padding: 10px }
49 .lwsgt_td { padding: 3px }
50 </style>
51```
52
53You can skip this but the result will be less beautiful until some CSS is
54provided.
55
56 - In your body section, declare a div with an id (can be whatever you want)
57
58```
59 <tr><td><div id="lwsgt1" class="group1"></div></td></tr>
60```
61
62lwsgt JS will put its content there.
63
64 - Finally in a <script> at the end of your page, instantiate lwsgt and
65provide a custom callback for clickable links
66
67```
68 <script>
69 var v1 = new lwsgt_initial("Dir listing demo",
70 "protocol-lws-table-dirlisting",
71 "lwsgt1", "lwsgt_dir_click", "v1");
72
73 function lwsgt_dir_click(gt, u, col, row)
74 {
75 if (u[0] == '=') { /* change directory */
76 window[gt].lwsgt_ws.send(u.substring(1, u.length));
77 return;
78 }
79 var win = window.open(u, '_blank');
80 win.focus();
81 }
82
83 </script>
84```
85
86In the callback, you can recover the ws object by `window[gt].lwsgt_ws`.
87
88
89@section gtc Lwsgt constructor
90
91To instantiate the ws link and lwsgt instance, your HTML must call a lwsgt
92constructor for each region on the page managed by lwsgt.
93
94`var myvar = new lwsgt_initial(title, ws_protocol, div_id, click_cb, myvar);`
95
96All of the arguments are strings.
97
98| Parameter | Description |
99|-----------------|---------------------------------------------------------|
100| title | Title string to go above the table |
101| ws_protocol | Protocol name string to use when making ws connection |
102| div_id | HTML id of div to fill with content |
103| click_cb | Callback function name string to handle clickable links |
104| myvar | Name of var used to hold this instantiation globally |
105
106Note "myvar" is needed so it can be passed to the click handling callback.
107
108
109@section gtclick Lwsgt click handling function
110
111When a clickable link produced by lwsgt is clicked, the function named in the
112click_cb parameter to lwsgt_initial is called.
113
114That function is expected to take four parameters, eg
115
116`function lwsgt_dir_click(gt, u, col, row)`
117
118| Parameter | Description |
119|------- ---|-----------------------------------------------------------|
120| gt | Name of global var holding this lwsgt context (ie, myvar) |
121| u | Link "url" string |
122| col | Table column number link is from |
123| row | Table row number link is from |
124
125
126
127@section gtgj Generic-table JSON
128
129### Column layout
130
131When the ws connection is established, the protocol should send a JSON message
132describing the table columns. For example
133
134```
135 "cols": [
136 { "name": "Date" },
137 { "name": "Size", "align": "right" },
138 { "name": "Icon" },
139 { "name": "Name", "href": "uri"},
140 { "name": "uri", "hide": "1" }
141 ]
142 }
143```
144
145 - This describes 5 columns
146
147 - Only four columns (not "uri") should be visible
148
149 - "Name" should be presented as a clickable link using "uri" as the
150 destination, when a "uri" field is presented.
151
152 - "Size" field should be presented aligned to the right
153
154 ### Breadcrumbs
155
156 When a view is hierarchical, it's useful to provide a "path" with links back
157 in the "path", known as "breadcrumbs".
158
159 Elements before the last one should provide a "url" member as well as the
160 displayable name, which is used to create the link destination.
161
162 The last element, being the current displayed page should not have a url
163 member and be displayed without link style.
164
165
166 ```
167 "breadcrumbs":[{"name":"top", "url": "/" }, {"name":"mydir"}]
168 ```
169
170 ### Table data
171
172 The actual file data consists of an array of rows, containing the columns
173 mentioned in the original "cols" section.
174
175 ```
176 "data":[
177 {
178 "Icon":" ",
179 "Date":"2015-Feb-06 03:08:35 +0000",
180 "Size":"1406",
181 "uri":"./serve//favicon.ico",
182 "Name":"favicon.ico"
183 }
184 ]
185
186 ```
187
188 @section gtdirl Setting up protocol-lws-table-dirlisting
189
190 The example protocol needs two mounts, one to provide the index.html, js and
191 the protocol itself
192
193 ```
194 {
195 "mountpoint": "/dirtest",
196 "origin": "file:///usr/share/libwebsockets-test-server/generic-table",
197 "origin": "callback://protocol-lws-table-dirlisting",
198 "default": "index.html",
199 "pmo": [{
200 "dir": "/usr/share/libwebsockets-test-server"
201 }]
202 },
203```
204
205The protocol wants a per-mount option (PMO) to tell it the base directory it
206is serving from, named "dir".
207
208The other mount is there to simply serve items that get clicked on from the
209table in a secure way
210
211```
212 {
213 "mountpoint": "/dirtest/serve",
214 "origin": "file:///usr/share/libwebsockets-test-server",
215 "default": "index.html"
216 },
217```
218
219This last bit is not related to using lwsgt itself.
220
README.h2-long-poll.md
1# h2 long poll in lws
2
3lws server and client can support "immortal" streams that are
4not subject to normal timeouts under a special condition. These
5are read-only (to the client).
6
7Network connections that contain at least one immortal stream
8are themselves not subject to timeouts until the last immortal
9stream they are carrying closes.
10
11Because of this, it's recommended there is some other way of
12confirming that the client is still active.
13
14## Setting up lws server for h2 long poll
15
16Vhosts that wish to allow clients to serve these immortal
17streams need to set the info.options flag `LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL`
18at vhost creation time. The JSON config equivalent is to set
19
20```
21"h2-half-closed-long-poll": "1"
22```
23
24on the vhost. That's all that is needed.
25
26Streams continue to act normally for timeout with the exception
27client streams are allowed to signal they are half-closing by
28sending a zero-length DATA frame with END_STREAM set. These
29streams are allowed to exist outside of any timeout and data
30can be sent on them at will in the server -> client direction.
31
32## Setting client streams for long poll
33
34An API is provided to allow established h2 client streams to
35transition to immortal mode and send the END_STREAM to the server
36to indicate it.
37
38```
39int
40lws_h2_client_stream_long_poll_rxonly(struct lws *wsi);
41```
42
43## Example applications
44
45You can confirm the long poll flow simply using example applications.
46Build and run `http-server/minimal-http-server-h2-long-poll` in one
47terminal.
48
49In another, build the usual `http-client/minimal-http-client` example
50and run it with the flags `-l --long-poll`
51
52The client will connect to the server and transition to the immortal mode.
53The server sends a timestamp every minute to the client, and that will
54stay up without timeouts.
55
56
README.http-fallback.md
1# Http fallback and raw proxying
2
3Lws has several interesting options and features that can be applied to get
4some special behaviours... this article discusses them and how they work.
5
6## Overview of normal vhost selection
7
8Lws supports multiple http or https vhosts sharing a listening socket on the
9same port.
10
11For unencrypted http, the Host: header is used to select which vhost the
12connection should bind to, by comparing what is given there against the
13names the server was configured with for the various vhosts. If no match, it
14selects the first configured vhost.
15
16For TLS, it has an extension called SNI (Server Name Indication) which tells
17the server early in the TLS handshake the host name the connection is aimed at.
18That allows lws to select the vhost early, and use vhost-specific TLS certs
19so everything is happy. Again, if there is no match the connection proceeds
20using the first configured vhost and its certs.
21
22## Http(s) fallback options
23
24What happens if you try to connect, eg, an ssh client to the http server port
25(this is not an idle question...)? Obviously the http server part or the tls
26part of lws will fail the connection and close it. (We will look at that flow
27in a moment in detail for both unencrypted and tls listeners.)
28
29However if the first configured vhost for the port was created with the
30vhost creation info struct `.options` flag `LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`,
31then instead of the error, the connection transitions to whatever role was
32given in the vhost creation info struct `.listen_accept_role` and `.listen_accept_protocol`.
33
34With lejp-conf / lwsws, the options can be applied to the first vhost using:
35
36```
37 "listen-accept-role": "the-role-name",
38 "listen-accept-protocol": "the-protocol-name",
39 "fallback-listen-accept": "1"
40```
41
42See `./minimal-examples/raw/minimal-raw-fallback-http-server` for examples of
43all the options in use via commandline flags.
44
45So long as the first packet for the protocol doesn't look like GET, POST, or
46a valid tls packet if connection to an https vhost, this allows the one listen
47socket to handle both http(s) and a second protocol, as we will see, like ssh.
48
49Notice there is a restriction that no vhost selection processing is possible,
50neither for tls listeners nor plain http ones... the packet belonging to a
51different protocol will not send any Host: header nor tls SNI.
52
53Therefore although the flags and settings are applied to the first configured
54vhost, actually their effect is global for a given listen port. If enabled,
55all vhosts on the same listen port will do the fallback action.
56
57### Plain http flow
58
59![plain http flow](/doc-assets/accept-flow-1.svg)
60
61Normally, if the first received packet does not contain a valid HTTP method,
62then the connection is dropped. Which is what you want from an http server.
63
64However if enabled, the connection can transition to the defined secondary
65role / protocol.
66
67|Flag|lejp-conf / lwsws|Function|
68|---|---|---|
69|`LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`|`"fallback-listen-accept": "1"`|Enable fallback processing|
70
71### TLS https flow
72
73![tls https flow](/doc-assets/accept-flow-2.svg)
74
75If the port is listening with tls, the point that a packet from a different
76protocol will fail is earlier, when the tls tunnel is being set up.
77
78|Flag|lejp-conf / lwsws|Function|
79|---|---|---|
80|`LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`|`"fallback-listen-accept": "1"`|Enable fallback processing|
81|`LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS`|`"redirect-http": "1"`|Treat invalid tls packet as http, issue http redirect to https://|
82|`LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER`|`"allow-http-on-https": "1"`|Accept unencrypted http connections on this tls port (dangerous)|
83
84The latter two options are higher priority than, and defeat, the first one.
85
86### Non-http listener
87
88![non-http flow](/doc-assets/accept-flow-3.svg)
89
90It's also possible to skip the fallback processing and just force the first
91vhost on the port to use the specified role and protocol in the first place.
92
93|Flag|lejp-conf / lwsws|Function|
94|---|---|---|
95|LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG|`"apply-listen-accept": "1"`|Force vhost to use listen-accept-role / listen-accept-protocol|
96
97## Using http(s) fallback with raw-proxy
98
99If enabled for build with `cmake .. -DLWS_ROLE_RAW_PROXY=1 -DLWS_WITH_PLUGINS=1`
100then lws includes ready-to-use support for raw tcp proxying.
101
102This can be used standalone on the first vhost on a port, but most intriguingly
103it can be specified as the fallback for http(s)...
104
105See `./minimal-examples/raw/minimal-raw-proxy-fallback.c` for a working example.
106
107### fallback with raw-proxy in code
108
109On the first vhost for the port, specify the required "onward" pvo to configure
110the raw-proxy protocol...you can adjust the "ipv4:127.0.0.1:22" to whatever you
111want...
112
113```
114 static struct lws_protocol_vhost_options pvo1 = {
115 NULL,
116 NULL,
117 "onward", /* pvo name */
118 "ipv4:127.0.0.1:22" /* pvo value */
119 };
120
121 static const struct lws_protocol_vhost_options pvo = {
122 NULL, /* "next" pvo linked-list */
123 &pvo1, /* "child" pvo linked-list */
124 "raw-proxy", /* protocol name we belong to on this vhost */
125 "" /* ignored */
126 };
127```
128
129... and set up the fallback enable and bindings...
130
131```
132 info.options |= LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG;
133 info.listen_accept_role = "raw_proxy";
134 info.listen_accept_proxy = "raw_proxy";
135 info.pvo = &pvo;
136```
137
138### fallback with raw-proxy in JSON conf
139
140On the first vhost for the port, enable the raw-proxy protocol on the vhost and
141set the pvo config
142
143```
144 "ws-protocols": [{
145 "raw-proxy": {
146 "status": "ok",
147 "onward": "ipv4:127.0.0.1:22"
148 }
149 }],
150```
151
152Enable the fallback behaviour on the vhost and the role / protocol binding
153
154```
155 "listen-accept-role": "raw-proxy",
156 "listen-accept-protocol": "raw-proxy",
157 "fallback-listen-accept": "1"
158```
159
160### Testing
161
162With this configured, the listen port will function normally for http or https
163depending on how it was set up.
164
165But if you try to connect to it with an ssh client, that will also work fine.
166
167The libwebsockets.org server is set up in this way, you can confirm it by
168visiting `https://libwebsockets.org` on port 443 as usual, but also trying
169`ssh -p 443 invalid@libwebsockets.org`... you will get permission denied from
170your ssh client. With valid credentials in fact that works perfectly for
171ssh, scp, git-over-ssh etc all on port 443...
172
173
README.lws_dll.md
1# lws_dll Doubly-linked list
2
3## Introduction
4
5Lws supports two kinds of doubly-linked list, `lws_dll` and `lws_dll2`.
6
7Unless memory is at a big premium, or it has to work on lws < v3.2, it's
8best to simply use `lws_dll2`.
9
10![lws_dll overview](../doc-assets/lws_dll.svg)
11
12## How to use
13
14The basics are the same for lws_dll and lws_dll2.
15
16The list objects point only to themselves, and you use the `lws_container_of`
17macro to get a pointer to your struct that contains the list object. Doing
18it this way
19
20 - the list object does not have to be the first thing in your struct
21
22 - your struct can contain multiple list objects and appear on lists belonging
23 to multiple owners simultaenously,
24
25### lws_dll Minimal example
26
27```
28struct mystruct {
29 ....
30 lws_dll list;
31 ...
32};
33
34lws_dll owner;
35```
36
37Adding a mystruct to the owner list (...add_tail() works the same way but adds
38to the other end of the list)
39
40```
41 struct mystruct *p;
42
43 ...
44
45 lws_dll_add_head(&p->list, &owner);
46```
47
48Removing the list object from its owner
49
50```
51 lws_dll2_remove(&p->list, &owner);
52```
53
54If you have a `struct lws_dll *d` pointing to `list` in struct mystruct, you can
55convert it to a `struct mystruct *p` ike this
56
57```
58 struct mystruct *p = lws_container_of(d, struct lws_dll, list);
59```
60
61### lws_dll2 Minimal example
62
63
64```
65struct mystruct {
66 ....
67 lws_dll2 list;
68 ...
69};
70
71lws_dll2_owner owner;
72```
73
74Adding a mystruct to the owner list (...add_tail() works the same way but adds
75to the other end of the list)
76
77```
78 struct mystruct *p;
79
80 ...
81
82 lws_dll2_add_head(&p->list, &owner);
83```
84
85Removing the list object from its owner (notice compared to lws_dll, it doesn't
86need to be told the owner)
87
88```
89 lws_dll2_remove(&p->list);
90```
91
92If you have a `struct lws_dll2 *d` pointing to `list` in struct mystruct, you
93can convert it to a `struct mystruct *p` ike this
94
95```
96 struct mystruct *p = lws_container_of(d, struct lws_dll2, list);
97```
98
99## Summary Comparing lws_dll and lws_dll2
100
101 - both offer a doubly-linked list object, and (since v3.2) track both the
102 head and tail in an "list owner" object
103
104 - both are initalized by memsetting to 0
105
106 - for `lws_dll`, it reuses an `lws_dll` as the "owner", for `lws_dll2`, there's a
107 specific `lws_dll2_owner` structure for that
108
109 - `lws_dll2_owner` also keeps count of the number of list elements
110
111 - `lws_dll2` knows which owner's list it is participating on. So it can remove
112 itself and update the owner without the caller needing to know its owner.
113 In the case there are several potential owners list objects may be on, this
114 is very convenient.
115
116 - `lws_dll` is simpler and has a smaller footprint (two pointers per entry vs
117 three). But you have to know the exact list owner to perform operations on
118 it.
119
120## apis
121
122|function|lws_dll|lws_dll2|
123|---|---|---|
124|add entry at head|`void lws_dll_add_head(struct lws_dll *d, struct lws_dll *phead)`|`void lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner)`|
125|add entry at tail|`void lws_dll_add_tail(struct lws_dll *d, struct lws_dll *phead);`|`void lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner)`|
126|remove entry from its owning list|`void lws_dll_remove_track_tail(struct lws_dll *d, struct lws_dll *phead)`|`void lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner)`|
127|get owner|(not supported)|`struct lws_dll2_owner * lws_dll2_owner(const struct lws_dll2 *d)`|
128|check if item is detached from any list|`lws_dll_is_detached(struct lws_dll *d, struct lws_dll *phead)|int lws_dll2_is_detached(const struct lws_dll2 *d)`|
129|iterate through items on list|`int lws_dll_foreach_safe(struct lws_dll *phead, void *user, int (*cb)(struct lws_dll *d, void *user))|int lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user, int (*cb)(struct lws_dll2 *d, void *user))`|
130
131
README.lws_retry.md
1# `lws_retry_bo_t` client connection management
2
3This struct sets the policy for delays between retries, and for
4how long a connection may be 'idle' before it first tries to
5ping / pong on it to confirm it's up, or drops the connection
6if still idle.
7
8## Retry rate limiting
9
10You can define a table of ms-resolution delays indexed by which
11connection attempt number is ongoing, this is pointed to by
12`.retry_ms_table` with `.retry_ms_table_count` containing the
13count of table entries.
14
15`.conceal_count` is the number of retries that should be allowed
16before informing the parent that the connection has failed. If it's
17greater than the number of entries in the table, the last entry is
18reused for the additional attempts.
19
20`.jitter_percent` controls how much additional random delay is
21added to the actual interval to be used... this stops a lot of
22devices all synchronizing when they try to connect after a single
23trigger event and DDoS-ing the server.
24
25The struct and apis are provided for user implementations, lws does
26not offer reconnection itself.
27
28## Connection validity management
29
30Lws has a sophisticated idea of connection validity and the need to
31reconfirm that a connection is still operable if proof of validity
32has not been seen for some time. It concerns itself only with network
33connections rather than streams, for example, it only checks h2
34network connections rather than the individual streams inside (which
35is consistent with h2 PING frames only working at the network stream
36level itself).
37
38Connections may fail in a variety of ways, these include that no traffic
39at all is passing, or, eg, incoming traffic may be received but no
40outbound traffic is making it to the network, and vice versa. In the
41case that tx is not failing at any point but just isn't getting sent,
42endpoints can potentially kid themselves that since "they are sending"
43and they are seeing RX, the combination means the connection is valid.
44This can potentially continue for a long time if the peer is not
45performing keepalives.
46
47"Connection validity" is proven when one side sends something and later
48receives a response that can only have been generated by the peer
49receiving what was just sent. This can happen for some kinds of user
50transactions on any stream using the connection, or by sending PING /
51PONG protocol packets where the PONG is only returned for a received PING.
52
53To ensure that the generated traffic is only sent when necessary, user
54code can report for any stream that it has observed a transaction amounting
55to a proof of connection validity using an api. This resets the timer for
56the associated network connection before the validity is considered
57expired.
58
59`.secs_since_valid_ping` in the retry struct sets the number of seconds since
60the last validity after which lws will issue a protocol-specific PING of some
61kind on the connection. `.secs_since_valid_hangup` specifies how long lws
62will allow the connection to go without a confirmation of validity before
63simply hanging up on it.
64
65## Defaults
66
67The context defaults to having a 5m valid ping interval and 5m10s hangup interval,
68ie, it'll send a ping at 5m idle if the protocol supports it, and if no response
69validating the connection arrives in another 10s, hang up the connection.
70
71User code can set this in the context creation info and can individually set the
72retry policy per vhost for server connections. Client connections can set it
73per connection in the client creation info `.retry_and_idle_policy`.
74
75## Checking for h2 and ws
76
77Check using paired minimal examples with the -v flag on one or both sides to get a
78small validity check period set of 3s / 10s
79
80Also give, eg, -d1039 to see info level debug logging
81
82### h2
83
84```
85$ lws-minimal-http-server-h2-long-poll -v
86
87$ lws-minimal-http-client -l -v
88```
89
90### ws
91
92```
93$ lws-minimal-ws-server-h2 -s -v
94
95$ lws-minimal-ws-client-ping -n --server 127.0.0.1 --port 7681 -v
96```
97
98
99
README.lws_sequencer.md
1# `struct lws_sequencer` introduction
2
3Often a single network action like a client GET is just part of a
4larger series of actions, perhaps involving different connections.
5
6Since lws operates inside an event loop, if the outer sequencing
7doesn't, it can be awkward to synchronize these steps with what's
8happening on the network with a particular connection on the event
9loop thread.
10
11![lws_sequencer](/doc-assets/lws_sequencer.svg)
12
13`struct lws_sequencer` provides a generic way to stage multi-step
14operations from inside the event loop. Because it participates
15in the event loop similar to a wsi, it always operates from the
16service thread context and can access structures that share the
17service thread without locking. It can also provide its own
18higher-level timeout handling.
19
20Naturally you can have many of them running in the same event
21loop operating independently.
22
23Sequencers themselves bind to a pt (per-thread) service thread,
24by default there's only one of these and it's the same as saying
25they bind to an `lws_context`. The sequencer callback may create
26wsi which in turn are bound to a vhost, but the sequencer itself
27is above all that.
28
29## Sequencer timeouts
30
31The sequencer additionally maintains its own second-resolution timeout
32checked by lws for the step being sequenced... this is independent of
33any lws wsi timeouts which tend to be set and reset for very short-term
34timeout protection inside one transaction.
35
36The sequencer timeout operates separately and above any wsi timeout, and
37is typically only reset by the sequencer callback when it receives an
38event indicating a step completed or failed, or it sets up the next sequence
39step.
40
41If the sequencer timeout expires, then the sequencer receives a queued
42`LWSSEQ_TIMED_OUT` message informing it, and it can take corrective action
43or schedule a retry of the step. This message is queued and sent normally
44under the service thread context and in order of receipt.
45
46Unlike lws timeouts which force the wsi to close, the sequencer timeout
47only sends the message. This allows the timeout to be used to, eg, wait
48out a retry cooloff period and then start the retry when the
49`LWSSEQ_TIMED_OUT` is received, according to the state of the sequencer.
50
51## Creating an `struct lws_sequencer`
52
53```
54typedef struct lws_seq_info {
55 struct lws_context *context; /* lws_context for seq */
56 int tsi; /* thread service idx */
57 size_t user_size; /* size of user alloc */
58 void **puser; /* place ptr to user */
59 lws_seq_event_cb cb; /* seq callback */
60 const char *name; /* seq name */
61 const lws_retry_bo_t *retry; /* retry policy */
62} lws_seq_info_t;
63```
64
65```
66struct lws_sequencer *
67lws_sequencer_create(lws_seq_info_t *info);
68```
69
70When created, in lws the sequencer objects are bound to a 'per-thread',
71which is by default the same as to say bound to the `lws_context`. You
72can tag them with an opaque user data pointer, and they are also bound to
73a user-specified callback which handles sequencer events
74
75```
76typedef int (*lws_seq_event_cb)(struct lws_sequencer *seq, void *user_data,
77 lws_seq_events_t event, void *data);
78```
79
80`struct lws_sequencer` objects are private to lws and opaque to the user. A small
81set of apis lets you perform operations on the pointer returned by the
82create api.
83
84## Queueing events on a sequencer
85
86Each sequencer object can be passed "events", which are held on a per-sequencer
87queue and handled strictly in the order they arrived on subsequent event loops.
88`LWSSEQ_CREATED` and `LWSSEQ_DESTROYED` events are produced by lws reflecting
89the sequencer's lifecycle, but otherwise the event indexes have a user-defined
90meaning and are queued on the sequencer by user code for eventual consumption
91by user code in the sequencer callback.
92
93Pending events are removed from the sequencer queues and sent to the sequencer
94callback from inside the event loop at a rate of one per event loop wait.
95
96## Destroying sequencers
97
98`struct lws_sequencer` objects are cleaned up during context destruction if they are
99still around.
100
101Normally the sequencer callback receives a queued message that
102informs it that it's either failed at the current step, or succeeded and that
103was the last step, and requests that it should be destroyed by returning
104`LWSSEQ_RET_DESTROY` from the sequencer callback.
105
106## Lifecycle considerations
107
108Sequencers may spawn additional assets like client wsi as part of the sequenced
109actions... the lifecycle of the sequencer and the assets overlap but do not
110necessarily depend on each other... that is a wsi created by the sequencer may
111outlive the sequencer.
112
113It's important therefore to detach assets from the sequencer and the sequencer
114from the assets when each step is over and the asset is "out of scope" for the
115sequencer. It doesn't necessarily mean closing the assets, just making sure
116pointers are invalidated. For example, if a client wsi held a pointer to the
117sequencer as its `.user_data`, when the wsi is out of scope for the sequencer
118it can set it to NULL, eg, `lws_set_wsi_user(wsi, NULL);`.
119
120Under some conditions wsi may want to hang around a bit to see if there is a
121subsequent client wsi transaction they can be reused on. They will clean
122themselves up when they time out.
123
124## Watching wsi lifecycle from a sequencer
125
126When a sequencer is creating a wsi as part of its sequence, it will be very
127interested in lifecycle events. At client wsi creation time, the sequencer
128callback can set info->seq to itself in order to receive lifecycle messages
129about its wsi.
130
131|message|meaning|
132|---|---|
133|`LWSSEQ_WSI_CONNECTED`|The wsi has become connected|
134|`LWSSEQ_WSI_CONN_FAIL`|The wsi has failed to connect|
135|`LWSSEQ_WSI_CONN_CLOSE`|The wsi had been connected, but has now closed|
136
137By receiving these, the sequencer can understand when it should attempt
138reconnections or that it cannot progress the sequence.
139
140When dealing with wsi that were created by the sequencer, they may close at
141any time, eg, be closed by the remote peer or an intermediary. The
142`LWSSEQ_WSI_CONN_CLOSE` message may have been queued but since they are
143strictly handled in the order they arrived, before it was
144handled an earlier message may want to cause some api to be called on
145the now-free()-d wsi. To detect this situation safely, there is a
146sequencer api `lws_sequencer_check_wsi()` which peeks the message
147buffer and returns nonzero if it later contains an `LWSSEQ_WSI_CONN_CLOSE`
148already.
149
150
README.lws_struct.md
1# lws_struct
2
3## Overview
4
5lws_struct provides a lightweight method for serializing and deserializing C
6structs to and from JSON, and to and from sqlite3.
7
8![lws_struct overview](../doc-assets/lws_struct-overview.svg)
9
10 - you provide a metadata array describing struct members one-time, then call
11 generic apis to serialize and deserialize
12
13 - supports flat structs, single child struct pointers, and unbounded arrays /
14 linked-lists of child objects automatically using [lws_dll2 linked-lists](./README.lws_dll.md)
15
16 - supports boolean and C types char, int, long, long long in explicitly signed
17 and unsigned forms
18
19 - supports both char * type string members where the unbounded content is
20 separate and pointed to, and fixed length char array[] type members where
21 the content is part of the struct
22
23 - huge linear strings are supported by storing to a temp lwsac of chained chunks,
24 which is written into a single linear chunk in the main lwsac once the
25 total string length is known
26
27 - deserialization allocates into an [lwsac](../lib/misc/lwsac/README.md), so everything is inside as few
28 heap allocations as possible while still able to expand to handle arbitrary
29 array or strins sizes
30
31 - when deserialized structs are finished with, a single call to free the
32 lwsac frees the whole thing without having to walk it
33
34 - stateful serializaton and deserialization allows as-you-get packets incremental
35 parsing and production of chunks of as-you-can-send incremental serialization
36 output cleanly
37
38## Examples
39
README.lws_sul.md
1# `lws_sul` scheduler api
2
3Since v3.2 lws no longer requires periodic checking for timeouts and
4other events. A new system was refactored in where future events are
5scheduled on to a single, unified, sorted linked-list in time order,
6with everything at us resolution.
7
8This makes it very cheap to know when the next scheduled event is
9coming and restrict the poll wait to match, or for event libraries
10set a timer to wake at the earliest event when returning to the
11event loop.
12
13Everything that was checked periodically was converted to use `lws_sul`
14and schedule its own later event. The end result is when lws is idle,
15it will stay asleep in the poll wait until a network event or the next
16scheduled `lws_sul` event happens, which is optimal for power.
17
18# Side effect for older code
19
20If your older code uses `lws_service_fd()`, it used to be necessary
21to call this with a NULL pollfd periodically to indicate you wanted
22to let the background checks happen. `lws_sul` eliminates the whole
23concept of periodic checking and NULL is no longer a valid pollfd
24value for this and related apis.
25
26# Using `lws_sul` in user code
27
28See `minimal-http-client-multi` for an example of using the `lws_sul`
29scheduler from your own code; it uses it to spread out connection
30attempts so they are staggered in time. You must create an
31`lws_sorted_usec_list_t` object somewhere, eg, in you own existing object.
32
33```
34static lws_sorted_usec_list_t sul_stagger;
35```
36
37Create your own callback for the event... the argument points to the sul object
38used when the callback was scheduled. You can use pointer arithmetic to translate
39that to your own struct when the `lws_sorted_usec_list_t` was a member of the
40same struct.
41
42```
43static void
44stagger_cb(lws_sorted_usec_list_t *sul)
45{
46...
47}
48```
49
50When you want to schedule the callback, use `lws_sul_schedule()`... this will call
51it 10ms in the future
52
53```
54 lws_sul_schedule(context, 0, &sul_stagger, stagger_cb, 10 * LWS_US_PER_MS);
55```
56
57In the case you destroy your object and need to cancel the scheduled callback, use
58
59```
60 lws_sul_schedule(context, 0, &sul_stagger, NULL, LWS_SET_TIMER_USEC_CANCEL);
61```
62
63
README.lws_system.md
1# `lws_system`
2
3See `include/libwebsockets/lws-system.h` for function and object prototypes.
4
5## System integration api
6
7`lws_system` allows you to set a `system_ops` struct at context creation time,
8which can write up some function callbacks for system integration. The goal
9is the user code calls these by getting the ops struct pointer from the
10context using `lws_system_get_ops(context)` and so does not spread system
11dependencies around the user code, making it directly usable on completely
12different platforms.
13
14```
15typedef struct lws_system_ops {
16 int (*reboot)(void);
17 int (*set_clock)(lws_usec_t us);
18 int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t cb,
19 lws_system_states_t state, void *opaque,
20 struct lws_attach_item **get);
21} lws_system_ops_t;
22```
23
24|Item|Meaning|
25|---|---|
26|`(*reboot)()`|Reboot the system|
27|`(*set_clock)()`|Set the system clock|
28|`(*attach)()`|Request an event loop callback from another thread context|
29
30### `reboot`
31
32Reboots the device
33
34### `set_clock`
35
36Set the system clock to us-resolution Unix time in seconds
37
38### `attach`
39
40Request a callback from the event loop from a foreign thread. This is used, for
41example, for foreign threads to set up their event loop activity in their
42callback, and eg, exit once it is done, with their event loop activity able to
43continue wholly from the lws event loop thread and stack context.
44
45## Foreign thread `attach` architecture
46
47When lws is started, it should define an `lws_system_ops_t` at context creation
48time which defines its `.attach` handler. In the `.attach` handler
49implementation, it should perform platform-specific locking around a call to
50`__lws_system_attach()`, a public lws api that actually queues the callback
51request and does the main work. The platform-specific wrapper is just there to
52do the locking so multiple calls from different threads to the `.attach()`
53operation can't conflict.
54
55User code can indicate it wants a callback from the lws event loop like this:
56
57```
58lws_system_get_ops(context)->attach(context, tsi, cb, state, opaque, NULL)
59```
60
61`context` is a pointer to the lws_context, `tsi` is normally 0, `cb` is the user
62callback in the form
63
64```
65void (*lws_attach_cb_t)(struct lws_context *context, int tsi, void *opaque);
66```
67
68`state` is the `lws_system` state we should have reached before performing the
69callback (usually, `LWS_SYSTATE_OPERATIONAL`), and `opaque` is a user pointer that
70will be passed into the callback.
71
72`cb` will normally want to create scheduled events and set up lws network-related
73activity from the event loop thread and stack context.
74
75Once the event loop callback has been booked by calling this api, the thread and
76its stack context that booked it may be freed. It will be called back and can
77continue operations from the lws event loop thread and stack context. For that
78reason, if `opaque` is needed it will usually point to something on the heap,
79since the stack context active at the time the callback was booked may be long
80dead by the time of the callback.
81
82See ./lib/system/README.md for more details.
83
84## `lws_system` blobs
85
86"Blobs" are arbitrary binary objects that have a total length. Lws lets you set
87them in two ways
88
89 - "directly", by pointing to them, which has no heap implication
90
91 - "heap", by adding one or more arbitrary chunk to a chained heap object
92
93In the "heap" case, it can be incrementally defined and the blob doesn't all
94have to be declared at once.
95
96For read, the same api allows you to read all or part of the blob into a user
97buffer.
98
99The following kinds of blob are defined
100
101|Item|Meaning|
102|---|---|
103|`LWS_SYSBLOB_TYPE_AUTH`|Auth-related blob 1, typically a registration token|
104|`LWS_SYSBLOB_TYPE_AUTH + 1`|Auth-related blob 2, typically an auth token|
105|`LWS_SYSBLOB_TYPE_CLIENT_CERT_DER`|Client cert public part|
106|`LWS_SYSBLOB_TYPE_CLIENT_KEY_DER`|Client cert key part|
107|`LWS_SYSBLOB_TYPE_DEVICE_SERIAL`|Arbitrary device serial number|
108|`LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION`|Arbitrary firmware version|
109|`LWS_SYSBLOB_TYPE_DEVICE_TYPE`|Arbitrary Device Type identifier|
110|`LWS_SYSBLOB_TYPE_NTP_SERVER`|String with the ntp server address (defaults to pool.ntp.org)|
111
112### Blob handle api
113
114Returns an object representing the blob for a particular type (listed above)
115
116```
117lws_system_blob_t *
118lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
119 int idx);
120```
121
122### Blob Setting apis
123
124Sets the blob to point length `len` at `ptr`. No heap allocation is used.
125
126```
127void
128lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
129```
130
131Allocates and copied `len` bytes from `buf` into heap and chains it on the end of
132any existing.
133
134```
135int
136lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *buf, size_t len)
137```
138
139Remove any content from the blob, freeing it if it was on the heap
140
141```
142void
143lws_system_blob_heap_empty(lws_system_blob_t *b)
144```
145
146### Blob getting apis
147
148Get the total size of the blob (ie, if on the heap, the aggreate size of all the
149chunks that were appeneded)
150
151```
152size_t
153lws_system_blob_get_size(lws_system_blob_t *b)
154```
155
156Copy part or all of the blob starting at offset ofs into a user buffer at buf.
157`*len` should be the length of the user buffer on entry, on exit it's set to
158the used extent of `buf`. This works the same whether the bob is a direct pointer
159or on the heap.
160
161```
162int
163lws_system_blob_get(lws_system_blob_t *b, uint8_t *buf, size_t *len, size_t ofs)
164```
165
166If you know that the blob was handled as a single direct pointer, or a single
167allocation, you can get a pointer to it without copying using this.
168
169```
170int
171lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr)
172```
173
174### Blob destroy api
175
176Deallocates any heap allocation for the blob
177
178```
179void
180lws_system_blob_destroy(lws_system_blob_t *b)
181```
182
183
184## System state and notifiers
185
186Lws implements a state in the context that reflects the readiness of the system
187for various steps leading up to normal operation. By default it acts in a
188backwards-compatible way and directly reaches the OPERATIONAL state just after
189the context is created.
190
191However other pieces of lws, and user, code may define notification handlers
192that get called back when the state changes incrementally, and may veto or delay
193the changes until work necessary for the new state has completed asynchronously.
194
195The generic states defined are:
196
197|State|Meaning|
198|---|---|
199|`LWS_SYSTATE_CONTEXT_CREATED`|The context was just created.|
200|`LWS_SYSTATE_INITIALIZED`|The vhost protocols have been initialized|
201|`LWS_SYSTATE_IFACE_COLDPLUG`|Existing network interfaces have been iterated|
202|`LWS_SYSTATE_DHCP`|Network identity is available|
203|`LWS_SYSTATE_TIME_VALID`|The system knows the time|
204|`LWS_SYSTATE_POLICY_VALID`|If the system needs information about how to act from the net, it has it|
205|`LWS_SYSTATE_REGISTERED`|The device has a registered identity|
206|`LWS_SYSTATE_AUTH1`|The device identity has produced a time-limited access token|
207|`LWS_SYSTATE_AUTH2`|Optional second access token for different services|
208|`LWS_SYSTATE_OPERATIONAL`|The system is ready for user code to work normally|
209|`LWS_SYSTATE_POLICY_INVALID`|All connections are being dropped because policy information is changing. It will transition back to `LWS_SYSTATE_INITIALIZED` and onward to `OPERATIONAL` again afterwards with the new policy|
210
211### Inserting a notifier
212
213You should create an object `lws_system_notify_link_t` in non-const memory and zero it down.
214Set the `notify_cb` member and the `name` member and then register it using either
215`lws_system_reg_notifier()` or the `.register_notifier_list`
216member of the context creation info struct to make sure it will exist early
217enough to see all events. The context creation info method takes a list of
218pointers to notify_link structs ending with a NULL entry.
219
220
README.lwsws.md
1Notes about lwsws
2=================
3
4@section lwsws Libwebsockets Web Server
5
6lwsws is an implementation of a very lightweight, ws-capable generic web
7server, which uses libwebsockets to implement everything underneath.
8
9If you are basically implementing a standalone server with lws, you can avoid
10reinventing the wheel and use a debugged server including lws.
11
12
13@section lwswsb Build
14
15Just enable -DLWS_WITH_LWSWS=1 at cmake-time.
16
17It enables libuv and plugin support automatically.
18
19NOTICE on Ubuntu, the default libuv package is called "libuv-0.10". This is ancient.
20
21You should replace this with libuv1 and libuv1-dev before proceeding.
22
23@section lwswsc Lwsws Configuration
24
25lwsws uses JSON config files, they're pure JSON except:
26
27 - '#' may be used to turn the rest of the line into a comment.
28
29 - There's also a single substitution, if a string contains "_lws_ddir_", then that is
30replaced with the LWS install data directory path, eg, "/usr/share" or whatever was
31set when LWS was built + installed. That lets you refer to installed paths without
32having to change the config if your install path was different.
33
34There is a single file intended for global settings
35
36/etc/lwsws/conf
37```
38 # these are the server global settings
39 # stuff related to vhosts should go in one
40 # file per vhost in ../conf.d/
41
42 {
43 "global": {
44 "username": "apache",
45 "groupname": "apache",
46 "count-threads": "1",
47 "server-string": "myserver v1", # returned in http headers
48 "ws-pingpong-secs": "200", # confirm idle established ws connections this often
49 "init-ssl": "yes"
50 }
51 }
52```
53and a config directory intended to take one file per vhost
54
55/etc/lwsws/conf.d/warmcat.com
56```
57 {
58 "vhosts": [{
59 "name": "warmcat.com",
60 "port": "443",
61 "interface": "eth0", # optional
62 "host-ssl-key": "/etc/pki/tls/private/warmcat.com.key", # if given enable ssl
63 "host-ssl-cert": "/etc/pki/tls/certs/warmcat.com.crt",
64 "host-ssl-ca": "/etc/pki/tls/certs/warmcat.com.cer",
65 "mounts": [{ # autoserve
66 "mountpoint": "/",
67 "origin": "file:///var/www/warmcat.com",
68 "default": "index.html"
69 }]
70 }]
71 }
72```
73To get started quickly, an example config reproducing the old test server
74on port 7681, non-SSL is provided. To set it up
75```
76 # mkdir -p /etc/lwsws/conf.d /var/log/lwsws
77 # cp ./lwsws/etc-lwsws-conf-EXAMPLE /etc/lwsws/conf
78 # cp ./lwsws/etc-lwsws-conf.d-localhost-EXAMPLE /etc/lwsws/conf.d/test-server
79 # sudo lwsws
80```
81
82@section lwswsacme Using Letsencrypt or other ACME providers
83
84Lws supports automatic provisioning and renewal of TLS certificates.
85
86See ./READMEs/README.plugin-acme.md for examples of how to set it up on an lwsws vhost.
87
88@section lwsogo Other Global Options
89
90 - `reject-service-keywords` allows you to return an HTTP error code and message of your choice
91if a keyword is found in the user agent
92
93```
94 "reject-service-keywords": [{
95 "scumbot": "404 Not Found"
96 }]
97```
98
99 - `timeout-secs` lets you set the global timeout for various network-related
100 operations in lws, in seconds. It defaults to 5.
101
102@section lwswsv Lwsws Vhosts
103
104One server can run many vhosts, where SSL is in use SNI is used to match
105the connection to a vhost and its vhost-specific SSL keys during SSL
106negotiation.
107
108Listing multiple vhosts looks something like this
109```
110 {
111 "vhosts": [ {
112 "name": "localhost",
113 "port": "443",
114 "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key",
115 "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt",
116 "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer",
117 "mounts": [{
118 "mountpoint": "/",
119 "origin": "file:///var/www/libwebsockets.org",
120 "default": "index.html"
121 }, {
122 "mountpoint": "/testserver",
123 "origin": "file:///usr/local/share/libwebsockets-test-server",
124 "default": "test.html"
125 }],
126 # which protocols are enabled for this vhost, and optional
127 # vhost-specific config options for the protocol
128 #
129 "ws-protocols": [{
130 "warmcat,timezoom": {
131 "status": "ok"
132 }
133 }]
134 },
135 {
136 "name": "localhost",
137 "port": "7681",
138 "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key",
139 "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt",
140 "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer",
141 "mounts": [{
142 "mountpoint": "/",
143 "origin": ">https://localhost"
144 }]
145 },
146 {
147 "name": "localhost",
148 "port": "80",
149 "mounts": [{
150 "mountpoint": "/",
151 "origin": ">https://localhost"
152 }]
153 }
154
155 ]
156 }
157```
158
159That 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
160
161
162@section lwswsvn Lwsws Vhost name and port sharing
163
164The vhost name field is used to match on incoming SNI or Host: header, so it
165must always be the host name used to reach the vhost externally.
166
167 - Vhosts may have the same name and different ports, these will each create a
168listening socket on the appropriate port.
169
170 - Vhosts may also have the same port and different name: these will be treated as
171true vhosts on one listening socket and the active vhost decided at SSL
172negotiation time (via SNI) or if no SSL, then after the Host: header from
173the client has been parsed.
174
175
176@section lwswspr Lwsws Protocols
177
178Vhosts by default have available the union of any initial protocols from context creation time, and
179any protocols exposed by plugins.
180
181Vhosts can select which plugins they want to offer and give them per-vhost settings using this syntax
182```
183 "ws-protocols": [{
184 "warmcat-timezoom": {
185 "status": "ok"
186 }
187 }]
188```
189
190The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost
191LWS_CALLBACK_PROTOCOL_INIT (in is a pointer to a linked list of struct lws_protocol_vhost_options
192containing the name and value pointers).
193
194To indicate that a protocol should be used when no Protocol: header is sent
195by the client, you can use "default": "1"
196```
197 "ws-protocols": [{
198 "warmcat-timezoom": {
199 "status": "ok",
200 "default": "1"
201 }
202 }]
203```
204
205Similarly, if your vhost is serving a raw protocol, you can mark the protocol
206to be selected using "raw": "1"
207```
208 "ws-protocols": [{
209 "warmcat-timezoom": {
210 "status": "ok",
211 "raw": "1"
212 }
213 }]
214```
215
216See also "apply-listen-accept" below.
217
218@section lwswsovo Lwsws Other vhost options
219
220 - If the three options `host-ssl-cert`, `host-ssl-ca` and `host-ssl-key` are given, then the vhost supports SSL.
221
222 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.
223
224 - `keeplive-timeout` (in secs) defaults to 60 for lwsws, it may be set as a vhost option
225
226 - `interface` lets you specify which network interface to listen on, if not given listens on all. If the network interface is not usable (eg, ethernet cable out) it will be logged at startup with such vhost not listening, and lws will poll for it and bind a listen socket to the interface if and when it becomes available.
227
228 - "`unix-socket`": "1" causes the unix socket specified in the interface option to be used instead of an INET socket
229
230 - "`unix-socket-perms`": "user:group" allows you to control the unix permissons on the listening unix socket. It's always get to `0600` mode, but you can control the user and group for the socket fd at creation time. This allows you to use unix user and groups to control who may open the other end of the unix socket on the local system.
231
232 - "`sts`": "1" causes lwsws to send a Strict Transport Security header with responses that informs the client he should never accept to connect to this address using http. This is needed to get the A+ security rating from SSL Labs for your server.
233
234 - "`access-log`": "filepath" sets where apache-compatible access logs will be written
235
236 - `"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.
237
238 - "`ciphers`": "<cipher list>" OPENSSL only: sets the allowed list of TLS <= 1.2 ciphers and key exchange protocols for the serving SSL_CTX on the vhost. The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system.
239
240 If you need to allow weaker ciphers, you can provide an alternative list here per-vhost.
241
242 - "`client-ssl-ciphers`": "<cipher list>" OPENSSL only: sets the allowed list of <= TLS1.2 ciphers and key exchange protocols for the client SSL_CTX on the vhost
243
244 - "`tls13-ciphers`": "<cipher list>" OPENSSL 1.1.1+ only: sets allowed list of TLS1.3+ ciphers and key exchange protocols for the client SSL_CTX on the vhost. The default is to allow all.
245
246 - "`client-tls13-ciphers`": "<cipher list>" OPENSSL 1.1.1+ only: sets the allowed list of TLS1.3+ ciphers and key exchange protocols for the client SSL_CTX on the vhost. The default is to allow all.
247
248 - "`ecdh-curve`": "<curve name>" The default ecdh curve is "prime256v1", but you can override it here, per-vhost
249
250 - "`noipv6`": "on" Disable ipv6 completely for this vhost
251
252 - "`ipv6only`": "on" Only allow ipv6 on this vhost / "off" only allow ipv4 on this vhost
253
254 - "`ssl-option-set`": "<decimal>" Sets the SSL option flag value for the vhost.
255 It may be used multiple times and OR's the flags together.
256
257 The values are derived from /usr/include/openssl/ssl.h
258```
259 # define SSL_OP_NO_TLSv1_1 0x10000000L
260```
261
262 would equate to
263
264```
265 "`ssl-option-set`": "268435456"
266 ```
267 - "`ssl-option-clear'": "<decimal>" Clears the SSL option flag value for the vhost.
268 It may be used multiple times and OR's the flags together.
269
270 - "`ssl-client-option-set`" and "`ssl-client-option-clear`" work the same way for the vhost Client SSL context
271
272 - "`headers':: [{ "header1": "h1value", "header2": "h2value" }]
273
274allows you to set arbitrary headers on every file served by the vhost
275
276recommended vhost headers for good client security are
277
278```
279 "headers": [{
280 "Content-Security-Policy": "script-src 'self'",
281 "X-Content-Type-Options": "nosniff",
282 "X-XSS-Protection": "1; mode=block",
283 "X-Frame-Options": "SAMEORIGIN"
284 }]
285
286```
287
288 - "`apply-listen-accept`": "on" This vhost only serves a non-http protocol, specified in "listen-accept-role" and "listen-accept-protocol"
289
290@section lwswsm Lwsws Mounts
291
292Where mounts are given in the vhost definition, then directory contents may
293be auto-served if it matches the mountpoint.
294
295Mount protocols are used to control what kind of translation happens
296
297 - file:// serve the uri using the remainder of the url past the mountpoint based on the origin directory.
298
299 Eg, with this mountpoint
300```
301 {
302 "mountpoint": "/",
303 "origin": "file:///var/www/mysite.com",
304 "default": "/"
305 }
306```
307 The uri /file.jpg would serve /var/www/mysite.com/file.jpg, since / matched.
308
309 - ^http:// or ^https:// these cause any url matching the mountpoint to issue a redirect to the origin url
310
311 - cgi:// this causes any matching url to be given to the named cgi, eg
312```
313 {
314 "mountpoint": "/git",
315 "origin": "cgi:///var/www/cgi-bin/cgit",
316 "default": "/"
317 }, {
318 "mountpoint": "/cgit-data",
319 "origin": "file:///usr/share/cgit",
320 "default": "/"
321 },
322```
323 would cause the url /git/myrepo to pass "myrepo" to the cgi /var/www/cgi-bin/cgit and send the results to the client.
324
325 - http:// or https:// these perform reverse proxying, serving the remote origin content from the mountpoint. Eg
326
327```
328 {
329 "mountpoint": "/proxytest",
330 "origin": "https://libwebsockets.org"
331 }
332```
333
334This will cause your local url `/proxytest` to serve content fetched from libwebsockets.org over ssl; whether it's served from your server using ssl is unrelated and depends how you configured your local server. Notice if you will use the proxying feature, `LWS_WITH_HTTP_PROXY` is required to be enabled at cmake, and for `https` proxy origins, your lwsws configuration must include `"init-ssl": "1"` and the vhost with the proxy mount must have `"enable-client-ssl": "1"`, even if you are not using ssl to serve.
335
336`/proxytest/abc`, or `/proxytest/abc?def=ghi` etc map to the origin + the part past `/proxytest`, so links and img src urls etc work as do all urls under the origin path.
337
338In addition link and src urls in the document are rewritten so / or the origin url part are rewritten to the mountpoint part.
339
340
341@section lwswsomo Lwsws Other mount options
342
3431) Some protocols may want "per-mount options" in name:value format. You can
344provide them using "pmo"
345
346 {
347 "mountpoint": "/stuff",
348 "origin": "callback://myprotocol",
349 "pmo": [{
350 "myname": "myvalue"
351 }]
352 }
353
3542) When using a cgi:// protocol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
355```
356 {
357 "mountpoint": "/git",
358 "origin": "cgi:///var/www/cgi-bin/cgit",
359 "default": "/",
360 "cgi-env": [{
361 "CGIT_CONFIG": "/etc/cgitrc/libwebsockets.org"
362 }]
363 }
364```
365 This allows you to customize one cgi depending on the mountpoint (and / or vhost).
366
3673) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this
368```
369 "cgi-timeout": "30"
370```
3714) `callback://` protocol may be used when defining a mount to associate a
372named protocol callback with the URL namespace area. For example
373```
374 {
375 "mountpoint": "/formtest",
376 "origin": "callback://protocol-post-demo"
377 }
378```
379All handling of client access to /formtest[anything] will be passed to the
380callback registered to the protocol "protocol-post-demo".
381
382This is useful for handling POST http body content or general non-cgi http
383payload generation inside a plugin.
384
385See the related notes in README.coding.md
386
3875) Cache policy of the files in the mount can also be set. If no
388options are given, the content is marked uncacheable.
389```
390 {
391 "mountpoint": "/",
392 "origin": "file:///var/www/mysite.com",
393 "cache-max-age": "60", # seconds
394 "cache-reuse": "1", # allow reuse at client at all
395 "cache-revalidate": "1", # check it with server each time
396 "cache-intermediaries": "1" # allow intermediary caches to hold
397 }
398```
399
4006) You can also define a list of additional mimetypes per-mount
401```
402 "extra-mimetypes": {
403 ".zip": "application/zip",
404 ".doc": "text/evil"
405 }
406```
407
408Normally a file suffix MUST match one of the canned mimetypes or one of the extra
409mimetypes, or the file is not served. This adds a little bit of security because
410even if there is a bug somewhere and the mount dirs are circumvented, lws will not
411serve, eg, /etc/passwd.
412
413If you provide an extra mimetype entry
414
415 "*": ""
416
417Then any file is served, if the mimetype was not known then it is served without a
418Content-Type: header.
419
4207) A mount can be protected by HTTP Basic Auth. This only makes sense when using
421https, since otherwise the password can be sniffed.
422
423You can add a `basic-auth` entry on an http mount like this
424
425```
426{
427 "mountpoint": "/basic-auth",
428 "origin": "file://_lws_ddir_/libwebsockets-test-server/private",
429 "basic-auth": "/var/www/balogins-private"
430}
431```
432
433Before serving anything, lws will signal to the browser that a username / password
434combination is required, and it will pop up a dialog. When the user has filled it
435in, lwsws checks the user:password string against the text file named in the `basic-auth`
436entry.
437
438The file should contain user:pass one per line
439
440```
441testuser:testpass
442myuser:hispass
443```
444
445The file should be readable by lwsws, and for a little bit of extra security not
446have a file suffix, so lws would reject to serve it even if it could find it on
447a mount.
448
449After successful authentication, `WSI_TOKEN_HTTP_AUTHORIZATION` contains the
450authenticated username.
451
452In the case you want to also protect being able to connect to a ws protocol on
453a particular vhost by requiring the http part can authenticate using Basic
454Auth before the ws upgrade, this is also possible. In this case, the
455"basic-auth": and filepath to the credentials file is passed as a pvo in the
456"ws-protocols" section of the vhost definition.
457
458@section lwswscc Requiring a Client Cert on a vhost
459
460You can make a vhost insist to get a client certificate from the peer before
461allowing the connection with
462
463```
464 "client-cert-required": "1"
465```
466
467the connection will only proceed if the client certificate was signed by the
468same CA as the server has been told to trust.
469
470@section rawconf Configuring Fallback and Raw vhosts
471
472Lws supports some unusual modes for vhost listen sockets, which may be
473configured entirely using the JSON per-vhost config language in the related
474vhost configuration section.
475
476There are three main uses for them
477
4781) A vhost bound to a specific role and protocol, not http. This binds all
479incoming connections on the vhost listen socket to the "raw-proxy" role and
480protocol "myprotocol".
481
482```
483 "listen-accept-role": "raw-proxy",
484 "listen-accept-protocol": "myprotocol",
485 "apply-listen-accept": "1"
486```
487
4882) A vhost that wants to treat noncompliant connections for http or https as
489 belonging to a secondary fallback role and protocol. This causes non-https
490 connections to an https listener to stop being treated as https, to lose the
491 tls wrapper, and bind to role "raw-proxy" and protocol "myprotocol". For
492 example, connect a browser on your external IP :443 as usual and it serves
493 as normal, but if you have configured the raw-proxy to portforward
494 127.0.0.1:22, then connecting your ssh client to your external port 443 will
495 instead proxy your sshd over :443 with no http or tls getting in the way.
496
497```
498 "listen-accept-role": "raw-proxy",
499 "listen-accept-protocol": "myprotocol",
500 "fallback-listen-accept": "1",
501 "allow-non-tls": "1"
502```
503
5043) A vhost wants to either redirect stray http traffic back to https, or to
505 actually serve http on an https listen socket (this is not recommended
506 since it allows anyone to drop the security assurances of https by
507 accident or design).
508
509```
510 "allow-non-tls": "1",
511 "redirect-http": "1",
512```
513
514...or,
515
516```
517 "allow-non-tls": "1",
518 "allow-http-on-https": "1",
519```
520
521@section lwswspl Lwsws Plugins
522
523Protcols and extensions may also be provided from "plugins", these are
524lightweight dynamic libraries. They are scanned for at init time, and
525any protocols and extensions found are added to the list given at context
526creation time.
527
528Protocols receive init (LWS_CALLBACK_PROTOCOL_INIT) and destruction
529(LWS_CALLBACK_PROTOCOL_DESTROY) callbacks per-vhost, and there are arrangements
530they can make per-vhost allocations and get hold of the correct pointer from
531the wsi at the callback.
532
533This allows a protocol to choose to strictly segregate data on a per-vhost
534basis, and also allows the plugin to handle its own initialization and
535context storage.
536
537To help that happen conveniently, there are some new apis
538
539 - lws_vhost_get(wsi)
540 - lws_protocol_get(wsi)
541 - lws_callback_on_writable_all_protocol_vhost(vhost, protocol)
542 - lws_protocol_vh_priv_zalloc(vhost, protocol, size)
543 - lws_protocol_vh_priv_get(vhost, protocol)
544
545dumb increment, mirror and status protocol plugins are provided as examples.
546
547
548@section lwswsplaplp Additional plugin search paths
549
550Packages that have their own lws plugins can install them in their own
551preferred dir and ask lwsws to scan there by using a config fragment
552like this, in its own conf.d/ file managed by the other package
553```
554 {
555 "global": {
556 "plugin-dir": "/usr/local/share/coherent-timeline/plugins"
557 }
558 }
559```
560
561@section lwswsssp lws-server-status plugin
562
563One provided protocol can be used to monitor the server status.
564
565Enable the protocol like this on a vhost's ws-protocols section
566```
567 "lws-server-status": {
568 "status": "ok",
569 "update-ms": "5000"
570 }
571```
572`"update-ms"` is used to control how often updated JSON is sent on a ws link.
573
574And map the provided HTML into the vhost in the mounts section
575```
576 {
577 "mountpoint": "/server-status",
578 "origin": "file:///usr/local/share/libwebsockets-test-server/server-status",
579 "default": "server-status.html"
580 }
581```
582You might choose to put it on its own vhost which has "interface": "lo", so it's not
583externally visible, or use the Basic Auth support to require authentication to
584access it.
585
586`"hide-vhosts": "{0 | 1}"` lets you control if information about your vhosts is included.
587Since this includes mounts, you might not want to leak that information, mount names,
588etc.
589
590`"filespath":"{path}"` lets you give a server filepath which is read and sent to the browser
591on each refresh. For example, you can provide server temperature information on most
592Linux systems by giving an appropriate path down /sys.
593
594This may be given multiple times.
595
596
597@section lwswsreload Lwsws Configuration Reload
598
599You may send lwsws a `HUP` signal, by, eg
600
601```
602$ sudo killall -HUP lwsws
603```
604
605This causes lwsws to "deprecate" the existing lwsws process, and remove and close all of
606its listen sockets, but otherwise allowing it to continue to run, until all
607of its open connections close.
608
609When a deprecated lwsws process has no open connections left, it is destroyed
610automatically.
611
612After sending the SIGHUP to the main lwsws process, a new lwsws process, which can
613pick up the newly-available listen sockets, and use the current configuration
614files, is automatically started.
615
616The new configuration may differ from the original one in arbitrary ways, the new
617context is created from scratch each time without reference to the original one.
618
619Notes
620
6211) Protocols that provide a "shared world" like mirror will have as many "worlds"
622as there are lwsws processes still active. People connected to a deprecated lwsws
623process remain connected to the existing peers.
624
625But any new connections will apply to the new lwsws process, which does not share
626per-vhost "shared world" data with the deprecated process. That means no new
627connections on the deprecated context, ie a "shrinking world" for those guys, and a
628"growing world" for people who connect after the SIGHUP.
629
6302) The new lwsws process owes nothing to the previous one. It starts with fresh
631plugins, fresh configuration, fresh root privileges if that how you start it.
632
633The plugins may have been updated in arbitrary ways including struct size changes
634etc, and lwsws or lws may also have been updated arbitrarily.
635
6363) A root parent process is left up that is not able to do anything except
637respond to SIGHUP or SIGTERM. Actual serving and network listening etc happens
638in child processes which use the privileges set in the lwsws config files.
639
640@section lwswssysd Lwsws Integration with Systemd
641
642lwsws needs a service file like this as `/usr/lib/systemd/system/lwsws.service`
643```
644[Unit]
645Description=Libwebsockets Web Server
646After=syslog.target
647
648[Service]
649ExecStart=/usr/local/bin/lwsws
650ExecReload=/usr/bin/killall -s SIGHUP lwsws ; sleep 1 ; /usr/local/bin/lwsws
651StandardError=null
652
653[Install]
654WantedBy=multi-user.target
655```
656
657You can find this prepared in `./lwsws/usr-lib-systemd-system-lwsws.service`
658
659
660@section lwswslr Lwsws Integration with logrotate
661
662For correct operation with logrotate, `/etc/logrotate.d/lwsws` (if that's
663where we're putting the logs) should contain
664```
665 /var/log/lwsws/*log {
666 copytruncate
667 missingok
668 notifempty
669 delaycompress
670 }
671```
672You can find this prepared in `/lwsws/etc-logrotate.d-lwsws`
673
674Prepare the log directory like this
675
676```
677 sudo mkdir /var/log/lwsws
678 sudo chmod 700 /var/log/lwsws
679```
680
681@section lwswsgdb Debugging lwsws with gdb
682
683Hopefully you won't need to debug lwsws itself, but you may want to debug your plugins. start lwsws like this to have everything running under gdb
684
685```
686sudo gdb -ex "set follow-fork-mode child" -ex "run" --args /usr/local/bin/lwsws
687
688```
689
690this will give nice backtraces in lwsws itself and in plugins, if they were built with symbols.
691
692@section lwswsvgd Running lwsws under valgrind
693
694You can just run lwsws under valgrind as usual and get valid results. However the results / analysis part of valgrind runs
695after the plugins have removed themselves, this means valgrind backtraces into plugin code is opaque, without
696source-level info because the dynamic library is gone.
697
698There's a simple workaround, use LD_PRELOAD=<plugin.so> before running lwsws, this has the loader bring the plugin
699in before executing lwsws as if it was a direct dependency. That means it's still mapped until the whole process
700exits after valgtind has done its thing.
701
702
703
README.plugin-acme.md
1lws-acme-client Plugin
2======================
3
4## Introduction
5
6lws-acme-client is a protcol plugin for libwebsockets that implements an
7ACME client able to communicate with let's encrypt and other certificate
8providers.
9
10It implements `tls-sni-01` challenge, and is able to provision tls certificates
11"from thin air" that are accepted by all the major browsers. It also manages
12re-requesting the certificate when it only has two weeks left to run.
13
14It works with both the OpenSSL and mbedTLS backends.
15
16## Overview for use
17
18You need to:
19
20 - Provide name resolution to the IP with your server, ie, myserver.com needs to
21 resolve to the IP that hosts your server
22
23 - Enable port forwarding / external firewall access to your port, usually 443
24
25 - Enable the "lws-acme-client" plugin on the vhosts you want it to manage
26 certs for
27
28 - Add per-vhost options describing what should be in the certificate
29
30After that the plugin will sort everything else out.
31
32## Example lwsws setup
33
34```
35 "vhosts": [ {
36 "name": "home.warmcat.com",
37 "port": "443",
38 "host-ssl-cert": "/etc/lwsws/acme/home.warmcat.com.crt.pem",
39 "host-ssl-key": "/etc/lwsws/acme/home.warmcat.com.key.pem",
40 "ignore-missing-cert": "1",
41 "access-log": "/var/log/lwsws/test-access-log",
42 "ws-protocols": [{
43 "lws-acme-client": {
44 "auth-path": "/etc/lwsws/acme/auth.jwk",
45 "cert-path": "/etc/lwsws/acme/home.warmcat.com.crt.pem",
46 "key-path": "/etc/lwsws/acme/home.warmcat.com.key.pem",
47 "directory-url": "https://acme-staging.api.letsencrypt.org/directory",
48 "country": "TW",
49 "state": "Taipei",
50 "locality": "Xiaobitan",
51 "organization": "Crash Barrier Ltd",
52 "common-name": "home.warmcat.com",
53 "email": "andy@warmcat.com"
54 },
55 ...
56```
57
58## Required PVOs
59
60Notice that the `"host-ssl-cert"` and `"host-ssl-key"` entries have the same
61meaning as usual, they point to your certificate and private key. However
62because the ACME plugin can provision these, you should also mark the vhost with
63`"ignore-missing-cert" : "1"`, so lwsws will ignore what will initially be
64missing certificate / keys on that vhost, and will set about creating the
65necessary certs and keys instead of erroring out.
66
67You must make sure the directories mentioned here exist, lws doesn't create them
68for you. They should be 0700 root:root, even if you drop lws privileges.
69
70If you are implementing support in code, this corresponds to making sure the
71vhost creating `info.options` has the `LWS_SERVER_OPTION_IGNORE_MISSING_CERT`
72bit set.
73
74Similarly, in code, the each of the per-vhost options shown above can be
75provided in a linked-list of structs at vhost creation time. See
76`./test-apps/test-server-v2.0.c` for example code for providing pvos.
77
78### auth-path
79
80This is where the plugin will store the auth keys it generated.
81
82### cert-path
83
84Where the plugin will store the certificate file. Should match `host-ssl-cert`
85that the vhost wants to use.
86
87The path should include at least one 0700 root:root directory.
88
89### key-path
90
91Where the plugin will store the certificate keys. Again it should match
92`host-ssl-key` the vhost is trying to use.
93
94The path should include at least one 0700 root:root directory.
95
96### directory-url
97
98This defines the URL of the certification server you will get your
99certificates from. For let's encrypt, they have a "practice" one
100
101 - `https://acme-staging.api.letsencrypt.org/directory`
102
103and they have a "real" one
104
105 - `https://acme-v01.api.letsencrypt.org/directory`
106
107the main difference is the CA certificate for the real one is in most browsers
108already, but the staging one's CA certificate isn't. The staging server will
109also let you abuse it more in terms of repeated testing etc.
110
111It's recommended you confirm expected operation with the staging directory-url,
112and then switch to the "real" URL.
113
114### common-name
115
116Your server DNS name, like "libwebsockets.org". The remote ACME server will
117use this to find your server to perform the SNI challenges.
118
119### email
120
121The contact email address for the certificate.
122
123## Optional PVOs
124
125These are not included in the cert by letsencrypt
126
127### country
128
129Two-letter country code for the certificate
130
131### state
132
133State "or province" for the certificate
134
135### locality
136
137Locality for the certificate
138
139### organization
140
141Your company name
142
143## Security / Key storage considerations
144
145The `lws-acme-client` plugin is able to provision and update your certificate
146and keys in an entirely root-only storage environment, even though lws runs
147as a different uid / gid with no privileges to access the storage dir.
148
149It does this by opening and holding two WRONLY fds on "update paths" inside the
150root directory structure for each cert and key it manages; these are the normal
151cert and key paths with `.upd` appended. If during the time the server is up
152the certs become within two weeks of expiry, the `lws-acme-client` plugin will
153negotiate new certs and write them to the file descriptors.
154
155Next time the server starts, if it sees `.upd` cert and keys, it will back up
156the old ones and copy them into place as the new ones, before dropping privs.
157
158To also handle the long-uptime server case, lws will update the vhost with the
159new certs using in-memory temporary copies of the cert and key after updating
160the cert.
161
162In this way the cert and key live in root-only storage but the vhost is kept up
163to date dynamically with any cert changes as well.
164
165## Multiple vhosts using same cert
166
167In the case you have multiple vhosts using of the same cert, just attach
168the `lws-acme-client` plugin to one instance. When the cert updates, all the
169vhosts are informed and vhosts using the same filepath to access the cert will
170be able to update their cert.
171
172## Implementation point
173
174You will need to remove the auth keys when switching from OpenSSL to
175mbedTLS. They will be regenerated automatically. It's the file at this
176path:
177
178```
179"auth-path": "/etc/lwsws/acme/auth.jwk",
180```
181
README.plugin-sshd-base.md
1ssh-base Plugin
2================
3
4## Introduction
5
6lws-ssh-base is a protcol plugin for libwebsockets that implements a
7generic, abstract, ssh server.
8
9 - very small footprint in code and memory, takes up small part of ESP32
10
11 - written with security in mind: valgrind and Coverity -clean
12
13 - binds to one or more vhosts, that controls listen port(s)
14
15 - all IO and settings abstracted through a single "ops" struct from user code
16
17 - each instance on a vhost has its own "ops" struct, defining server keys,
18 auth method and functions to implement IO and other operations
19
20 - The plugin has no built-in behaviours like check ~/.ssh/authorized_keys,
21 treat auth usernames as system usernames, or spawn the user's shell.
22 Everything potentially dangerous is left to the user ops code to decide
23 how to handle. It's NOT like sshd where running it implies it will accept
24 existing keys for any system user, will spawn a shell, etc, unless you
25 implement those parts in the ops callbacks.
26
27 - The plugin requires extra code around it in the form of the ops struct
28 handlers. So it's role is something like an abstract base class for an ssh
29 server. All the crypto, protocol sequencing and state machine are inside,
30 but all the IO except the network connection is outside.
31
32 - Built as part of libwebsockets, like all plugins may be dynamically loaded
33 at runtime or built statically. Test app `libwebsockets-test-sshd` provided
34
35 - Uses hash and RSA functions from either mbedTLS or OpenSSL automatically,
36 according to which library libwebsockets was built for
37
38To maintain its small size, it implements a single "best of breed" crypto for
39the following functions:
40
41|Function|Crypto|
42|---|---|
43|KEX|curve25519-sha256@libssh.org|
44|Server host key|ssh-rsa (4096b)|
45|Encryption|chacha20-poly1305@openssh.com|
46|Compression|None|
47
48## License
49
50lws-ssh-base is Free Software, available under libwebsockets' MIT license.
51
52The crypto parts are available elsewhere under a BSD license. But for
53simplicity the whole plugin is under MIT.
54
55## Generating your own keys
56
57```
58 $ ssh-keygen -t rsa -b 4096 -f mykeys
59```
60
61will ask for a passphrase and generate the private key in `mykeys` and the
62public key in `mykeys.pub`. If you already have a suitable RSA key you use
63with ssh, you can just use that directly.
64
65lws installs a test keypair in /usr[/local]/share/libwebsockets-test-server
66that the test apps will accept.
67
68## Example code
69
701) There's a working example app `libwebsockets-test-sshd` included that
71spawns a bash shell when an ssh client authenticates. The username used on
72the remote ssh has no meaning, it spawns the shell under the credentials of
73"lws-test-sshd" was run under. It accepts the lws ssh test key which is
74installed into /usr[/local]/share/libwebsockets-test-server.
75
76Start the server like this (it wants root only because the server key is stored
77in /etc)
78
79```
80 $ sudo libwebsockets-test-sshd
81```
82
83Connect to it using the test private key like this
84
85```
86 $ ssh -p 2200 -i /usr/local/share/libwebsockets-test-server/lws-ssh-test-keys anyuser@127.0.0.1
87```
88
892) There's also a working example plugin `lws-sshd-demo` that "subclasses" the
90abstract `lws-ssh-base` plugin to make a protocol which can be used from,
91eg, lwsws. For an lwsws vhost that listens on port 2222 and responds with
92the lws-sshd-demo ssh server, the related config is:
93
94```
95 {
96 "name": "sshd",
97 "port": "2222",
98 "onlyraw": "1",
99 "ws-protocols": [{
100 "lws-ssh-base": {
101 "status": "ok",
102 "ops-from": "lws-sshd-demo"
103 },
104 "lws-sshd-demo": {
105 "status": "ok",
106 "raw": "1"
107 }
108 }]
109 }
110```
111
112
113
114## Integration to other apps
115
116### Step 0: Build and install libwebsockets
117
118For the `libwebsockets-test-sshd` example, you will need CMake options
119`LWS_WITH_CGI`, since it uses lws helpers to spawn a shell.
120
121lws-ssh-base itself doesn't require CGI support in libwebsockets.
122
123### Step 1: make the code available in your app
124
125Include `lws-plugin-ssh-base` in your app, either as a runtime plugin or by using
126the lws static include scheme.
127
128To bring in the whole of the ssh-base plugin
129into your app in one step, statically, just include
130`plugins/ssh-base/include/lws-plugin-sshd-static-build-includes.h`, you can see
131an example of this in `./test-apps/test-sshd.c`.
132
133### Step 2: define your `struct lws_ssh_ops`
134
135`plugins/ssh-base/include/lws-plugin-ssh.h` defines
136`struct lws_ssh_ops` which is used for all customization and integration
137of the plugin per vhost. Eg,
138
139```
140static const struct lws_ssh_ops ssh_ops = {
141 .channel_create = ssh_ops_channel_create,
142 .channel_destroy = ssh_ops_channel_destroy,
143 .tx_waiting = ssh_ops_tx_waiting,
144 .tx = ssh_ops_tx,
145 .rx = ssh_ops_rx,
146 .get_server_key = ssh_ops_get_server_key,
147 .set_server_key = ssh_ops_set_server_key,
148 .set_env = ssh_ops_set_env,
149 .pty_req = ssh_ops_pty_req,
150 .child_process_io = ssh_ops_child_process_io,
151 .child_process_terminated = ssh_ops_child_process_terminated,
152 .exec = ssh_ops_exec,
153 .shell = ssh_ops_shell,
154 .is_pubkey_authorized = ssh_ops_is_pubkey_authorized,
155 .banner = ssh_ops_banner,
156 .disconnect_reason = ssh_ops_disconnect_reason,
157 .server_string = "SSH-2.0-Libwebsockets",
158 .api_version = 1,
159};
160```
161The `ssh_ops_...()` functions are your implementations for the operations
162needed by the plugin for your purposes.
163
164### Step 3: enable `lws-ssh-base` protocol to a vhost and configure using pvo
165
166A pointer to your struct lws_ssh_ops is passed into the vhost instance of the
167protocol using per-vhost options
168
169```
170static const struct lws_protocol_vhost_options pvo_ssh_ops = {
171 NULL,
172 NULL,
173 "ops",
174 (void *)&ssh_ops
175};
176
177static const struct lws_protocol_vhost_options pvo_ssh = {
178 NULL,
179 &pvo_ssh_ops,
180 "lws-sshd-base",
181 "" /* ignored, just matches the protocol name above */
182};
183
184...
185 info.port = 22;
186 info.options = LWS_SERVER_OPTION_ONLY_RAW;
187 info.vhost_name = "sshd";
188 info.protocols = protocols_sshd;
189 info.pvo = &pvo_ssh;
190
191 vh_sshd = lws_create_vhost(context, &info);
192```
193
194There are two possible pvos supported, "ops", shown above, directly passes the
195ops structure in using the value on the "ops" pvo.
196
197To support other protocols that want to provide ops to lws-ssh-base themselves
198for a particular vhost, you can also provide a pvo `"ops-from"` whose value is
199the name of the protocol also enabled on this vhost, whose protocol ".user"
200pointer points to the ops struct lws-ssh-base should use.
201
202## Integration to other plugins
203
204A worked example of using the abstract `lws-ssh-base` plugin from another
205plugin that provides the ops struct is in `./plugins/protocol_lws_sshd_demo`.
206
207The key points to note
208
209 - the plugin sets the ops struct for the vhost instantiation of `lws-ssh-base`
210 by passing a pointer to the ops struct in its `lws_protocols` struct `user`
211 member.
212
213 - the config for the vhost tells `lws-ssh-base` to pick up the ops struct
214 pointer using an "ops-from" pvo that indicates the protocol name.
215
216```
217 "lws-ssh-base": {
218 "status": "ok",
219 "ops-from": "lws-sshd-demo"
220 },
221```
222
223 - the config for the vhost tells lws this vhost only serves RAW (ie, no http)
224
225```
226 {
227 "name": "sshd",
228 "port": "2222",
229 "onlyraw": "1",
230 ...
231```
232
233 - the config for the vhost marks the protocol that uses `lws-ssh-base`, not
234 `lws-ssh-base` itself, as the protocol to be served for raw connections
235
236```
237 "lws-sshd-demo": {
238 "status": "ok",
239 "raw": "1"
240 ...
241```
242
243## Notes
244
245You can have the vhost it binds to listen on a nonstandard port. The ssh
246commandline app cane be told to connect to a non-22 port with
247`ssh -p portnum user@hostname`
248
249
250
README.porting.md
1# Guidance for porting to new platform
2
3Where differences existed between the initial POSIX platform for lws and other
4supported platforms like Windows, `lws_plat_...()` apis were added to move
5handling to platform-specific code in `./lib/plat/`.
6
7Depending o which platform is built, different platform-specific implementations
8of these `lws_plat...()` apis get built.
9
10## 1) Prepare the cmake cross-build file if necessary
11
12CMake isolates its settings for cross-build into a separate file, which can be
13used to different cmake projects for the same platform as well.
14
15Find a similar examples already in `./contrib/cross-*` and copy and adapt it
16as needed,
17
18All settings related to toolchain should go in there. For cross-toolchain,
19the convention is to pass the path to its installed directory in `CROSS_PATH`
20environment variable.
21
22## 2) Copy the closest platform dir in ./lib/plat
23
24Wholesale copy the closest existing platform dir to `/lib/plat/myplatform` and
25rename the files.
26
27Remove stuff specific to the original platform.
28
29## 3) Add a flag in CMakeLists.txt
30
31Cut and paste a flag to select your platform, preferably `LWS_PLAT_MYPLATFORM` or so
32
33## 4) Add a section to force-select and deselect other cmake options based on platform flag
34
35Some options on by default may not make sense on your platform, and others off
36by default may be mandatory. After the options() section in CMakeLists.txt, you
37can use this kind of structure
38
39```
40 if (LWS_PLAT_MYPLATFORM)
41 set(LWS_WITH_XXXX 0)
42 endif()
43```
44
45to enforce implicit requirements of your platform. Optional stuff should be set by
46running cmake commandline as usual.
47
48## 5) Add building your platform files into CMakeLists.txt
49
50Add entries in CMakeLists.txt for building stuff in `./lib/plat/myplatform` when
51`LWS_PLAT_MYPLATFORM` is enabled.
52
53## 6) Adapt your copied ./lib/plat/myplatform/ files
54
55You can now do test builds using the cross-build file, your platform flag in
56cmake, and your copied ./lib/plat content... this last part since it was
57copied from another platform will initially be a plentiful source of errors.
58
59You can iteratively build and adapt the platform files.
60
61
README.problems.md
1Debugging problems
2==================
3
4Check it's still a problem with latest lws
5------------------------------------------
6
7Older versions of lws don't attract any new work after they are released
8(see [the release policy](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.release-policy.md) for details);
9for a while they will get backported bugfixes but that's it.
10
11All new work and bugfixes happen on master branch.
12
13Old, old versions may be convenient for you to use for some reason. But unless
14you pay for support or have contributed work to lws so we feel we owe you some
15consideration, nobody else has any reason to particularly care about solving
16issues on ancient versions. Whereas if the problem exists on master, and can be
17reproduced by developers, it usually gets attention, often immediately.
18
19If the problem doesn't exist on master, you can either use master or check also
20the -stable branch of the last released version to see if it was already solved
21there.
22
23Library is a component
24----------------------
25
26As a library, lws is always just a component in a bigger application.
27
28When users have a problem involving lws, what is happening in the bigger
29application is usually critical to understand what is going on (and where the
30solution lies). Sometimes access to the remote peer like server or client is also
31necessary to provoke the symptom. Sometimes, the problem is in lws, but
32sometimes the problem is not in lws but in these other pieces.
33
34Many users are able to share their sources, but others decide not to, for
35presumed "commercial advantage" or whatever. (In any event, it can be painful
36looking through large chunks of someone else's sources for problems when that
37is not the library author's responsibility.)
38
39This makes answering questions like "what is wrong with my code I am not
40going to show you?" or even "what is wrong with my code?" very difficult.
41
42Even if it's clear there is a problem somewhere, it cannot be understood or
43reproduced by anyone else if it needs user code that isn't provided.
44
45The biggest question is, "is this an lws problem actually"? To solve that
46the best solution is to strip out all or as much user code as possible,
47and see if the problem is still coming.
48
49
50Use the test apps / minimal examples as sanity checks
51-----------------------------------------------------
52
53The test server and client, and any more specifically relevant minimal example
54 are extremely useful for sanity checks and debugging guidance.
55
56 - **test apps work on your platform**, then either
57 - your user code is broken, align it to how the test apps work, or,
58 - something from your code is required to show an lws problem, provide a
59 minimal patch on a test app so it can be reproduced
60
61 - **test apps break on your platform**, but work on, eg, x86_64, either
62 - toolchain or platform-specific (eg, OS) issue, or
63 - lws platform support issue
64
65 - **test apps break everywhere**
66 - sounds like lws problem, info to reproduce and / or a patch is appreciated
67
README.release-policy.md
1# lws release policy
2
3## How should users consume lws?
4
5The one definitively wrong way to consume lws (or anything else) is "import" some
6version of it into your proprietary tree and think you will stick with that
7forever, perhaps piling cryptic fixes or hacks on top until quite quickly,
8nobody dare think about updating it.
9
10The stable releases go on to a branch like v4.0-stable as described below, over
11time these attract dozens or even hundreds of minor or major fix patches
12backported from master. So you should not consume tags like v4.0.0 but build
13into your planning that you will need to follow v4.0-stable in order to stay on
14top of known bugs.
15
16And we only backport fixes to the last stable release, although we will make
17exceptions for important fixes. So after a while, trying to stick with one
18old versions means nobody is providing security fixes on it any more. So you
19should build into your planning that you will follow lws release upgrades.
20
21If you find problems and create fixes, please upstream them, simplifying your
22life so you can just directly consume the upstream tree with no private changes.
23
24## Master branch
25
26Master branch is the default and all new work happens there. It's unstable and
27subject to history rewrites, patches moving about and being squashed etc. In
28terms of it working, it is subject to passing CI tests including a battery of
29runtime tests, so if it is passing CI as it usually is then it's probably in
30usable shape. See "Why no history on master" below for why it's managed like
31that.
32
33![all work happens on master](../doc-assets/lws-relpol-1.svg)
34
35If you have patches (you are a hero) they should be targeted at master.
36
37To follow such a branch, `git pull` is the wrong tool... the starting point
38of what you currently have may no longer exist remotely due to rearranging the
39patches there. Instead use a flow like this:
40
41```
42 $ git fetch https://libwebsockets.org/repo/libwebsockets +master:m && git reset --hard m
43```
44
45This fetches current remote master into local branch `m`, and then forces your
46local checkout to exactly match `m`. This replaces your checked-out tree
47including any of your local changes, so stash those first, or use stgit or so
48to pop them before updating your basis against lws master.
49
50## Stable branches
51
52Master is very useful for coordinating development, and integrating WIP,
53but for distros or integration into large user projects some stability is often
54more desirable than the latest development work.
55
56Periodically, when master seems in good shape and various new developments seem
57to be working, it's copied out into a versioned stable branch, like `v3.0-stable`.
58
59![stable branches are copied from master](../doc-assets/lws-relpol-2.svg)
60
61The initial copy is tagged with, eg, `v3.0.0`.
62
63(At that time, master's logical version is set to "...99", eg, `v3.0.99` so
64version comparisons show that version of master is "later" than any other
65v3.0 version, which will never reach 99 point releases itself, but "earlier"
66than, eg, v3.1.)
67
68## Backport policy
69
70Work continues on master, and as part of that usually bugs are reported and / or
71fixes found that may apply not just to current master, but the version of master
72that was copied to form the last -stable branch.
73
74In that case, the patch may be backported to the last stable branch to also fix
75the bug there. In the case of refactors or major internal improvements, these
76typically do not get backported.
77
78This applies only to fixes and public API-neutral internal changes to lws... if
79new features were backported or API changes allowed, then there would be
80multiple apis under the same version name and library soname, which is
81madness.
82
83When new stable releases are made, the soname is bumped reflecting the API is
84different than that of previous versions.
85
86![backports from master to stable](../doc-assets/lws-relpol-3.svg)
87
88If there is something you need in a later lws version that is not backported,
89you need to either backport it yourself or use a later lws version.
90Using a more recent version of lws (and contributing fixes and changes so you
91yourself can get them easily as well as contributing for others) is almost
92always the correct way.
93
94## Stable point releases
95
96Periodically fix patches pile up on the -stable branch and are tagged out as
97"point releases". So if the original stable release was "v3.0.0", the point
98release may be "v3.0.1".
99
100![point releases of stable](../doc-assets/lws-relpol-4.svg)
101
102## Critical fixes
103
104Sometimes a bug is found and fixed that had been hiding for a few versions.
105If the bug has some security dimension or is otherwise important, we may
106backport it to a few recent releases, not just the last one. This is pretty
107uncommon though.
108
109![backport to multiple stable branches](../doc-assets/lws-relpol-5.svg)
110
111## Why no history on master
112
113Git is a wonderful tool that can be understood to have two main modes of operation,
114merge and rebase that are mutually exclusive. Most devs only use merge / pull,
115but rebase / fetch is much more flexible. Running master via rebases allows me to
116dispense with feature branches during development and enables tracking multiple
117in-progress patches in-tree by updating them in place. If this doesn't make
118sense or seems heretical to you, it's OK I don't need devsplain'ing about it,
119just sit back and enjoy the clean, rapid development results.
120
121Since stable branches don't allow new features, they are run as traditional trees
122with a history, like a one-way pile of patches on top of the original release. If
123CI shows something is messed up with the latest patch, I will edit it in-place if
124it has only been out for a few hours, but there is no re-ordering or other history
125manipulation.
126
127
README.test-apps.md
1Overview of lws test apps
2=========================
3
4Are you building a client? You just need to look at the test client
5[libwebsockets-test-client](../test-apps/test-client.c).
6
7If you are building a standalone server, there are three choices, in order of
8preferability.
9
101) lwsws + protocol plugins
11
12Lws provides a generic web server app that can be configured with JSON
13config files. https://libwebsockets.org itself uses this method.
14
15With lwsws handling the serving part, you only need to write an lws protocol
16plugin. See [plugin-standalone](../plugin-standalone) for an example of how
17to do that outside lws itself, using lws public apis.
18
19 $ cmake .. -DLWS_WITH_LWSWS=1
20
21See [README.lwsws.md](../READMEs/README.lwsws.md) for information on how to configure
22lwsws.
23
24NOTE this method implies libuv is used by lws, to provide crossplatform
25implementations of timers, dynamic lib loading etc for plugins and lwsws.
26
272) Using plugins in code
28
29This method lets you configure web serving in code, instead of using lwsws.
30
31Plugins are still used, but you have a choice whether to dynamically load
32them or statically include them. In this example, they are dynamically
33loaded.
34
35 $ cmake .. -DLWS_WITH_PLUGINS=1
36
37See, eg, the [test-server](../test-apps/test-server.c)
38
393) protocols in the server app
40
41This is the original way lws implemented servers, plugins and libuv are not
42required, but without plugins separating the protocol code directly, the
43combined code is all squidged together and is much less maintainable.
44
45This method is still supported in lws but all ongoing and future work is
46being done in protocol plugins only.
47
48You can simply include the plugin contents and have it buit statically into
49your server, just define this before including the plugin source
50
51```
52#define LWS_PLUGIN_STATIC
53```
54
55This gets you most of the advantages without needing dynamic loading +
56libuv.
57
58
59Notes about lws test apps
60=========================
61
62@section tsb Testing server with a browser
63
64If you run [libwebsockets-test-server](../test-apps/test-server.c) and point your browser
65(eg, Chrome) to
66
67 http://127.0.0.1:7681
68
69It will fetch a script in the form of `test.html`, and then run the
70script in there on the browser to open a websocket connection.
71Incrementing numbers should appear in the browser display.
72
73By default the test server logs to both stderr and syslog, you can control
74what is logged using `-d <log level>`, see later.
75
76
77@section tsd Running test server as a Daemon
78
79You can use the -D option on the test server to have it fork into the
80background and return immediately. In this daemonized mode all stderr is
81disabled and logging goes only to syslog, eg, `/var/log/messages` or similar.
82
83The server maintains a lockfile at `/tmp/.lwsts-lock` that contains the pid
84of the master process, and deletes this file when the master process
85terminates.
86
87To stop the daemon, do
88```
89 $ kill \`cat /tmp/.lwsts-lock\`
90```
91If it finds a stale lock (the pid mentioned in the file does not exist
92any more) it will delete the lock and create a new one during startup.
93
94If the lock is valid, the daemon will exit with a note on stderr that
95it was already running.
96
97@section clicert Testing Client Certs
98
99Here is a very quick way to create a CA, and a client and server cert from it,
100for testing.
101
102```
103$ cp -rp ./scripts/client-ca /tmp
104$ cd /tmp/client-ca
105$ ./create-ca.sh
106$ ./create-server-cert.sh server
107$ ./create-client-cert.sh client
108```
109
110The last step wants an export password, you will need this password again to
111import the p12 format certificate into your browser.
112
113This will get you the following
114
115|name|function|
116|----|--------|
117|ca.pem|Your Certificate Authority cert|
118|ca.key|Private key for the CA cert|
119|client.pem|Client certificate, signed by your CA|
120|client.key|Client private key|
121|client.p12|combined client.pem + client.key in p12 format for browsers|
122|server.pem|Server cert, signed by your CA|
123|server.key|Server private key|
124
125You can confirm yourself the client and server certs are signed by the CA.
126
127```
128 $ openssl verify -verbose -trusted ca.pem server.pem
129 $ openssl verify -verbose -trusted ca.pem client.pem
130```
131
132Import the client.p12 file into your browser. In FFOX57 it's
133
134 - preferences
135 - Privacy & Security
136 - Certificates | View Certificates
137 - Certificate Manager | Your Certificates | Import...
138 - Enter the password you gave when creating client1.p12
139 - Click OK.
140
141You can then run the test server like this:
142
143```
144 $ libwebsockets-test-server -s -A ca.pem -K server.key -C server.pem -v
145```
146
147When you connect your browser to https://localhost:7681 after accepting the
148selfsigned server cert, your browser will pop up a prompt to send the server
149your client cert (the -v switch enables this). The server will only accept
150a client cert that has been signed by ca.pem.
151
152@section sssl Using SSL on the server side
153
154To test it using SSL/WSS, just run the test server with
155```
156 $ libwebsockets-test-server --ssl
157```
158and use the URL
159```
160 https://127.0.0.1:7681
161```
162The connection will be entirely encrypted using some generated
163certificates that your browser will not accept, since they are
164not signed by any real Certificate Authority. Just accept the
165certificates in the browser and the connection will proceed
166in first https and then websocket wss, acting exactly the
167same.
168
169[test-server.c](../test-apps/test-server.c) is all that is needed to use libwebsockets for
170serving both the script html over http and websockets.
171
172@section lwstsdynvhost Dynamic Vhosts
173
174You can send libwebsockets-test-server or libwebsockets-test-server-v2.0 a SIGUSR1
175to toggle the creation and destruction of an identical second vhost on port + 1.
176
177This is intended as a test and demonstration for how to bring up and remove
178vhosts dynamically.
179
180@section unixskt Testing Unix Socket Server support
181
182Start the test server with -U and the path to create the unix domain socket
183
184```
185 $ libwebsockets-test-server -U /tmp/uds
186```
187
188On exit, lws will delete the socket inode.
189
190To test the client side, eg
191
192```
193 $ nc -C -U /tmp/uds -i 30
194```
195
196and type
197
198`GET / HTTP/1.1`
199
200followed by two ENTER. The contents of test.html should be returned.
201
202@section wscl Testing websocket client support
203
204If you run the test server as described above, you can also
205connect to it using the test client as well as a browser.
206
207```
208 $ libwebsockets-test-client localhost
209```
210
211will by default connect to the test server on localhost:7681
212and print the dumb increment number from the server at the
213same time as drawing random circles in the mirror protocol;
214if you connect to the test server using a browser at the
215same time you will be able to see the circles being drawn.
216
217The test client supports SSL too, use
218
219```
220 $ libwebsockets-test-client localhost --ssl -s
221```
222
223the -s tells it to accept the default self-signed cert from the server,
224otherwise it will strictly fail the connection if there is no CA cert to
225validate the server's certificate.
226
227
228@section choosingts Choosing between test server variations
229
230If you will be doing standalone serving with lws, ideally you should avoid
231making your own server at all, and use lwsws with your own protocol plugins.
232
233The second best option is follow test-server-v2.0.c, which uses a mount to
234autoserve a directory, and lws protocol plugins for ws, without needing any
235user callback code (other than what's needed in the protocol plugin).
236
237For those two options libuv is needed to support the protocol plugins, if
238that's not possible then the other variations with their own protocol code
239should be considered.
240
241@section tassl Testing SSL on the client side
242
243To test SSL/WSS client action, just run the client test with
244```
245 $ libwebsockets-test-client localhost --ssl
246```
247By default the client test applet is set to accept self-signed
248certificates used by the test server, this is indicated by the
249`use_ssl` var being set to `2`. Set it to `1` to reject any server
250certificate that it doesn't have a trusted CA cert for.
251
252
253@section taping Using the websocket ping utility
254
255libwebsockets-test-ping connects as a client to a remote
256websocket server and pings it like the
257normal unix ping utility.
258```
259 $ libwebsockets-test-ping localhost
260 handshake OK for protocol lws-mirror-protocol
261 Websocket PING localhost.localdomain (127.0.0.1) 64 bytes of data.
262 64 bytes from localhost: req=1 time=0.1ms
263 64 bytes from localhost: req=2 time=0.1ms
264 64 bytes from localhost: req=3 time=0.1ms
265 64 bytes from localhost: req=4 time=0.2ms
266 64 bytes from localhost: req=5 time=0.1ms
267 64 bytes from localhost: req=6 time=0.2ms
268 64 bytes from localhost: req=7 time=0.2ms
269 64 bytes from localhost: req=8 time=0.1ms
270 ^C
271 --- localhost.localdomain websocket ping statistics ---
272 8 packets transmitted, 8 received, 0% packet loss, time 7458ms
273 rtt min/avg/max = 0.110/0.185/0.218 ms
274 $
275```
276By default it sends 64 byte payload packets using the 04
277PING packet opcode type. You can change the payload size
278using the `-s=` flag, up to a maximum of 125 mandated by the
27904 standard.
280
281Using the lws-mirror protocol that is provided by the test
282server, libwebsockets-test-ping can also use larger payload
283sizes up to 4096 is BINARY packets; lws-mirror will copy
284them back to the client and they appear as a PONG. Use the
285`-m` flag to select this operation.
286
287The default interval between pings is 1s, you can use the -i=
288flag to set this, including fractions like `-i=0.01` for 10ms
289interval.
290
291Before you can even use the PING opcode that is part of the
292standard, you must complete a handshake with a specified
293protocol. By default lws-mirror-protocol is used which is
294supported by the test server. But if you are using it on
295another server, you can specify the protocol to handshake with
296by `--protocol=protocolname`
297
298
299@section ta fraggle Fraggle test app
300
301By default it runs in server mode
302```
303 $ libwebsockets-test-fraggle
304 libwebsockets test fraggle
305 (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under MIT
306 Compiled with SSL support, not using it
307 Listening on port 7681
308 server sees client connect
309 accepted v06 connection
310 Spamming 360 random fragments
311 Spamming session over, len = 371913. sum = 0x2D3C0AE
312 Spamming 895 random fragments
313 Spamming session over, len = 875970. sum = 0x6A74DA1
314 ...
315```
316You need to run a second session in client mode, you have to
317give the `-c` switch and the server address at least:
318```
319 $ libwebsockets-test-fraggle -c localhost
320 libwebsockets test fraggle
321 (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under MIT
322 Client mode
323 Connecting to localhost:7681
324 denied deflate-stream extension
325 handshake OK for protocol fraggle-protocol
326 client connects to server
327 EOM received 371913 correctly from 360 fragments
328 EOM received 875970 correctly from 895 fragments
329 EOM received 247140 correctly from 258 fragments
330 EOM received 695451 correctly from 692 fragments
331 ...
332```
333The fraggle test sends a random number up to 1024 fragmented websocket frames
334each of a random size between 1 and 2001 bytes in a single message, then sends
335a checksum and starts sending a new randomly sized and fragmented message.
336
337The fraggle test client receives the same message fragments and computes the
338same checksum using websocket framing to see when the message has ended. It
339then accepts the server checksum message and compares that to its checksum.
340
341
342@section taproxy proxy support
343
344The http_proxy environment variable is respected by the client
345connection code for both `ws://` and `wss://`. It doesn't support
346authentication.
347
348You use it like this
349```
350 $ export http_proxy=myproxy.com:3128
351 $ libwebsockets-test-client someserver.com
352```
353
354@section talog debug logging
355
356By default logging of severity "notice", "warn" or "err" is enabled to stderr.
357
358Again by default other logging is compiled in but disabled from printing.
359
360By default debug logs below "notice" in severity are not compiled in. To get
361them included, add this option in CMAKE
362
363```
364 $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG
365```
366
367If you want to see more detailed debug logs, you can control a bitfield to
368select which logs types may print using the `lws_set_log_level()` api, in the
369test apps you can use `-d <number>` to control this. The types of logging
370available are (OR together the numbers to select multiple)
371
372 - 1 ERR
373 - 2 WARN
374 - 4 NOTICE
375 - 8 INFO
376 - 16 DEBUG
377 - 32 PARSER
378 - 64 HEADER
379 - 128 EXTENSION
380 - 256 CLIENT
381 - 512 LATENCY
382
383
384@section ws13 Websocket version supported
385
386The final IETF standard is supported for both client and server, protocol
387version 13.
388
389
390@section latency Latency Tracking
391
392Since libwebsockets runs using `poll()` and a single threaded approach, any
393unexpected latency coming from system calls would be bad news. There's now
394a latency tracking scheme that can be built in with `-DLWS_WITH_LATENCY=1` at
395cmake, logging the time taken for system calls to complete and if
396the whole action did complete that time or was deferred.
397
398You can see the detailed data by enabling logging level 512 (eg, `-d 519` on
399the test server to see that and the usual logs), however even without that
400the "worst" latency is kept and reported to the logs with NOTICE severity
401when the context is destroyed.
402
403Some care is needed interpreting them, if the action completed the first figure
404(in us) is the time taken for the whole action, which may have retried through
405the poll loop many times and will depend on network roundtrip times. High
406figures here don't indicate a problem. The figure in us reported after "lat"
407in the logging is the time taken by this particular attempt. High figures
408here may indicate a problem, or if you system is loaded with another app at
409that time, such as the browser, it may simply indicate the OS gave preferential
410treatment to the other app during that call.
411
412
413@section autobahn Autobahn Test Suite
414
415Lws can be tested against the autobahn websocket fuzzer in both client and
416server modes
417
4181) pip install autobahntestsuite
419
4202) From your build dir:
421
422```
423 $ cmake .. -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_MINIMAL_EXAMPLES=1 && make
424```
425
4263) ../scripts/autobahn-test.sh
427
4284) In a browser go to the directory you ran wstest in (eg, /projects/libwebsockets)
429
430file:///projects/libwebsockets/build/reports/clients/index.html
431
432to see the results
433
434
435@section autobahnnotes Autobahn Test Notes
436
4371) Two of the tests make no sense for Libwebsockets to support and we fail them.
438
439 - Tests 2.10 + 2.11: sends multiple pings on one connection. Lws policy is to
440only allow one active ping in flight on each connection, the rest are dropped.
441The autobahn test itself admits this is not part of the standard, just someone's
442random opinion about how they think a ws server should act. So we will fail
443this by design and it is no problem about RFC6455 compliance.
444
4452) Currently two parts of autobahn are broken and we skip them
446
447https://github.com/crossbario/autobahn-testsuite/issues/71
448
449
README.udp.md
1## Using UDP in lws
2
3UDP is supported in lws... the quickest way is to use the api
4`lws_create_adopt_udp()` which returns a wsi bound to the provided
5vhost, protocol, `lws_retry` struct, dns address and port.
6
7The wsi can be treated normally and `lws_write()` used to write on
8it.
9
10## Implementing UDP retries
11
12Retries are important in udp but there's no standardized ack method
13unlike tcp. Lws allows you to bind an `lws_retry` struct describing
14the policy to the udp wsi, but since one UDP socket may have many
15transactions in flight, the `lws_sul` and `uint16_t` to count the
16retries must live in the user's transaction object like this
17
18```
19...
20 lws_sorted_usec_list_t sul;
21 uint16_t retry;
22...
23```
24
25in the `LWS_CALLBACK_RAW_WRITEABLE` callback, before doing the write,
26set up the retry like this
27
28```
29 if (lws_dll2_is_detached(&transaction->sul_write.list) &&
30 lws_retry_sul_schedule_retry_wsi(wsi, &transaction->sul_write,
31 transaction_retry_write_cb,
32 &transaction->retry_count_write)) {
33 /* we have reached the end of our concealed retries */
34 lwsl_warn("%s: concealed retries done, failing\n", __func__);
35 goto retry_conn;
36 }
37```
38
39This manages the retry counter in the transaction object, guards against it wrapping,
40selects the timeout using the policy bound to the wsi, and sets the `lws_sul` in the
41transaction object to call the given callback if the sul time expires.
42
43In the callback, it should simply call `lws_callback_on_writable()` for the udp wsi.
44
45## Simulating packetloss
46
47lws now allows you to set the amount of simulated packetloss on udp rx and tx in
48the context creation info struct, using `.udp_loss_sim_tx_pc` and `.udp_loss_sim_rx_pc`,
49the values are percentages between 0 and 100. 0, the default, means no packetloss.
50
51
README.unix-domain-reverse-proxy.md
1## Unix Domain Sockets Reverse Proxy
2
3### Introduction
4
5lws is able to use a mount to place reverse proxies into the URL space.
6
7These are particularly useful when using Unix Domain Sockets, basically
8files in the server filesystem, to communicate between lws and a separate
9server process and integrate the result into a coherent URL namespace on
10the lws side. It's also possible to proxy using tcp sockets.
11
12![overview](../doc-assets/http-proxy-overview.svg)
13
14This has the advantage that the actual web server that forwards the
15data from the unix socket owner is in a different process than the server
16that serves on the unix socket. If it has problems, they do not affect
17the actual public-facing web server. The unix domain socket server may
18be in a completely different language than the web server.
19
20Compared to CGI, there are no forks to make a connection to the unix
21domain socket server.
22
23### Mount origin format
24
25Unix Domain Sockets are effectively "files" in the server filesystem, and
26are defined by their filepath. The "server" side that is to be proxied opens
27the socket and listens on it, which creates a file in the server filesystem.
28The socket understands either http or https protocol.
29
30Lws can be told to act as a proxy for that at a mountpoint in the lws vhost
31url space.
32
33If your mount is expressed in C code, then the mount type is LWSMPRO_HTTP or
34LWSMPRO_HTTPS depending on the protocol the unix socket understands, and the
35origin address has the form `+/path/to/unix/socket:/path/inside/mount`.
36
37The + at the start indicates it is a local unix socket we are proxying, and
38the ':' acts as a delimiter for the socket path, since unlike other addresses
39the unix socket path can contain '/' itself.
40
41### Connectivity rules and translations
42
43Onward proxy connections from lws to the Unix Domain Socket happen using
44http/1.1. That implies `transfer-encoding: chunking` in the case that the
45length of the output is not known beforehand.
46
47Lws takes care of stripping any chunking (which is illegal in h2) and
48translating between h1 and h2 header formats if the return connection is
49actually in http/2.
50
51The h1 onward proxy connection translates the following headers from the return
52connection, which may be h1 or h2:
53
54Header|Function
55---|---
56host|Which vhost
57etag|Information on any etag the client has cached for this URI
58if-modified-since|Information on the freshness of any etag the client has cached for this URI
59accept-language|Which languages the return path client prefers
60accept-encoding|Which compression encodings the client can accept
61cache-control|Information from the return path client about cache acceptability
62x-forwarded-for|The IP address of the return path client
63
64This implies that the proxied connection can
65
66 - return 301 etc to say the return path client's etag is still valid
67
68 - choose to compress using an acceptable content-encoding
69
70The following headers are translated from the headers replied via the onward
71connection (always h1) back to the return path (which may be h1 or h2)
72
73Header|Function
74---|---
75content-length|If present, an assertion of how much payload is expected
76content-type|The mimetype of the payload
77etag|The canonical etag for the content at this URI
78accept-language|This is returned to the return path client because there is no easy way for the return path client to know what it sent originally. It allows clientside selection of i18n.
79content-encoding|Any compression format on the payload (selected from what the client sent in accept-encoding, if anything)
80cache-control|The onward server's response about cacheability of its payload
81
82### h1 -> h2 conversion
83
84Chunked encoding that may have been used on the outgoing proxy client connection
85is removed for h2 return connections (chunked encoding is illegal for h2).
86
87Headers are converted to all lower-case and hpack format for h2 return connections.
88
89Header and payload proxying is staged according to when the return connection
90(which may be an h2 child stream) is writable.
91
92### Behaviour if unix domain socket server unavailable
93
94If the server that listens on the unix domain socket is down or being restarted,
95lws understands that it couldn't connect to it and returns a clean 503 response
96`HTTP_STATUS_SERVICE_UNAVAILABLE` along with a brief human-readable explanation.
97
98The generated status page produced will try to bring in a stylesheet
99`/error.css`. This allows you to produce a styled error pages with logos,
100graphics etc. See [this](https://libwebsockets.org/git/badrepo) for an example of what you can do with it.
101
102
README.vulnerability-reporting.md
1## Vulnerability Reporting
2
3If you become aware of an issue with lws that has a security
4dimension for users, please contact `andy@warmcat.com` by
5direct email.
6
7## Procedure for announcing vulnerability fixes
8
9The problem and fixed versions will be announced on the
10libwebsockets mailing list and a note added to the master
11README.md.
12
13