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-android.md
1# Building for Android NDK
2
3If you have the ndk and prebuilt toolchains with that, you can simply build
4lws library for your android app from one cmake and one make command.
5
6However if you want a tls lib, you have to take care of building and pointing
7to that first. But if it's a cmake project like mbedtls, that also is just a
8matter of one cmake and one make.
9
10## Installing NDK pieces
11
12There's probably a more direct way but the official way is install the whole
13Android Studio and then run `sdkmanager` to install a recent NDK.
14
15I installed the sdk and ndk pieces into /opt/android/ and that's how the
16`./contrib/cross-aarch64-android.cmake` toolchain file is shipped. You can
17adapt some settings at the top of that file including the path if needed.
18
19## Fetching lws (needed first for cross toolchain file)
20
21It doesn't care where you put these projects, but for simplicity they should
22be in the same parent dir, like
23
24```
25 - /home/someone
26 - /home/someone/libwebsockets
27 - /home/someone/mbedtls
28```
29
30The reason is that building mbedtls need the cross toolchain file from
31libwebsockets, that's also why we have to get libwebsockets first now but
32build it later.
33
34```
35$ git clone https://libwebsockets.org/repo/libwebsockets
36```
37
38## Building mbedtls
39
40```
41$ git clone https://github.com/ARMmbed/mbedtls.git
42$ cd mbedtls
43$ mkdir build
44$ cd build
45$ rm -f CMakeCache.txt && \
46 cmake .. -DCMAKE_TOOLCHAIN_FILE=../libwebsockets/contrib/cross-aarch64-android.cmake \
47 -DUSE_SHARED_MBEDTLS_LIBRARY=1 \
48 -DENABLE_PROGRAMS=0 \
49 -Wno-dev && \
50 make -j && \
51 cmake --install .
52```
53
54The lws toolchain file sets the path to install into as the cross root path, so
55despite it looks like the destination dir is missing for the install, it will
56go into, eg `/opt/android/ndk/21.1.6352462/platforms/android-24/arch-arm64/lib/libmbedcrypto.a`
57where lws will look for it
58
59## Building lws
60
61You don't need to explain where mbedtls can be found... lws will build with the
62same toolchain file that sets the cross root to the same place as mbedtls, it
63will easily find them there without any further hints.
64
65```
66$ mkdir build
67$ cd build
68$ rm -f CMakeCache.txt && \
69 cmake .. -DCMAKE_TOOLCHAIN_FILE=../libwebsockets/contrib/cross-aarch64-android.cmake \
70 -DLWS_WITH_MBEDTLS=1 \
71 -DLWS_WITHOUT_TESTAPPS=1 && \
72 make && \
73 cmake --install .
74```
75
76That's it, both mbedtls and lws library and header files are installed into the
77ndk cross root.
78
README.build-windows.md
1# Some notes for the windows jungle
2
3This was how I compiled libwebsockets starting from a blank windows install
4in March - April 2020. Doing this on a linux distro is way simpler and quicker
5than all this!
6
7## Notes on vm installation
8
9### Disk size
10
11For building you'll need 40GB+ available for the guest storage.
12
13### Required: Windows product key
14
15Assuming like me the first thing you do with a new laptop is install Linux over
16the windows it came with, you can recover your 'windows tax' windows product key
17from your device typically using `sudo strings /sys/firmware/acpi/tables/MSDM`,
18and use that for your VM install.
19
20### Required: Spice guest
21
22To have shared clipboard, and for windows video driver to match your vm window
23resolution, you must install spice guest tools inside the windows VM. It also
24installs some virtio pieces you will want.
25
26https://www.spice-space.org/download/windows/spice-guest-tools/spice-guest-tools-latest.exe
27
28### Blood-pressure reduction: Firefox
29
30https://www.mozilla.org/en-US/exp/firefox/
31
32When it's up, add-ons: ublock origin, privacy badger, noscript, disable search
33bar prediction
34
35### Blood-pressure reduction: Clink
36
37This is a hack on cmd.exe that lets it understand Ctrl-R and fixup unix-style
38slashes automagically.
39
40https://github.com/mridgers/clink/releases/download/0.4.9/clink_0.4.9_setup.exe
41
42If you're usually using *nix, you definitely need this to keep your sanity.
43
44### Required: cmake
45
46CMake have a windows installer thing downloadable from here
47
48[cmake](https://cmake.org/download/)
49
50after that you can use `cmake` from the terminal OK.
51
52### Required: git
53
54Visit the canonical git site to download their windows installer thing
55
56[git](https://git-scm.com/download/win)
57
58**Select the install option for "extra unix commands"** so you can get `ls -l`,
59`cp`, `mv` and suchlike working in cmd.exe... that's awesome, thanks git!
60
61Afterwards you can just use `git` as normal from cmd.exe as well.
62
63### Required: Install the "free" "community" visual studio
64
65You can do this through "windows store" by searching for "visual studio"
66
67I installed as little as possible, we just want the C "C++" tools... 7GB :-)
68
69It still wouldn't link without the "mt" helper tool from the
70huge windows SDK, so you have to install GB of that as well.
71
72They don't mention it during the install, but after 30 days this "free"
73"community" edition demands you open a microsoft account or it stops working.
74In the install they give you the option to add a microsoft account and the
75alternative is, "not now, maybe later". Compare and contrast to gcc or git or
76the other FOSS projects.
77
78### Required: OpenSSL
79
80Ugh... I tried using prebuilts but it's unreliable and needs an unfeasible
81amount of trust. So I recommend bite the bullet and build your own... that's
82trivial on Linux but of course windows makes everything nasty.
83
84At least hopefully all the "research" is done and listed out here.
85
86#### OpenSSL build Prerequisite: install perl binary
87
88Move the git version of perl out of the way, it won't work for OpenSSL build
89
90```
91mv /usr/bin/perl /usr/bin/perl-git
92```
93
94For windows, OpenSSL "recommends" ActiveState perl but it doesn't work for me,
95complaining about stuff needed from cpan and then dying when it was installed.
96"Strawberry Perl" is installed in `C:\Strawberry` and worked out the box.
97
98http://strawberryperl.com/download/5.30.2.1/strawberry-perl-5.30.2.1-64bit.msi
99
100The installer sets up `%PATH%` if you open a new cmd window.
101
102#### OpenSSL build Prerequisite: NASM
103
104Go here and click on the latest stable, download the win32 .exe
105
106https://nasm.us/
107
108Just install via the defaults. Then add it to the PATH temporarily...
109
110```
111$ set PATH=%PATH%;C:\Program Files (x86)\NASM
112```
113
114#### OpenSSL build setup: source VC env vars
115
116These fix up the PATH and include dirs etc necessary for VC build in the cmd
117window.
118
119```
120$ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64
121```
122
123### OpenSSL build:
124
125Grab openssl from git... assuming the prerequisites above went well it will
126just sit there building for 30 minutes or whatever.
127
128```
129$ git clone https://github.com/openssl/openssl
130$ cd openssl
131$ perl Configure VC-WIN64A
132$ nmake
133```
134
135Afterwards, open an Administrator mode cmd.exe, redo the msvc path and then
136install the build.
137
138```
139$ cd openssl
140$ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64
141$ nmake install
142```
143
144Oh another grindingly slow windows build action. Finally it's in there in
145`C:\Program Files\OpenSSL`.
146
147libraries are looking for a cert bundle at "C:\Program Files\Common Files\SSL\cert.pem"...
148it's not documented or included in the zip file from the above, so...
149
150#### Installing a cert bundle
151
152You can get a trusted cert bundle from here
153
154[drwetter/testssl cert bundle](https://raw.githubusercontent.com/drwetter/testssl.sh/3.1dev/etc/Microsoft.pem)
155
156Save it into `C:\Program Files\Common Files\SSL\cert.pem` where openssl will be able to see it.
157
158## Required: pthreads
159
160It's amazing but after all these years windows doesn't offer pthreads compatibility
161itself. Just like the many other missing POSIX bits like fork().
162
163I downloaded the latest (2012) zip release of pthreads-win32 from here
164
165ftp://sourceware.org/pub/pthreads-win32
166
167Then I created a dir "C:\Program Files (x86)\pthreads", and copied the `dll`,
168`include` and `lib` subdirs from the `prebuilt` folder in the zip there.
169
170The cmake incantation to build against pthreads set up like that is
171
172```
173 $ cmake .. -DLWS_HAVE_PTHREAD_H=1 -DLWS_EXT_PTHREAD_INCLUDE_DIR="C:\Program Files (x86)\pthreads\include" -DLWS_EXT_PTHREAD_LIBRARIES="C:\Program Files (x86)\pthreads\lib\x64\libpthreadGC2.a" -DLWS_WITH_MINIMAL_EXAMPLES=1
174```
175
176## Building libwebsockets
177
178We'll clone libwebsockets then use cmake to build via vs tools
179
180```
181> git clone https://libwebsockets.org/repo/libwebsockets
182> cd libwebsockets
183> mkdir build
184> cd build
185> cmake ..
186> cmake --build . --config DEBUG
187```
188
189Installing requires admin privs, I opened a second cmd window as admin and did it
190there.
191
192```
193> cmake --install . --config DEBUG
194```
195
196### Hack the libs into view
197
198The libs we built against aren't visible in the system, I don't know what
199Real Windows Programmers are supposed to do about that, but I used an Admin cmd
200prompt to copy them into C:\windows\system32
201
202```
203$ cp "C:\Program Files (x86)\pthreads\dll\x64\pthreadGC2.dll" "C:\Program Files\OpenSSL\bin\libcrypto-3.dll" "C:\Program Files\OpenSSL\bin\libssl-3.dll" C:\Windows\system32
204```
205
206After that you can run the test apps OK, eg
207
208```
209$ libwebsockets-test-server.exe -s
210```
211
212## Note about using paths with spaces in with cmake
213
214
215
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/main/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.captive-portal-detection.md
1# Captive Portal Detection
2
3## Background
4
5Wifi devices may face some interception of their connection to the
6internet, it's very common for, eg, coffee shop wifi to present some
7kind of login or other clickthrough before access to the Internet is
8granted. Devices may need to understand that they are in this
9situation, and there are several different techniques for trying to
10gague it.
11
12Sequence-wise the device has been granted a DHCP lease and has been
13configured with DNS, but the DNS may be wrongly resolving everything
14to an address on the LAN or a portal on the net.
15
16Whether there is a captive portal active should be a sticky state for a given
17connection if there is not going to be any attempt to login or pass the landing
18page, it only needs checking for after DHCP acquisition then. If there will be
19an attempt to satisfy the landing page, the test should be repeated after the
20attempt.
21
22## Detection schemes
23
24The most popular detection scheme by numbers is Android's method,
25which is to make an HTTP client GET to `http://connectivitycheck.android.com/generate_204`
26and see if a 204 is coming back... if intercepted, typically there'll be a
273xx redirect to the portal, perhaps on https. Or, it may reply on http with
28a 200 and show the portal directly... either way it won't deliver a 204
29like the real remote server does.
30
31Variations include expecting a 200 but with specific http body content, and
32doing a DNS lookup for a static IP that the device knows; if it's resolved to
33something else, it knows there's monkey business implying a captive portal.
34
35Other schemes involve https connections going out and detecting that the cert
36of the server it's actually talking to doesn't check out, although this is
37potentially ambiguous.
38
39Yet more methods are possible outside of tcp or http.
40
41## lws captive portal detect support
42
43lws provides a generic api to start captive portal detection...
44
45```
46LWS_EXTERN LWS_VISIBLE int
47lws_system_cpd_start(struct lws_context *context);
48```
49
50and two states in `lws_system` states to trigger it from, either
51`LWS_SYSTATE_CPD_PRE_TIME` which happens after DHCP acquisition but before
52ntpclient and is suitable for non https-based scheme where the time doesn't
53need to be known, or the alternative `LWS_SYSTATE_CPD_POST_TIME` state which
54happens after ntpclient has completed and we know the time.
55
56The actual platform implementation is set using `lws_system_ops_t` function
57pointer `captive_portal_detect_request`, ie
58
59```
60 int (*captive_portal_detect_request)(struct lws_context *context);
61 /**< Check if we can go out on the internet cleanly, or if we are being
62 * redirected or intercepted by a captive portal.
63 * Start the check that proceeds asynchronously, and report the results
64 * by calling lws_captive_portal_detect_result() api
65 */
66```
67
68User platform code can provide this to implement whatever scheme they want, when
69it has arrived at a result, it can call the lws api `lws_system_cpd_result()` to
70inform lws. If there isn't any captive portal, this will also try to advance the
71system state towards OPERATIONAL.
72
73```
74/**
75 * lws_system_cpd_result() - report the result of the captive portal detection
76 *
77 * \param context: the lws_context
78 * \param result: one of the LWS_CPD_ constants representing captive portal state
79 * \param redirect_url: NULL, or the url we were redirected to if result is
80 * LWS_CPD_HTTP_REDIRECT
81 *
82 * Sets the context's captive portal detection state to result. User captive
83 * portal detection code would call this once it had a result from its test.
84 */
85LWS_EXTERN LWS_VISIBLE int
86lws_system_cpd_result(struct lws_context *context, int result, const char *redirect_url);
87```
88
89
README.cbor-cose.md
1# RFC8152 COSE apis
2
3|||
4|---|---|---|
5|cmake| `LWS_WITH_COSE`|
6|Header| ./include/libwebsockets/lws-cose.h|
7|api-test| ./minimal-examples/api-tests/api-test-cose/|
8|README| ./READMEs/README.cbor-cose.md
9
10COSE is the CBOR equivalent of the JOSE suite of crypto objects and operations.
11You can represent public and private EC, RSA and SYMMETRIC keys, and sets of
12keys of various types; import the logical keys to and from CBOR; and sign /
13verify and encrypt / decrypt payloads using structured CBOR. Key generation is
14also supported.
15
16|type|operations|algs|
17|---|---|---|
18|lws_cose_key_t|import, export, generation|EC / RSA / SYMMETRIC|
19|cose_sign1|sign, validate|ES256/384/512, RS256/384/512|
20|cose_sign|sign, validate|ES256/384/512, RS256/384/512|
21|cose_mac0|sign, validate|HS256/HS256_64/384/512|
22|cose_mac|validate only|HS256/HS256_64/384/512|
23
24The lws COSE support uses the lws gencrypto layer, which calls through to the
25tls crypto library, and so works on both OpenSSL and mbedTLS the same.
26
27An increasing number of higher-level IETF specifications use COSE underneath.
28
29## cose_key and sets
30
31Lws provides an `lws_cose_key_t` object to contain a single key's metadata and
32key material for EC, RSA and SYMMETRIC key types.
33
34There is a commandline tool wrapping the key dumping and generation apis
35available at `./minimal-examples/crypto/lws-crypto-cose-key`
36
37### cose_key and sets import from CBOR and destroying
38
39```
40lws_cose_key_t *
41lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
42 void *user, const uint8_t *in, size_t len);
43void
44lws_cose_key_destroy(lws_cose_key_t **ck);
45
46void
47lws_cose_key_set_destroy(lws_dll2_owner_t *o);
48```
49
50To convert a single key, `pkey_set` should be NULL and the created key will be
51returned, for a cose_key set, which is simply a CBOR array of cose_keys, it
52should be a prepared (ie, zero'd down if nothing in it) lws_dll2_owner_t that
53will contain the resulting list of `lws_cose_key_t` objects that were created.
54In both cases the return is NULL if there was a fatal error and anything created
55has been cleaned up, the return has no other meaning in the cose_key set case.
56
57`lws_cose_key_destroy()` destroys a single `lws_cose_key_t` and sets the
58contents of the pointer to NULL, for cose_key sets you instead pass a pointer to
59the owner object to `lws_cose_key_set_destroy()` to destroy all the keys in the
60set in one step.
61
62cose_key has some confusions about type, kty and alg may be either ints,
63representing well-known standardized key and alg types, or freeform strings.
64We convert the well-known ints to their string representations at import, so
65there can be no confusion later.
66
67### cose_key generation
68
69```
70lws_cose_key_t *
71lws_cose_key_generate(struct lws_context *context, int cose_kty, int use_mask,
72 int bits, const char *curve, const char *kid);
73```
74
75This creates an `lws_cose_key_t`, generates a key (SYMMETRIC) or keypair into
76it and returns a pointer to it.
77
78`cose_kty` is one of `LWSCOSE_WKKTV_OKP`, `LWSCOSE_WKKTV_EC2`, `LWSCOSE_WKKTV_RSA`,
79or `LWSCOSE_WKKTV_SYMMETRIC`. `bits` is valid for RSA keys and for EC keys,
80`curve` should be a well-known curve name, one of `P-256`, `P-384` and `P-521`
81currently. `use_mask` is a bitfield made up of (1 << LWSCOSE_WKKO_...) set to
82enable the usage on the key.
83
84### cose_key export to CBOR
85
86The export api uses the same CBOR write context as `lws_lec_printf()` uses to
87emit the key into an output buffer. Like the CBOR output apis, it may return
88`LWS_LECPCTX_RET_AGAIN` to indicate it filled the buffer and should be called
89again to fill another buffer. `lws_lec_init()` should be used to prepare the
90write context and `lws_lec_setbuf()` to reset the output buffer on subsequent
91calls, exactly the same as the CBOR write apis.
92
93```
94enum lws_lec_pctx_ret
95lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags);
96```
97
98`flags` may be 0 to only output the public key pieces, or `LWSJWKF_EXPORT_PRIVATE`
99to output everything.
100
101## Signing and signature validation
102
103COSE specifies three kinds of signed object, `cose_sign1` which signs a payload
104with a single algorithm and key, `cose_sign` which may sign a payload with
105multiple algorithms and keys, and `countersign`.
106
107`cose_sign1` has the advantage it can be validated with a single pass through
108the signed object; `cose_sign` unfortunately specifies the parameters of the
109signatures after the payload and must be done with multiple passes through the
110payload, for inline payloads, by caching it in heap.
111
112`cose_sign` and `cose_sign1` objects are supported by lws, Countersigned
113objects are not yet supported.
114
115`cose_mac0` is supported using HMAC for signing and validation, `cose_mac` is
116only supported for validation.
117
118There is a commandline tool wrapping the signing and validation apis
119available at `./minimal-examples/crypto/lws-crypto-cose-sign`
120
121### Signature validation
122
123Signature validation does not have to be done synchronously, to facilitate this
124first you create a validation context specifying the type (eg, `SIGTYPE_SINGLE`)
125and a keyset of public keys the signature might use to validate (notice even a
126single key is passed in an lws_dll2_owner_t keyset).
127
128Creation uses a public `lws_cose_validate_create_info_t` info struct
129
130```
131typedef struct lws_cose_validate_create_info {
132 struct lws_context *cx;
133 /**< REQUIRED: the lws context */
134 lws_dll2_owner_t *keyset;
135 /**< REQUIRED: one or more cose_keys */
136
137 enum lws_cose_sig_types sigtype;
138 /**< 0 if a CBOR tag is in the sig, else one of SIGTYPE_MULTI,
139 * SIGTYPE_SINGLE, etc*/
140
141 lws_cose_validate_pay_cb_t pay_cb;
142 /**< optional: called back with unvalidated payload pieces */
143 void *pay_opaque;
144 /**< optional: passed into pay_cb callback along with payload chunk */
145
146 lws_cose_sign_ext_pay_cb_t ext_cb;
147 /**< optional extra application data provision callback */
148 void *ext_opaque;
149 /**< optional extra application data provision callback opaque */
150 size_t ext_len;
151 /**< if we have extra app data, this must be set to the length of it */
152} lws_cose_validate_create_info_t;
153```
154
155```
156struct lws_cose_validate_context *
157lws_cose_validate_create(const lws_cose_validate_create_info_t *info);
158
159void
160lws_cose_validate_destroy(struct lws_cose_validate_context **cps);
161```
162
163after that as pieces of the signature CBOR become available, they can be
164processed by the validation context
165
166```
167int
168lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
169 const uint8_t *in, size_t in_len, size_t *used_in);
170```
171
172The parsing of the signature yields a list of result objects indicating
173information about each signature it encountered and whether it was validated or
174not. The parsing itself only fails if there is an unrecoverable error, the
175completion of parsing does not indicate validation, it may yield zero or more
176result objects indicating the validation failed.
177
178```
179lws_dll2_owner_t *
180lws_cose_validate_results(struct lws_cose_validate_context *cps);
181
182typedef struct {
183 lws_dll2_t list;
184
185 const lws_cose_key_t *cose_key;
186 cose_param_t cose_alg;
187
188 int result; /* 0 = validated */
189
190} lws_cose_validate_res_t;
191```
192
193It's like this because for multiple signatures, we may only have keys for some
194of them, and we may have different policies for validation that can only be
195assessed as a whole, eg, we may inisit that signatures pass with specific
196algorithms, or all signatures for specific keys must be present and pass. This
197way user code can assess the situation after the signature parsing and make its
198decision about overall validity according to its own policies.
199
200## Signing
201
202Signing is again done by creating a signing context using an info struct to pass
203in the paramter (a `lws_cose_sign_create_info_t`).
204
205```
206#define LCSC_FL_ADD_CBOR_TAG (1 << 0)
207#define LCSC_FL_ADD_CBOR_PREFER_MAC0 (1 << 1)
208
209typedef struct lws_cose_sign_create_info {
210 struct lws_context *cx;
211 /**< REQUIRED: the lws context */
212 lws_dll2_owner_t *keyset;
213 /**< REQUIRED: one or more cose_keys */
214
215 lws_lec_pctx_t *lec;
216 /**< REQUIRED: the cbor output context to emit to, user must
217 * initialize with lws_lec_init() beforehand */
218
219 lws_cose_sign_ext_pay_cb_t ext_cb;
220 /**< optional extra application data provision callback */
221 void *ext_opaque;
222 /**< optional extra application data provision callback opaque */
223 size_t ext_len;
224 /**< if we have extra app data, this must be set to the length of it */
225
226 size_t inline_payload_len;
227 /**< REQUIRED: size of the inline payload we will provide */
228
229 int flags;
230 /**< bitmap of LCSC_FL_* */
231 enum lws_cose_sig_types sigtype;
232 /**< 0, or sign type hint */
233} lws_cose_sign_create_info_t;
234```
235
236```
237struct lws_cose_sign_context *
238lws_cose_sign_create(const lws_cose_sign_create_info_t *info);
239```
240
241After creating the signing context, you call `lws_cose_sign_add()` one or more
242times to add algorithms and keys to sign with (since cose_sign allows multiple
243recipients with the same payload signed in different ways).
244
245```
246int
247lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
248 const lws_cose_key_t *ck);
249```
250
251The payload does not have to be provided all at once and can be passed in chunk
252by chunk over time via `lws_cose_sign_payload_chunk()`.
253
254Output is mediated via an lws CBOR output context provided in the info at
255creation-time, it's only emitted during the `lws_cose_sign_payload_chunk()`
256phase. If it returns `LWS_LECPCTX_RET_AGAIN`, you must call that api again
257after using the CBOR output context data and resetting its buffer by
258`lws_lec_setbuf()`, so it can continue to output.
259
260```
261enum lws_lec_pctx_ret
262lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
263 const uint8_t *in, size_t in_len);
264```
265
266Finally the signing context is destroyed.
267
268```
269void
270lws_cose_sign_destroy(struct lws_cose_sign_context **csc);
271```
272
273
README.cbor-lecp.md
1# RFC8949 CBOR Stream Parsing and Writing
2
3|||
4|---|---|---|
5|cmake| `LWS_WITH_CBOR`, `LWS_WITH_CBOR_FLOAT`|
6|Header| ./include/libwebsockets/lws-lecp.h|
7|api-test| ./minimal-examples/api-tests/api-test-lecp/|
8|test app| ./test-apps/test-lecp.c -> libwebsockets-test-lecp|
9
10LECP is the RFC8949 CBOR stream parsing counterpart to LEJP for JSON.
11
12## Features
13
14 - Completely immune to input fragmentation, give it any size blocks of CBOR as
15 they become available; 1 byte, or 100K at a time give identical parsing
16 results
17 - Input chunks discarded as they are parsed, whole CBOR never needed in memory
18 - Nonrecursive, fixed stack usage of a few dozen bytes
19 - No heap allocations at all, just requires ~500 byte context usually on
20 caller stack
21 - Creates callbacks to a user-provided handler as members are parsed out
22 - No payload size limit, supports huge / endless strings or blobs bigger than
23 system memory
24 - Collates utf-8 text and blob payloads into a 250-byte chunk buffer for ease
25 of access
26 - Write apis don't use any heap allocations or recursion either
27 - Write apis use an explicit context with its own lifecycle, and printf style
28 vaargs including sized blobs, C strings, double, int, unsigned long etc
29 - Completely immune to output fragmentation, supports huge strings and blobs
30 into small buffers, api returns to indicates unfinished if it needs to be
31 called again to continue; 1 byte or 100K output buffer give same results
32 - Write apis completely fill available buffer and if unfinished, continues
33 into same or different buffer when called again with same args; no
34 requirement for subsequent calls to be done sequentially or even from same
35 function
36
37## Type limits
38
39CBOR allows negative integers of up to 64 bits, these do not fit into a `uint64_t`.
40LECP has a union for numbers that includes the types `uint64_t` and `int64_t`,
41but it does not separately handle negative integers. Only -2^63.. 2^64 -1 can
42be handled by the C types, the oversize negative numbers wrap and should be
43avoided.
44
45## Floating point support
46
47Floats are handled using the IEEE memory format, it means they can be parsed
48from the CBOR without needing any floating point support in the build. If
49floating point is available, you can also enable `LWS_WITH_CBOR_FLOAT` and
50a `float` and `double` types are available in the number item union. Otherwise
51these are handled as `ctx->item.u.u32` and `ctx->item.u.u64` union members.
52
53Half-float (16-bit) is defined in CBOR and always handled as a `uint16_t`
54number union member `ctx->item.u.hf`.
55
56## Callback reasons
57
58The user callback does not have to handle any callbacks, it only needs to
59process the data for the ones it is interested in.
60
61|Callback reason|CBOR structure|Associated data|
62|---|---|---|
63|`LECPCB_CONSTRUCTED`|Created the parse context||
64|`LECPCB_DESTRUCTED`|Destroyed the parse context||
65|`LECPCB_COMPLETE`|The parsing completed OK||
66|`LECPCB_FAILED`|The parsing failed||
67|`LECPCB_VAL_TRUE`|boolean true||
68|`LECPCB_VAL_FALSE`|boolean false||
69|`LECPCB_VAL_NULL`|explicit NULL||
70|`LECPCB_VAL_NUM_INT`|signed integer|`ctx->item.u.i64`|
71|`LECPCB_VAL_STR_START`|A UTF-8 string is starting||
72|`LECPCB_VAL_STR_CHUNK`|The next string chunk|`ctx->npos` bytes in `ctx->buf`|
73|`LECPCB_VAL_STR_END`|The last string chunk|`ctx->npos` bytes in `ctx->buf`|
74|`LECPCB_ARRAY_START`|An array is starting||
75|`LECPCB_ARRAY_END`|An array has ended||
76|`LECPCB_OBJECT_START`|A CBOR map is starting||
77|`LECPCB_OBJECT_END`|A CBOR map has ended||
78|`LECPCB_TAG_START`|The following data has a tag index|`ctx->item.u.u64`|
79|`LECPCB_TAG_END`|The end of the data referenced by the last tag||
80|`LECPCB_VAL_NUM_UINT`|Unsigned integer|`ctx->item.u.u64`|
81|`LECPCB_VAL_UNDEFINED`|CBOR undefined||
82|`LECPCB_VAL_FLOAT16`|half-float available as host-endian `uint16_t`|`ctx->item.u.hf`|
83|`LECPCB_VAL_FLOAT32`|`float` (`uint32_t` if no float support) available|`ctx->item.u.f`|
84|`LECPCB_VAL_FLOAT64`|`double` (`uint64_t` if no float support) available|`ctx->item.u.d`|
85|`LECPCB_VAL_SIMPLE`|CBOR simple|`ctx->item.u.u64`|
86|`LECPCB_VAL_BLOB_START`|A binary blob is starting||
87|`LECPCB_VAL_BLOB_CHUNK`|The next blob chunk|`ctx->npos` bytes in `ctx->buf`|
88|`LECPCB_VAL_BLOB_END`|The last blob chunk|`ctx->npos` bytes in `ctx->buf`|
89|`LECPCB_ARRAY_ITEM_START`|A logical item in an array is starting|
90|`LCEPDB_ARRAY_ITEM_END`|A logical item in an array has completed|
91
92## CBOR indeterminite lengths
93
94Indeterminite lengths are supported, but are concealed in the parser as far as
95possible, the CBOR lengths or its indeterminacy are not exposed in the callback
96interface at all, just chunks of data that may be the start, the middle, or the
97end.
98
99## Handling CBOR UTF-8 strings and blobs
100
101When a string or blob is parsed, an advisory callback of `LECPCB_VAL_STR_START` or
102`LECPCB_VAL_BLOB_START` occurs first. The `_STR_` callbacks indicate the
103content is a CBOR UTF-8 string, `_BLOB_` indicates it is binary data.
104
105Strings or blobs may have indeterminite length, but if so, they are composed
106of logical chunks which must have known lengths. When the `_START` callback
107occurs, the logical length either of the whole string, or of the sub-chunk if
108indeterminite length, can be found in `ctx->item.u.u64`.
109
110Payload is collated into `ctx->buf[]`, the valid length is in `ctx->npos`.
111
112For short strings or blobs where the length is known, the whole payload is
113delivered in a single `LECPCB_VAL_STR_END` or `LECPCB_VAL_BLOB_END` callback.
114
115For payloads larger than the size of `ctx->buf[]`, `LECPCB_VAL_STR_CHUNK` or
116`LECPCB_VAL_BLOB_CHUNK` callbacks occur delivering each sequential bufferload.
117If the CBOR indicates the total length, the last chunk is delievered in a
118`LECPCB_VAL_STR_END` or `LECPCB_VAL_BLOB_END`.
119
120If the CBOR indicates the string end after the chunk, a zero-length `..._END`
121callback is provided.
122
123## Handling CBOR tags
124
125CBOR tags are exposed as `LECPCB_TAG_START` and `LECPCB_TAG_END` pairs, at
126the `_START` callback the tag index is available in `ctx->item.u.u64`.
127
128## CBOR maps
129
130You can check if you are on the "key" part of a map "key:value" pair using the
131helper api `lecp_parse_map_is_key(ctx)`.
132
133## Parsing paths
134
135LECP maintains a "parsing path" in `ctx->path` that represents the context of
136the callback events. As a convenience, at LECP context creation time, you can
137pass in an array of path strings you want to match on, and have any match
138checkable in the callback using `ctx->path_match`, it's 0 if no active match,
139or the match index from your path array starting from 1 for the first entry.
140
141|CBOR element|Representation in path|
142|---|---|
143|CBOR Array|`[]`|
144|CBOR Map|`.`|
145|CBOR Map entry key string|`keystring`|
146
147## Accessing raw CBOR subtrees
148
149Some CBOR usages like COSE require access to selected raw CBOR from the input
150stream. `lecp_parse_report_raw(ctx, on)` lets you turn on and off buffering of
151raw CBOR and reporting it in the parse callback with `LECPCB_LITERAL_CBOR`
152callbacks. The callbacks mean the temp buffer `ctx->cbor[]` has `ctx->cbor_pos`
153bytes of raw CBOR available in it. Callbacks are triggered when the buffer
154fills, or reporting is turned off and the buffer has something in it.
155
156By turning the reporting on and off according to the outer CBOR parsing state,
157it's possible to get exactly the raw CBOR subtree that's needed.
158
159Capturing and reporting the raw CBOR does not change that the same CBOR is being
160passed to the parser as usual as well.
161
162## Comparison with LEJP (JSON parser)
163
164LECP is based on the same principles as LEJP and shares most of the callbacks.
165The major differences:
166
167 - LEJP value callbacks all appear in `ctx->buf[]`, ie, floating-point is
168 provided to the callback in ascii form like `"1.0"`. CBOR provides a more
169 strict typing system, and the different type values are provided either in
170 `ctx->buf[]` for blobs or utf-8 text strtings, or the `item.u` union for
171 converted types, with additional callback reasons specific to each type.
172
173 - CBOR "maps" use `_OBJECT_START` and `_END` parsing callbacks around the
174 key / value pairs. LEJP has a special callback type `PAIR_NAME` for the
175 key string / integer, but in LECP these are provided as generic callbacks
176 dependent on type, ie, generic string callbacks or integer ones, and the
177 value part is represented according to whatever comes.
178
179
180# Writing CBOR
181
182CBOR is written into a `lws_lec_pctx_t` object that has been initialized to
183point to an output buffer of a specified size, using printf type formatting.
184
185Output is paused if the buffer fills, and the write api may be called again
186later with the same context object, to resume emitting to the same or different
187buffer.
188
189This allows bufferloads of encoded CBOR to be produced on demand, it's designed
190to fit usage in WRITEABLE callbacks and Secure Streams tx() callbacks where the
191buffer size for one packet is already fixed.
192
193CBOR array and map lengths are deduced from the format string, as is whether to
194use indeterminite length formatting or not. For indeterminite text or binary
195strings, a container of < >
196
197|Format|Arg(s)|Meaning|
198|---|---|---|
199|`123`||unsigned literal number|
200|`-123`||signed literal number|
201|`%u`|`unsigned int`|number|
202|`%lu`|`unsigned long int`|number|
203|`%llu`|`unsigned long long int`|number|
204|`%d`|`signed int`|number|
205|`%ld`|`signed long int`|number|
206|`%lld`|`signed long long int`|number|
207|`%f`|`double`|floating point number|
208|`123(...)`||literal tag and scope|
209|`%t(...)`|`unsigned int`|tag and scope|
210|`%lt(...)`|`unsigned long int`|tag and scope|
211|`%llt(...)`|`unsigned long long int`|tag and scope|
212|`[...]`||Array (fixed len if `]` in same format string)|
213|`{...}`||Map (fixed len if `}` in same format string)|
214|`<t...>`||Container for indeterminite text string frags|
215|`<b...>`||Container for indeterminite binary string frags|
216|`'string'`||Literal text of known length|
217|`%s`|`const char *`|NUL-terminated string|
218|`%.*s`|`int`, `const char *`|length-specified string|
219|`%.*b`|`int`, `const uint8_t *`|length-specified binary|
220|`:`||separator between Map items (a:b)|
221|`,`||separator between Map pairs or array items|
222
223Backslash is used as an escape in `'...'` literal strings, so `'\\'` represents
224a string consisting of a single backslash, and `'\''` a string consisting of a
225single single-quote.
226
227For integers, various natural C types are available, but in all cases, the
228number is represented in CBOR using the smallest valid way based on its value,
229the long or long-long modifiers just apply to the expected C type in the args.
230
231For floats, the C argument is always expected to be a `double` type following
232C type promotion, but again it is represented in CBOR using the smallest valid
233way based on value, half-floats are used for NaN / Infinity and where possible
234for values like 0.0 and -1.0.
235
236## Examples
237
238### Literal ints
239
240```
241 uint8_t buf[128];
242 lws_lec_pctx_t cbw;
243
244 lws_lec_init(&cbw, buf, sizeof(buf));
245 lws_lec_printf(ctx, "-1");
246```
247|||
248|---|---|
249|Return| `LWS_LECPCTX_RET_FINISHED`|
250|`ctx->used`|1|
251|`buf[]`|20|
252
253### Dynamic ints
254
255```
256 uint8_t buf[128];
257 lws_lec_pctx_t cbw;
258 int n = -1; /* could be long */
259
260 lws_lec_init(&cbw, buf, sizeof(buf));
261 lws_lec_printf(ctx, "%d", n); /* use %ld for long */
262```
263|||
264|---|---|
265|Return| `LWS_LECPCTX_RET_FINISHED`|
266|`ctx->used`|1|
267|`buf[]`|20|
268
269### Maps, arrays and dynamic ints
270
271```
272 ...
273 int args[3] = { 1, 2, 3 };
274
275 lws_lec_printf(ctx, "{'a':%d,'b':[%d,%d]}", args[0], args[1], args[2]);
276```
277
278|||
279|---|---|
280|Return| `LWS_LECPCTX_RET_FINISHED`|
281|`ctx->used`|9|
282|`buf[]`|A2 61 61 01 61 62 82 02 03|
283
284### String longer than the buffer
285
286Using `%s` and the same string as an arg gives same results
287
288```
289 uint8_t buf[16];
290 lws_lec_pctx_t cbw;
291
292 lws_lec_init(&cbw, buf, sizeof(buf));
293 lws_lec_printf(ctx, "'A literal string > one buf'");
294 /* not required to be in same function context or same buf,
295 * but the string must remain the same */
296 lws_lec_setbuf(&cbw, buf, sizeof(buf));
297 lws_lec_printf(ctx, "'A literal string > one buf'");
298```
299
300First call
301
302|||
303|---|---|
304|Return| `LWS_LECPCTX_RET_AGAIN`|
305|`ctx->used`|16|
306|`buf[]`|78 1A 41 20 6C 69 74 65 72 61 6C 20 73 74 72 69|
307
308Second call
309
310|||
311|---|---|
312|Return| `LWS_LECPCTX_RET_FINISHED`|
313|`ctx->used`|12|
314|`buf[]`|6E 67 20 3E 20 6F 6E 65 20 62 75 66|
315
316### Binary blob longer than the buffer
317
318```
319 uint8_t buf[16], blob[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
320 lws_lec_pctx_t cbw;
321
322 lws_lec_init(&cbw, buf, sizeof(buf));
323 lws_lec_printf(ctx, "%.*b", (int)sizeof(blob), blob);
324 /* not required to be in same function context or same buf,
325 * but the length and blob must remain the same */
326 lws_lec_setbuf(&cbw, buf, sizeof(buf));
327 lws_lec_printf(ctx, "%.*b", (int)sizeof(blob), blob);
328```
329
330First call
331
332|||
333|---|---|
334|Return| `LWS_LECPCTX_RET_AGAIN`|
335|`ctx->used`|16|
336|`buf[]`|52 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F|
337
338Second call
339
340|||
341|---|---|
342|Return| `LWS_LECPCTX_RET_FINISHED`|
343|`ctx->used`|3|
344|`buf[]`|10 11 12|
345
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.cmake.md
1# Tips about CMake
2
3## Don't be afraid to nuke your build dir
4
5CMake likes to cache options and other things in the build dir... if you stop
6asserting the state of something like `-DMY_OPTION=1`, then the last way it was
7set it cached. On order to keep track of what you have set and not set, it's
8very advisable to explicitly keep all your options and set them all on one cmake
9line.
10
11Then, when you meet a situation you changed something but somehow cmake is
12sticking with what it knew before, you can fearlessly delete your build dir
13and create a new one with your explicit config.
14
15On Linux, it's usually enough to delete `CMakeCache.txt` to trigger it to config
16from the start again, but on, eg, windows, it isn't, for whatever reason it
17literally needs the build dir removing.
18
19## CMake presence tests that fail
20
21Lws makes use of various CMake features to figure out what apis your libraries
22offer, eg, OpenSSL has many different apis based on version, lws knows how to
23work around most of the changes, but to do it it must find out what apis are
24available first on your build environment.
25
26CMake basically builds little throwaway test programs using each api in turn, and
27if it builds, it understands that the api was available and sets a preprocessor
28symbol that's available in the main build accordingly. Then we can do `#if xxx`
29to figure out if we can use `xxx` or need to do a workaround at build-time.
30
31This works very well, but unfortunately if the program didn't build, there are
32many possible ways for the build to break even if the api being tested is
33really available... for example, some library in your toolchain isn't being
34linked for the throwaway test program.
35
36When this happens, cmake indicates that apis that must be available are not available...
37CMake keeps a log of what happened with the failed test programs in
38`./build/CMakeFiles/CMakeError.log`. This is appeneded to, so the best way is blow
39away the build dir and reconfig a new one from scratch, and go look in there to
40find out what the compiler or linker was complaining about.
41
42
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
186The only lws api that's safe to call from other thread contexts is `lws_cancel_service()`.
187This will take a platform-specific action to wake the lws event loop thread wait,
188either put a byte into a pipe2() the event loop is waiting on, or send a packet on
189a UDP socket pair that the event loop waits on. When the wake is handled by the
190lws event loop thread, it will broadcast a `LWS_CALLBACK_EVENT_WAIT_CANCELLED`
191message to every vhost-protocol instantiation, so you can handle this callback,
192usually lock a shared data region, and if you see you need to write, call
193`lws_callback_on_writeable()` for the wsi(s) that need to write.
194
195There's no restriction on multiple threads calling `lws_cancel_service()`, it's
196unconditionally safe due to how it is implemented underneath.
197
1985) The obverse of this truism about the receiver being the boss is the case where
199we are receiving. If we get into a situation we actually can't usefully
200receive any more, perhaps because we are passing the data on and the guy we want
201to send to can't receive any more, then we should "turn off RX" by using the
202RX flow control API, `lws_rx_flow_control(wsi, 0)`. When something happens where we
203can accept more RX, (eg, we learn our onward connection is writeable) we can call
204it again to re-enable it on the incoming wsi.
205
206LWS stops calling back about RX immediately you use flow control to disable RX, it
207buffers the data internally if necessary. So you will only see RX when you can
208handle it. When flow control is disabled, LWS stops taking new data in... this makes
209the situation known to the sender by TCP "backpressure", the tx window fills and the
210sender finds he cannot write any more to the connection.
211
212See the mirror protocol implementations for example code.
213
214If you need to service other socket or file descriptors as well as the
215websocket ones, you can combine them together with the websocket ones
216in one poll loop, see "External Polling Loop support" below, and
217still do it all in one thread / process context. If the need is less
218architectural, you can also create RAW mode client and serving sockets; this
219is how the lws plugin for the ssh server works.
220
221@section anonprot Working without a protocol name
222
223Websockets allows connections to negotiate without a protocol name...
224in that case by default it will bind to the first protocol in your
225vhost protocols[] array.
226
227You can tell the vhost to use a different protocol by attaching a
228pvo (per-vhost option) to the
229
230```
231/*
232 * this sets a per-vhost, per-protocol option name:value pair
233 * the effect is to set this protocol to be the default one for the vhost,
234 * ie, selected if no Protocol: header is sent with the ws upgrade.
235 */
236
237static const struct lws_protocol_vhost_options pvo_opt = {
238 NULL,
239 NULL,
240 "default",
241 "1"
242};
243
244static const struct lws_protocol_vhost_options pvo = {
245 NULL,
246 &pvo_opt,
247 "my-protocol",
248 ""
249};
250
251...
252
253 context_info.pvo = &pvo;
254...
255
256```
257
258Will select "my-protocol" from your protocol list (even if it came
259in by plugin) as being the target of client connections that don't
260specify a protocol.
261
262@section closing Closing connections from the user side
263
264When you want to close a connection, you do it by returning `-1` from a
265callback for that connection.
266
267You can provoke a callback by calling `lws_callback_on_writable` on
268the wsi, then notice in the callback you want to close it and just return -1.
269But usually, the decision to close is made in a callback already and returning
270-1 is simple.
271
272If the socket knows the connection is dead, because the peer closed or there
273was an affirmitive network error like a FIN coming, then **libwebsockets** will
274take care of closing the connection automatically.
275
276If you have a silently dead connection, it's possible to enter a state where
277the send pipe on the connection is choked but no ack will ever come, so the
278dead connection will never become writeable. To cover that, you can use TCP
279keepalives (see later in this document) or pings.
280
281@section gzip Serving from inside a zip file
282
283Lws now supports serving gzipped files from inside a zip container. Thanks to
284Per Bothner for contributing the code.
285
286This has the advtantage that if the client can accept GZIP encoding, lws can
287simply send the gzip-compressed file from inside the zip file with no further
288processing, saving time and bandwidth.
289
290In the case the client can't understand gzip compression, lws automatically
291decompressed the file and sends it normally.
292
293Clients with limited storage and RAM will find this useful; the memory needed
294for the inflate case is constrained so that only one input buffer at a time
295is ever in memory.
296
297To use this feature, ensure LWS_WITH_ZIP_FOPS is enabled at CMake.
298
299`libwebsockets-test-server-v2.0` includes a mount using this technology
300already, run that test server and navigate to http://localhost:7681/ziptest/candide.html
301
302This will serve the book Candide in html, together with two jpgs, all from
303inside a .zip file in /usr/[local/]share-libwebsockets-test-server/candide.zip
304
305Usage is otherwise automatic, if you arrange a mount that points to the zipfile,
306eg, "/ziptest" -> "mypath/test.zip", then URLs like `/ziptest/index.html` will be
307servied from `index.html` inside `mypath/test.zip`
308
309@section frags Fragmented messages
310
311To support fragmented messages you need to check for the final
312frame of a message with `lws_is_final_fragment`. This
313check can be combined with `libwebsockets_remaining_packet_payload`
314to gather the whole contents of a message, eg:
315
316```
317 case LWS_CALLBACK_RECEIVE:
318 {
319 Client * const client = (Client *)user;
320 const size_t remaining = lws_remaining_packet_payload(wsi);
321
322 if (!remaining && lws_is_final_fragment(wsi)) {
323 if (client->HasFragments()) {
324 client->AppendMessageFragment(in, len, 0);
325 in = (void *)client->GetMessage();
326 len = client->GetMessageLength();
327 }
328
329 client->ProcessMessage((char *)in, len, wsi);
330 client->ResetMessage();
331 } else
332 client->AppendMessageFragment(in, len, remaining);
333 }
334 break;
335```
336
337The test app libwebsockets-test-fraggle sources also show how to
338deal with fragmented messages.
339
340
341@section debuglog Debug Logging
342
343See ./READMEs/README.logging.md
344
345@section asan Building with ASAN
346
347Under GCC you can select for the build to be instrumented with the Address
348Sanitizer, 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
349standard and depend on platform behaviours.
350
351Run your application like this
352
353```
354 $ sudo ASAN_OPTIONS=verbosity=2:halt_on_error=1 /usr/local/bin/lwsws
355```
356
357and attach gdb to catch the place it halts.
358
359@section extpoll External Polling Loop support
360
361**libwebsockets** maintains an internal `poll()` array for all of its
362sockets, but you can instead integrate the sockets into an
363external polling array. That's needed if **libwebsockets** will
364cooperate with an existing poll array maintained by another
365server.
366
367Three callbacks `LWS_CALLBACK_ADD_POLL_FD`, `LWS_CALLBACK_DEL_POLL_FD`
368and `LWS_CALLBACK_CHANGE_MODE_POLL_FD` appear in the callback for protocol 0
369and allow interface code to manage socket descriptors in other poll loops.
370
371You can pass all pollfds that need service to `lws_service_fd()`, even
372if the socket or file does not belong to **libwebsockets** it is safe.
373
374If **libwebsocket** handled it, it zeros the pollfd `revents` field before returning.
375So you can let **libwebsockets** try and if `pollfd->revents` is nonzero on return,
376you know it needs handling by your code.
377
378Also note that when integrating a foreign event loop like libev or libuv where
379it doesn't natively use poll() semantics, and you must return a fake pollfd
380reflecting the real event:
381
382 - be sure you set .events to .revents value as well in the synthesized pollfd
383
384 - check the built-in support for the event loop if possible (eg, ./lib/libuv.c)
385 to see how it interfaces to lws
386
387 - use LWS_POLLHUP / LWS_POLLIN / LWS_POLLOUT from libwebsockets.h to avoid
388 losing windows compatibility
389
390You also need to take care about "forced service" somehow... these are cases
391where the network event was consumed, incoming data was all read, for example,
392but the work arising from it was not completed. There will not be any more
393network event to trigger the remaining work, Eg, we read compressed data, but
394we did not use up all the decompressed data before returning to the event loop
395because we had to write some of it.
396
397Lws provides an API to determine if anyone is waiting for forced service,
398`lws_service_adjust_timeout(context, 1, tsi)`, normally tsi is 0. If it returns
3990, then at least one connection has pending work you can get done by calling
400`lws_service_tsi(context, -1, tsi)`, again normally tsi is 0.
401
402For eg, the default poll() event loop, or libuv/ev/event, lws does this
403checking for you and handles it automatically. But in the external polling
404loop case, you must do it explicitly. Handling it after every normal service
405triggered by the external poll fd should be enough, since the situations needing
406it are initially triggered by actual network events.
407
408An example of handling it is shown in the test-server code specific to
409external polling.
410
411@section cpp Using with in c++ apps
412
413The library is ready for use by C++ apps. You can get started quickly by
414copying the test server
415
416```
417 $ cp test-apps/test-server.c test.cpp
418```
419
420and building it in C++ like this
421
422```
423 $ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets
424```
425
426`INSTALL_DATADIR` is only needed because the test server uses it as shipped, if
427you remove the references to it in your app you don't need to define it on
428the g++ line either.
429
430
431@section headerinfo Availability of header information
432
433HTTP Header information is managed by a pool of "ah" structs. These are a
434limited resource so there is pressure to free the headers and return the ah to
435the pool for reuse.
436
437For that reason header information on HTTP connections that get upgraded to
438websockets is lost after the ESTABLISHED callback. Anything important that
439isn't processed by user code before then should be copied out for later.
440
441For HTTP connections that don't upgrade, header info remains available the
442whole time.
443
444@section http2compat Code Requirements for HTTP/2 compatibility
445
446Websocket connections only work over http/1, so there is nothing special to do
447when you want to enable -DLWS_WITH_HTTP2=1.
448
449The internal http apis already follow these requirements and are compatible with
450http/2 already. So if you use stuff like mounts and serve stuff out of the
451filesystem, there's also nothing special to do.
452
453However if you are getting your hands dirty with writing response headers, or
454writing bulk data over http/2, you need to observe these rules so that it will
455work over both http/1.x and http/2 the same.
456
4571) LWS_PRE requirement applies on ALL lws_write(). For http/1, you don't have
458to take care of LWS_PRE for http data, since it is just sent straight out.
459For http/2, it will write up to LWS_PRE bytes behind the buffer start to create
460the http/2 frame header.
461
462This has implications if you treated the input buffer to lws_write() as const...
463it isn't any more with http/2, up to 9 bytes behind the buffer will be trashed.
464
4652) Headers are encoded using a sophisticated scheme in http/2. The existing
466header access apis are already made compatible for incoming headers,
467for outgoing headers you must:
468
469 - observe the LWS_PRE buffer requirement mentioned above
470
471 - Use `lws_add_http_header_status()` to add the transaction status (200 etc)
472
473 - use lws apis `lws_add_http_header_by_name()` and `lws_add_http_header_by_token()`
474 to put the headers into the buffer (these will translate what is actually
475 written to the buffer depending on if the connection is in http/2 mode or not)
476
477 - use the `lws api lws_finalize_http_header()` api after adding the last
478 response header
479
480 - write the header using lws_write(..., `LWS_WRITE_HTTP_HEADERS`);
481
482 3) http/2 introduces per-stream transmit credit... how much more you can send
483 on a stream is decided by the peer. You start off with some amount, as the
484 stream sends stuff lws will reduce your credit accordingly, when it reaches
485 zero, you must not send anything further until lws receives "more credit" for
486 that stream the peer. Lws will suppress writable callbacks if you hit 0 until
487 more credit for the stream appears, and lws built-in file serving (via mounts
488 etc) already takes care of observing the tx credit restrictions. However if
489 you write your own code that wants to send http data, you must consult the
490 `lws_get_peer_write_allowance()` api to find out the state of your tx credit.
491 For http/1, it will always return (size_t)-1, ie, no limit.
492
493 This is orthogonal to the question of how much space your local side's kernel
494 will make to buffer your send data on that connection. So although the result
495 from `lws_get_peer_write_allowance()` is "how much you can send" logically,
496 and may be megabytes if the peer allows it, you should restrict what you send
497 at one time to whatever your machine will generally accept in one go, and
498 further reduce that amount if `lws_get_peer_write_allowance()` returns
499 something smaller. If it returns 0, you should not consume or send anything
500 and return having asked for callback on writable, it will only come back when
501 more tx credit has arrived for your stream.
502
503 4) Header names with captital letters are illegal in http/2. Header names in
504 http/1 are case insensitive. So if you generate headers by name, change all
505 your header name strings to lower-case to be compatible both ways.
506
507 5) Chunked Transfer-encoding is illegal in http/2, http/2 peers will actively
508 reject it. Lws takes care of removing the header and converting CGIs that
509 emit chunked into unchunked automatically for http/2 connections.
510
511If you follow these rules, your code will automatically work with both http/1.x
512and http/2.
513
514@section ka TCP Keepalive
515
516It is possible for a connection which is not being used to send to die
517silently somewhere between the peer and the side not sending. In this case
518by default TCP will just not report anything and you will never get any more
519incoming data or sign the link is dead until you try to send.
520
521To deal with getting a notification of that situation, you can choose to
522enable TCP keepalives on all **libwebsockets** sockets, when you create the
523context.
524
525To enable keepalive, set the ka_time member of the context creation parameter
526struct to a nonzero value (in seconds) at context creation time. You should
527also fill ka_probes and ka_interval in that case.
528
529With keepalive enabled, the TCP layer will send control packets that should
530stimulate a response from the peer without affecting link traffic. If the
531response is not coming, the socket will announce an error at `poll()` forcing
532a close.
533
534Note that BSDs don't support keepalive time / probes / interval per-socket
535like Linux does. On those systems you can enable keepalive by a nonzero
536value in `ka_time`, but the systemwide kernel settings for the time / probes/
537interval are used, regardless of what nonzero value is in `ka_time`.
538
539
540@section sslopt Optimizing SSL connections
541
542There's a member `ssl_cipher_list` in the `lws_context_creation_info` struct
543which allows the user code to restrict the possible cipher selection at
544context-creation time.
545
546You might want to look into that to stop the ssl peers selecting a cipher which
547is too computationally expensive. To use it, point it to a string like
548
549 `"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"`
550
551if left `NULL`, then the "DEFAULT" set of ciphers are all possible to select.
552
553You can also set it to `"ALL"` to allow everything (including insecure ciphers).
554
555
556@section sslcerts Passing your own cert information direct to SSL_CTX
557
558For most users it's enough to pass the SSL certificate and key information by
559giving filepaths to the info.ssl_cert_filepath and info.ssl_private_key_filepath
560members when creating the vhost.
561
562If you want to control that from your own code instead, you can do so by leaving
563the related info members NULL, and setting the info.options flag
564LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX at vhost creation time. That will create
565the vhost SSL_CTX without any certificate, and allow you to use the callback
566LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS to add your certificate to
567the SSL_CTX directly. The vhost SSL_CTX * is in the user parameter in that
568callback.
569
570@section clientasync Async nature of client connections
571
572When you call `lws_client_connect_info(..)` and get a `wsi` back, it does not
573mean your connection is active. It just means it started trying to connect.
574
575Your client connection is actually active only when you receive
576`LWS_CALLBACK_CLIENT_ESTABLISHED` for it.
577
578There's a 5 second timeout for the connection, and it may give up or die for
579other reasons, if any of that happens you'll get a
580`LWS_CALLBACK_CLIENT_CONNECTION_ERROR` callback on protocol 0 instead for the
581`wsi`.
582
583After attempting the connection and getting back a non-`NULL` `wsi` you should
584loop calling `lws_service()` until one of the above callbacks occurs.
585
586As usual, see [test-client.c](../test-apps/test-client.c) for example code.
587
588Notice that the client connection api tries to progress the connection
589somewhat before returning. That means it's possible to get callbacks like
590CONNECTION_ERROR on the new connection before your user code had a chance to
591get the wsi returned to identify it (in fact if the connection did fail early,
592NULL will be returned instead of the wsi anyway).
593
594To avoid that problem, you can fill in `pwsi` in the client connection info
595struct to point to a struct lws that get filled in early by the client
596connection api with the related wsi. You can then check for that in the
597callback to confirm the identity of the failing client connection.
598
599
600@section fileapi Lws platform-independent file access apis
601
602lws now exposes his internal platform file abstraction in a way that can be
603both used by user code to make it platform-agnostic, and be overridden or
604subclassed by user code. This allows things like handling the URI "directory
605space" as a virtual filesystem that may or may not be backed by a regular
606filesystem. One example use is serving files from inside large compressed
607archive storage without having to unpack anything except the file being
608requested.
609
610The test server shows how to use it, basically the platform-specific part of
611lws prepares a file operations structure that lives in the lws context.
612
613The user code can get a pointer to the file operations struct
614
615```
616 LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
617 `lws_get_fops`(struct lws_context *context);
618```
619
620and then can use helpers to also leverage these platform-independent
621file handling apis
622
623```
624 lws_fop_fd_t
625 `lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename,
626 lws_fop_flags_t *flags)
627 int
628 `lws_plat_file_close`(lws_fop_fd_t fop_fd)
629
630 unsigned long
631 `lws_plat_file_seek_cur`(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
632
633 int
634 `lws_plat_file_read`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
635 uint8_t *buf, lws_filepos_t len)
636
637 int
638 `lws_plat_file_write`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
639 uint8_t *buf, lws_filepos_t len )
640```
641
642Generic helpers are provided which provide access to generic fops information or
643call through to the above fops
644
645```
646lws_filepos_t
647lws_vfs_tell(lws_fop_fd_t fop_fd);
648
649lws_filepos_t
650lws_vfs_get_length(lws_fop_fd_t fop_fd);
651
652uint32_t
653lws_vfs_get_mod_time(lws_fop_fd_t fop_fd);
654
655lws_fileofs_t
656lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
657
658lws_fileofs_t
659lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
660```
661
662
663The user code can also override or subclass the file operations, to either
664wrap or replace them. An example is shown in test server.
665
666### Changes from v2.1 and before fops
667
668There are several changes:
669
6701) 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.
671
6722) 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.
673
6743) Everything is wrapped in typedefs. See lws-plat-unix.c for examples of how to implement.
675
6764) Position in the file, File Length, and a copy of Flags left after open are now generically held in the fop_fd.
677VFS implementation must set and manage this generic information now. See the implementations in lws-plat-unix.c for
678examples.
679
6805) The file length is no longer set at a pointer provided by the open() fop. The api `lws_vfs_get_length()` is provided to
681get the file length after open.
682
6836) If your file namespace is virtual, ie, is not reachable by platform fops directly, you must set LWS_FOP_FLAG_VIRTUAL
684on the flags during open.
685
6867) There is an optional `mod_time` uint32_t member in the generic fop_fd. If you are able to set it during open, you
687should indicate it by setting `LWS_FOP_FLAG_MOD_TIME_VALID` on the flags.
688
689@section rawfd RAW file descriptor polling
690
691LWS allows you to include generic platform file descriptors in the lws service / poll / event loop.
692
693Open your fd normally and then
694
695```
696 lws_sock_file_fd_type u;
697
698 u.filefd = your_open_file_fd;
699
700 if (!lws_adopt_descriptor_vhost(vhost, 0, u,
701 "protocol-name-to-bind-to",
702 optional_wsi_parent_or_NULL)) {
703 // failed
704 }
705
706 // OK
707```
708
709A wsi is created for the file fd that acts like other wsi, you will get these
710callbacks on the named protocol
711
712```
713 LWS_CALLBACK_RAW_ADOPT_FILE
714 LWS_CALLBACK_RAW_RX_FILE
715 LWS_CALLBACK_RAW_WRITEABLE_FILE
716 LWS_CALLBACK_RAW_CLOSE_FILE
717```
718
719starting with LWS_CALLBACK_RAW_ADOPT_FILE.
720
721The minimal example `raw/minimal-raw-file` demonstrates how to use it.
722
723`protocol-lws-raw-test` plugin also provides a method for testing this with
724`libwebsockets-test-server-v2.0`:
725
726The plugin creates a FIFO on your system called "/tmp/lws-test-raw"
727
728You can feed it data through the FIFO like this
729
730```
731 $ sudo sh -c "echo hello > /tmp/lws-test-raw"
732```
733
734This plugin simply prints the data. But it does it through the lws event
735loop / service poll.
736
737@section rawsrvsocket RAW server socket descriptor polling
738
739You can also enable your vhost to accept RAW socket connections, in addition to
740HTTP[s] and WS[s]. If the first bytes written on the connection are not a
741valid HTTP method, then the connection switches to RAW mode.
742
743This is disabled by default, you enable it by setting the `.options` flag
744LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG, and setting
745`.listen_accept_role` to `"raw-skt"` when creating the vhost.
746
747RAW mode socket connections receive the following callbacks
748
749```
750 LWS_CALLBACK_RAW_ADOPT
751 LWS_CALLBACK_RAW_RX
752 LWS_CALLBACK_RAW_WRITEABLE
753 LWS_CALLBACK_RAW_CLOSE
754```
755
756You can control which protocol on your vhost handles these RAW mode
757incoming connections by setting the vhost info struct's `.listen_accept_protocol`
758to the vhost protocol name to use.
759
760`protocol-lws-raw-test` plugin provides a method for testing this with
761`libwebsockets-test-server-v2.0`:
762
763Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg
764
765```
766 $ telnet 127.0.0.1 7681
767```
768
769type something that isn't a valid HTTP method and enter, before the
770connection times out. The connection will switch to RAW mode using this
771protocol, and pass the unused rx as a raw RX callback.
772
773The test protocol echos back what was typed on telnet to telnet.
774
775@section rawclientsocket RAW client socket descriptor polling
776
777You can now also open RAW socket connections in client mode.
778
779Follow the usual method for creating a client connection, but set the
780`info.method` to "RAW". When the connection is made, the wsi will be
781converted to RAW mode and operate using the same callbacks as the
782server RAW sockets described above.
783
784The libwebsockets-test-client supports this using raw:// URLS. To
785test, open a netcat listener in one window
786
787```
788 $ nc -l 9999
789```
790
791and in another window, connect to it using the test client
792
793```
794 $ libwebsockets-test-client raw://127.0.0.1:9999
795```
796
797The connection should succeed, and text typed in the netcat window (including a CRLF)
798will be received in the client.
799
800@section rawudp RAW UDP socket integration
801
802Lws provides an api to create, optionally bind, and adopt a RAW UDP
803socket (RAW here means an uninterpreted normal UDP socket, not a
804"raw socket").
805
806```
807LWS_VISIBLE LWS_EXTERN struct lws *
808lws_create_adopt_udp(struct lws_vhost *vhost, int port, int flags,
809 const char *protocol_name, struct lws *parent_wsi);
810```
811
812`flags` should be `LWS_CAUDP_BIND` if the socket will receive packets.
813
814The callbacks `LWS_CALLBACK_RAW_ADOPT`, `LWS_CALLBACK_RAW_CLOSE`,
815`LWS_CALLBACK_RAW_RX` and `LWS_CALLBACK_RAW_WRITEABLE` apply to the
816wsi. But UDP is different than TCP in some fundamental ways.
817
818For receiving on a UDP connection, data becomes available at
819`LWS_CALLBACK_RAW_RX` as usual, but because there is no specific
820connection with UDP, it is necessary to also get the source address of
821the data separately, using `struct lws_udp * lws_get_udp(wsi)`.
822You should take a copy of the `struct lws_udp` itself (not the
823pointer) and save it for when you want to write back to that peer.
824
825Writing is also a bit different for UDP. By default, the system has no
826idea about the receiver state and so asking for a `callback_on_writable()`
827always believes that the socket is writeable... the callback will
828happen next time around the event loop.
829
830With UDP, there is no single "connection". You need to write with sendto() and
831direct the packets to a specific destination. To return packets to a
832peer who sent something earlier and you copied his `struct lws_udp`, you
833use the .sa and .salen members as the last two parameters of the sendto().
834
835The kernel may not accept to buffer / write everything you wanted to send.
836So you are responsible to watch the result of sendto() and resend the
837unsent part next time (which may involve adding new protocol headers to
838the remainder depending on what you are doing).
839
840@section ecdh ECDH Support
841
842ECDH Certs are now supported. Enable the CMake option
843
844 cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1
845
846**and** the info->options flag
847
848 LWS_SERVER_OPTION_SSL_ECDH
849
850to build in support and select it at runtime.
851
852@section sslinfo SSL info callbacks
853
854OpenSSL allows you to receive callbacks for various events defined in a
855bitmask in openssl/ssl.h. The events include stuff like TLS Alerts.
856
857By default, lws doesn't register for these callbacks.
858
859However if you set the info.ssl_info_event_mask to nonzero (ie, set some
860of the bits in it like `SSL_CB_ALERT` at vhost creation time, then
861connections to that vhost will call back using LWS_CALLBACK_SSL_INFO
862for the wsi, and the `in` parameter will be pointing to a struct of
863related args:
864
865```
866struct lws_ssl_info {
867 int where;
868 int ret;
869};
870```
871
872The default callback handler in lws has a handler for LWS_CALLBACK_SSL_INFO
873which prints the related information, You can test it using the switch
874-S -s on `libwebsockets-test-server-v2.0`.
875
876Returning nonzero from the callback will close the wsi.
877
878@section smp SMP / Multithreaded service
879
880SMP support is integrated into LWS without any internal threading. It's
881very simple to use, libwebsockets-test-server-pthread shows how to do it,
882use -j n argument there to control the number of service threads up to 32.
883
884Two new members are added to the info struct
885
886 unsigned int count_threads;
887 unsigned int fd_limit_per_thread;
888
889leave them at the default 0 to get the normal singlethreaded service loop.
890
891Set count_threads to n to tell lws you will have n simultaneous service threads
892operating on the context.
893
894There is still a single listen socket on one port, no matter how many
895service threads.
896
897When a connection is made, it is accepted by the service thread with the least
898connections active to perform load balancing.
899
900The user code is responsible for spawning n threads running the service loop
901associated to a specific tsi (Thread Service Index, 0 .. n - 1). See
902the libwebsockets-test-server-pthread for how to do.
903
904If you leave fd_limit_per_thread at 0, then the process limit of fds is shared
905between the service threads; if you process was allowed 1024 fds overall then
906each thread is limited to 1024 / n.
907
908You can set fd_limit_per_thread to a nonzero number to control this manually, eg
909the overall supported fd limit is less than the process allowance.
910
911You can control the context basic data allocation for multithreading from Cmake
912using -DLWS_MAX_SMP=, if not given it's set to 1. The serv_buf allocation
913for the threads (currently 4096) is made at runtime only for active threads.
914
915Because lws will limit the requested number of actual threads supported
916according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to
917discover how many threads were actually allowed when the context was created.
918
919See the test-server-pthreads.c sample for how to use.
920
921@section smplocking SMP Locking Helpers
922
923Lws provide a set of pthread mutex helpers that reduce to no code or
924variable footprint in the case that LWS_MAX_SMP == 1.
925
926Define your user mutex like this
927
928```
929 lws_pthread_mutex(name);
930```
931
932If LWS_MAX_SMP > 1, this produces `pthread_mutex_t name;`. In the case
933LWS_MAX_SMP == 1, it produces nothing.
934
935Likewise these helpers for init, destroy, lock and unlock
936
937
938```
939 void lws_pthread_mutex_init(pthread_mutex_t *lock)
940 void lws_pthread_mutex_destroy(pthread_mutex_t *lock)
941 void lws_pthread_mutex_lock(pthread_mutex_t *lock)
942 void lws_pthread_mutex_unlock(pthread_mutex_t *lock)
943```
944
945resolve to nothing if LWS_MAX_SMP == 1, otherwise produce the equivalent
946pthread api.
947
948pthreads is required in lws only if LWS_MAX_SMP > 1.
949
950
951@section libevuv libev / libuv / libevent support
952
953You can select either or both
954
955 -DLWS_WITH_LIBEV=1
956 -DLWS_WITH_LIBUV=1
957 -DLWS_WITH_LIBEVENT=1
958
959at cmake configure-time. The user application may use one of the
960context init options flags
961
962 LWS_SERVER_OPTION_LIBEV
963 LWS_SERVER_OPTION_LIBUV
964 LWS_SERVER_OPTION_LIBEVENT
965
966to indicate it will use one of the event libraries at runtime.
967
968libev and libevent headers conflict, they both define critical constants like
969EV_READ to different values. Attempts to discuss clearing that up with both
970libevent and libev did not get anywhere useful. Therefore CMakeLists.txt will
971error out if you enable both LWS_WITH_LIBEV and LWS_WITH_LIBEVENT.
972
973In addition depending on libev / compiler version, building anything with libev
974apis using gcc may blow strict alias warnings (which are elevated to errors in
975lws). I did some googling at found these threads related to it, the issue goes
976back at least to 2010 on and off
977
978https://github.com/redis/hiredis/issues/434
979https://bugs.gentoo.org/show_bug.cgi?id=615532
980http://lists.schmorp.de/pipermail/libev/2010q1/000916.html
981http://lists.schmorp.de/pipermail/libev/2010q1/000920.html
982http://lists.schmorp.de/pipermail/libev/2010q1/000923.html
983
984We worked around this problem by disabling -Werror on the parts of lws that
985use libev. FWIW as of Dec 2019 using Fedora 31 libev 4.27.1 and its gcc 9.2.1
986doesn't seem to trigger the problem even without the workaround.
987
988For these reasons and the response I got trying to raise these issues with
989them, if you have a choice about event loop, I would gently encourage you
990to avoid libev. Where lws uses an event loop itself, eg in lwsws, we use
991libuv.
992
993@section extopts Extension option control from user code
994
995User code may set per-connection extension options now, using a new api
996`lws_set_extension_option()`.
997
998This should be called from the ESTABLISHED callback like this
999```
1000 lws_set_extension_option(wsi, "permessage-deflate",
1001 "rx_buf_size", "12"); /* 1 << 12 */
1002```
1003
1004If the extension is not active (missing or not negotiated for the
1005connection, or extensions are disabled on the library) the call is
1006just returns -1. Otherwise the connection's extension has its
1007named option changed.
1008
1009The extension may decide to alter or disallow the change, in the
1010example above permessage-deflate restricts the size of his rx
1011output buffer also considering the protocol's rx_buf_size member.
1012
1013
1014@section httpsclient Client connections as HTTP[S] rather than WS[S]
1015
1016You may open a generic http client connection using the same
1017struct lws_client_connect_info used to create client ws[s]
1018connections.
1019
1020To stay in http[s], set the optional info member "method" to
1021point to the string "GET" instead of the default NULL.
1022
1023After the server headers are processed, when payload from the
1024server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP
1025will be made.
1026
1027You can choose whether to process the data immediately, or
1028queue a callback when an outgoing socket is writeable to provide
1029flow control, and process the data in the writable callback.
1030
1031Either way you use the api `lws_http_client_read()` to access the
1032data, eg
1033
1034```
1035 case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
1036 {
1037 char buffer[1024 + LWS_PRE];
1038 char *px = buffer + LWS_PRE;
1039 int lenx = sizeof(buffer) - LWS_PRE;
1040
1041 lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n");
1042
1043 /*
1044 * Often you need to flow control this by something
1045 * else being writable. In that case call the api
1046 * to get a callback when writable here, and do the
1047 * pending client read in the writeable callback of
1048 * the output.
1049 */
1050 if (lws_http_client_read(wsi, &px, &lenx) < 0)
1051 return -1;
1052 while (lenx--)
1053 putchar(*px++);
1054 }
1055 break;
1056```
1057
1058Notice that if you will use SSL client connections on a vhost, you must
1059prepare the client SSL context for the vhost after creating the vhost, since
1060this is not normally done if the vhost was set up to listen / serve. Call
1061the api lws_init_vhost_client_ssl() to also allow client SSL on the vhost.
1062
1063@section clipipe Pipelining Client Requests to same host
1064
1065If you are opening more client requests to the same host and port, you
1066can give the flag LCCSCF_PIPELINE on `info.ssl_connection` to indicate
1067you wish to pipeline them.
1068
1069Without the flag, the client connections will occur concurrently using a
1070socket and tls wrapper if requested for each connection individually.
1071That is fast, but resource-intensive.
1072
1073With the flag, lws will queue subsequent client connections on the first
1074connection to the same host and port. When it has confirmed from the
1075first connection that pipelining / keep-alive is supported by the server,
1076it lets the queued client pipeline connections send their headers ahead
1077of time to create a pipeline of requests on the server side.
1078
1079In this way only one tcp connection and tls wrapper is required to transfer
1080all the transactions sequentially. It takes a little longer but it
1081can make a significant difference to resources on both sides.
1082
1083If lws learns from the first response header that keepalive is not possible,
1084then it marks itself with that information and detaches any queued clients
1085to make their own individual connections as a fallback.
1086
1087Lws can also intelligently combine multiple ongoing client connections to
1088the same host and port into a single http/2 connection with multiple
1089streams if the server supports it.
1090
1091Unlike http/1 pipelining, with http/2 the client connections all occur
1092simultaneously using h2 stream multiplexing inside the one tcp + tls
1093connection.
1094
1095You can turn off the h2 client support either by not building lws with
1096`-DLWS_WITH_HTTP2=1` or giving the `LCCSCF_NOT_H2` flag in the client
1097connection info struct `ssl_connection` member.
1098
1099@section vhosts Using lws vhosts
1100
1101If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create
1102your context, it won't create a default vhost using the info struct
1103members for compatibility. Instead you can call lws_create_vhost()
1104afterwards to attach one or more vhosts manually.
1105
1106```
1107 LWS_VISIBLE struct lws_vhost *
1108 lws_create_vhost(struct lws_context *context,
1109 struct lws_context_creation_info *info);
1110```
1111
1112lws_create_vhost() uses the same info struct as lws_create_context(),
1113it ignores members related to context and uses the ones meaningful
1114for vhost (marked with VH in libwebsockets.h).
1115
1116```
1117 struct lws_context_creation_info {
1118 int port; /* VH */
1119 const char *iface; /* VH */
1120 const struct lws_protocols *protocols; /* VH */
1121 const struct lws_extension *extensions; /* VH */
1122 ...
1123```
1124
1125When you attach the vhost, if the vhost's port already has a listen socket
1126then both vhosts share it and use SNI (is SSL in use) or the Host: header
1127from the client to select the right one. Or if no other vhost already
1128listening the a new listen socket is created.
1129
1130There are some new members but mainly it's stuff you used to set at
1131context creation time.
1132
1133
1134@section sni How lws matches hostname or SNI to a vhost
1135
1136LWS first strips any trailing :port number.
1137
1138Then it tries to find an exact name match for a vhost listening on the correct
1139port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a
1140vhost named abc.com that is listening on port 1234.
1141
1142If there is no exact match, lws will consider wildcard matches, for example
1143if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will
1144accept a vhost "abc.com" listening on port 1234. If there was a better, exact,
1145match, it will have been chosen in preference to this.
1146
1147Connections with SSL will still have the client go on to check the
1148certificate allows wildcards and error out if not.
1149
1150
1151
1152@section mounts Using lws mounts on a vhost
1153
1154The last argument to lws_create_vhost() lets you associate a linked
1155list of lws_http_mount structures with that vhost's URL 'namespace', in
1156a similar way that unix lets you mount filesystems into areas of your /
1157filesystem how you like and deal with the contents transparently.
1158
1159```
1160 struct lws_http_mount {
1161 struct lws_http_mount *mount_next;
1162 const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */
1163 const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */
1164 const char *def; /* default target, eg, "index.html" */
1165
1166 struct lws_protocol_vhost_options *cgienv;
1167
1168 int cgi_timeout;
1169 int cache_max_age;
1170
1171 unsigned int cache_reusable:1;
1172 unsigned int cache_revalidate:1;
1173 unsigned int cache_intermediaries:1;
1174
1175 unsigned char origin_protocol;
1176 unsigned char mountpoint_len;
1177 };
1178```
1179
1180The last mount structure should have a NULL mount_next, otherwise it should
1181point to the 'next' mount structure in your list.
1182
1183Both the mount structures and the strings must persist until the context is
1184destroyed, since they are not copied but used in place.
1185
1186`.origin_protocol` should be one of
1187
1188```
1189 enum {
1190 LWSMPRO_HTTP,
1191 LWSMPRO_HTTPS,
1192 LWSMPRO_FILE,
1193 LWSMPRO_CGI,
1194 LWSMPRO_REDIR_HTTP,
1195 LWSMPRO_REDIR_HTTPS,
1196 LWSMPRO_CALLBACK,
1197 };
1198```
1199
1200 - LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and
1201serve it automatically.
1202
1203 - LWSMPRO_CGI associates the url namespace with the given CGI executable, which
1204runs when the URL is accessed and the output provided to the client.
1205
1206 - LWSMPRO_REDIR_HTTP and LWSMPRO_REDIR_HTTPS auto-redirect clients to the given
1207origin URL.
1208
1209 - LWSMPRO_CALLBACK causes the http connection to attach to the callback
1210associated with the named protocol (which may be a plugin).
1211
1212
1213@section mountcallback Operation of LWSMPRO_CALLBACK mounts
1214
1215The feature provided by CALLBACK type mounts is binding a part of the URL
1216namespace to a named protocol callback handler.
1217
1218This allows protocol plugins to handle areas of the URL namespace. For example
1219in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin
1220providing "protocol-post-demo" like this
1221
1222```
1223 static const struct lws_http_mount mount_post = {
1224 NULL, /* linked-list pointer to next*/
1225 "/formtest", /* mountpoint in URL namespace on this vhost */
1226 "protocol-post-demo", /* handler */
1227 NULL, /* default filename if none given */
1228 NULL,
1229 0,
1230 0,
1231 0,
1232 0,
1233 0,
1234 LWSMPRO_CALLBACK, /* origin points to a callback */
1235 9, /* strlen("/formtest"), ie length of the mountpoint */
1236 };
1237```
1238
1239Client access to /formtest[anything] will be passed to the callback registered
1240with the named protocol, which in this case is provided by a protocol plugin.
1241
1242Access by all methods, eg, GET and POST are handled by the callback.
1243
1244protocol-post-demo deals with accepting and responding to the html form that
1245is in the test server HTML.
1246
1247When a connection accesses a URL related to a CALLBACK type mount, the
1248connection protocol is changed until the next access on the connection to a
1249URL outside the same CALLBACK mount area. User space on the connection is
1250arranged to be the size of the new protocol user space allocation as given in
1251the protocol struct.
1252
1253This allocation is only deleted / replaced when the connection accesses a
1254URL region with a different protocol (or the default protocols[0] if no
1255CALLBACK area matches it).
1256
1257This "binding connection to a protocol" lifecycle in managed by
1258`LWS_CALLBACK_HTTP_BIND_PROTOCOL` and `LWS_CALLBACK_HTTP_DROP_PROTOCOL`.
1259Because of HTTP/1.1 connection pipelining, one connection may perform
1260many transactions, each of which may map to different URLs and need
1261binding to different protocols. So these messages are used to
1262create the binding of the wsi to your protocol including any
1263allocations, and to destroy the binding, at which point you should
1264destroy any related allocations.
1265
1266@section BINDTODEV SO_BIND_TO_DEVICE
1267
1268The .bind_iface flag in the context / vhost creation struct lets you
1269declare that you want all traffic for listen and transport on that
1270vhost to be strictly bound to the network interface named in .iface.
1271
1272This Linux-only feature requires SO_BIND_TO_DEVICE, which in turn
1273requires CAP_NET_RAW capability... root has this capability.
1274
1275However this feature needs to apply the binding also to accepted
1276sockets during normal operation, which implies the server must run
1277the whole time as root.
1278
1279You can avoid this by using the Linux capabilities feature to have
1280the unprivileged user inherit just the CAP_NET_RAW capability.
1281
1282You can confirm this with the test server
1283
1284
1285```
1286 $ sudo /usr/local/bin/libwebsockets-test-server -u agreen -i eno1 -k
1287```
1288
1289The part that ensures the capability is inherited by the unprivileged
1290user is
1291
1292```
1293#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
1294 info.caps[0] = CAP_NET_RAW;
1295 info.count_caps = 1;
1296#endif
1297```
1298
1299
1300@section dim Dimming webpage when connection lost
1301
1302The lws test plugins' html provides useful feedback on the webpage about if it
1303is still connected to the server, by greying out the page if not. You can
1304also add this to your own html easily
1305
1306 - include lws-common.js from your HEAD section
1307
1308 \<script src="/lws-common.js">\</script>
1309
1310 - dim the page during initialization, in a script section on your page
1311
1312 lws_gray_out(true,{'zindex':'499'});
1313
1314 - in your ws onOpen(), remove the dimming
1315
1316 lws_gray_out(false);
1317
1318 - in your ws onClose(), reapply the dimming
1319
1320 lws_gray_out(true,{'zindex':'499'});
1321
1322@section errstyle Styling http error pages
1323
1324In the code, http errors should be handled by `lws_return_http_status()`.
1325
1326There are basically two ways... the vhost can be told to redirect to an "error
1327page" URL in response to specifically a 404... this is controlled by the
1328context / vhost info struct (`struct lws_context_creation_info`) member
1329`.error_document_404`... if non-null the client is redirected to this string.
1330
1331If it wasn't redirected, then the response code html is synthesized containing
1332the user-selected text message and attempts to pull in `/error.css` for styling.
1333
1334If this file exists, it can be used to style the error page. See
1335https://libwebsockets.org/git/badrepo for an example of what can be done (
1336and https://libwebsockets.org/error.css for the corresponding css).
1337
1338
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 approved 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 allow 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 approve 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.ctest.md
1## Using CTest with lws
2
3### Updating ancient cmake
4
5You need a recent cmake to have the CTest tests work properly, if you're on an
6older distro you need to update your cmake. Luckily Kitware provide a repo for
7common distros. These instructions work for bionic and xenial.
8
9First remove the old distro cmake and install the pieces needed to get the new repo keys
10
11```
12# apt purge --auto-remove cmake
13# apt install gnupg wget apt-transport-https ca-certificates
14# wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
15# apt edit-sources
16```
17
18Add the line `deb https://apt.kitware.com/ubuntu/ bionic main` at the end
19replacing `bionic` with `xenial` as needed, and save (:wq). Then
20
21```
22# apt update
23# apt install cmake
24```
25
26## Tests live in CMakeLists.txt
27
28The rules for tests are described in ctest / cmake language inside the minimal
29examples and api tests that are enabled by current build options, so you need
30to build with `-DLWS_WITH_MINIMAL_EXAMPLES=1` to build the examples along with
31the library.
32
33The tests are typically running the examples or api tests and regarding the
34process exiting with exit code 0 as success, anything else as failure.
35
36## Generating the tests
37
38The main tests just need `-DLWS_WITH_MINIMAL_EXAMPLES=1`. You can optionally set
39`-DLWS_CTEST_INTERNET_AVAILABLE=0` to indicate you can't run the tests that need
40internet connectivity.
41
42## Preparing to run the tests
43
44The tests have to be able to run without root and without disturbing any other
45install of lws in the build machine.
46
47For that reason you have to do an unprivileged side-install into `../destdir`,
48using `make install DESTDIR=../destdir` from the build directory and perform the
49tests on the pieces in there.
50
51## Running the tests
52
53We must take care to run the pieces (.so etc) we just built, without having
54root access, and not any of the same pieces from some other lws version that may
55have been installed on the build machine. That includes, eg, plugins that
56we just built, to ensure precedence of those in the search path we can set our
57DESTDIR unprivileged install path in `LD_LIBRARY_PATH`.
58
59Then we can run ctest on the unprivileged install. The whole step looks
60something like this:
61
62```
63build $ make -j12 && \
64 rm -rf ../destdir && \
65 make -j12 DESTDIR=../destdir install && \\
66 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins ctest -j2 --output-on-failure
67```
68
69On windows, it looks like `ctest . -C DEBUG` or RELEASE if that was the build
70type.
71
72Good results look something like this (which tests can run depend on your
73build options)
74
75```
76Test project /projects/libwebsockets/build
77 Start 71: st_wcs_srv
78 Start 43: st_hcp_srv
79 1/73 Test #71: st_wcs_srv .................................. Passed 5.01 sec
80 Start 19: st_hcmp_srv
81 2/73 Test #43: st_hcp_srv .................................. Passed 5.01 sec
82 Start 17: st_hcm_srv
83 3/73 Test #19: st_hcmp_srv ................................. Passed 5.01 sec
84 Start 55: st_ssproxyctx
85 4/73 Test #17: st_hcm_srv .................................. Passed 5.01 sec
86 Start 52: st_ssproxy
87 5/73 Test #55: st_ssproxyctx ............................... Passed 1.02 sec
88 Start 67: st_sstfproxy
89 6/73 Test #52: st_ssproxy .................................. Passed 1.02 sec
90 Start 60: st_ssprxsmd_sspc
91 7/73 Test #67: st_sstfproxy ................................ Passed 1.01 sec
92 Start 63: st_mulssprxsmd_sspc
93 8/73 Test #60: st_ssprxsmd_sspc ............................ Passed 1.01 sec
94 Start 69: sspc-minimaltf
95 9/73 Test #63: st_mulssprxsmd_sspc ......................... Passed 1.02 sec
96 Start 73: ws-client-spam
9710/73 Test #73: ws-client-spam .............................. Passed 12.21 sec
98 Start 57: sspc-minimaltx
9911/73 Test #57: sspc-minimaltx .............................. Passed 5.90 sec
100 Start 65: mulsspcsmd_sspc
10112/73 Test #65: mulsspcsmd_sspc ............................. Passed 3.58 sec
102 Start 62: sspcsmd_sspc
10313/73 Test #62: sspcsmd_sspc ................................ Passed 1.73 sec
104 Start 22: http-client-multi-h1
10514/73 Test #22: http-client-multi-h1 ........................ Passed 5.04 sec
106 Start 25: http-client-multi-stag
10715/73 Test #25: http-client-multi-stag ...................... Passed 4.53 sec
108 Start 26: http-client-multi-stag-h1
10916/73 Test #26: http-client-multi-stag-h1 ................... Passed 4.40 sec
110 Start 21: http-client-multi
11117/73 Test #21: http-client-multi ........................... Passed 4.37 sec
112 Start 36: http-client-multi-post-h1
11318/73 Test #36: http-client-multi-post-h1 ................... Passed 2.73 sec
114 Start 54: sspc-minimal
11519/73 Test #54: sspc-minimal ................................ Passed 0.93 sec
116 Start 39: http-client-multi-post-stag
11720/73 Test #39: http-client-multi-post-stag ................. Passed 2.29 sec
118 Start 40: http-client-multi-post-stag-h1
11921/73 Test #69: sspc-minimaltf .............................. Passed 49.83 sec
120 Start 35: http-client-multi-post
12122/73 Test #40: http-client-multi-post-stag-h1 .............. Passed 4.30 sec
122 Start 33: http-client-multi-restrict-nopipe-fail
12323/73 Test #35: http-client-multi-post ...................... Passed 3.23 sec
124 Start 28: http-client-multi-stag-h1-pipe
12524/73 Test #33: http-client-multi-restrict-nopipe-fail ...... Passed 2.86 sec
126 Start 32: http-client-multi-restrict-stag-h1-pipe
12725/73 Test #28: http-client-multi-stag-h1-pipe .............. Passed 2.86 sec
128 Start 27: http-client-multi-stag-pipe
12926/73 Test #32: http-client-multi-restrict-stag-h1-pipe ..... Passed 1.51 sec
130 Start 31: http-client-multi-restrict-stag-pipe
13127/73 Test #27: http-client-multi-stag-pipe ................. Passed 1.52 sec
132 Start 34: http-client-multi-restrict-h1-nopipe-fail
13328/73 Test #34: http-client-multi-restrict-h1-nopipe-fail ... Passed 2.78 sec
134 Start 46: http-client-post-m
13529/73 Test #31: http-client-multi-restrict-stag-pipe ........ Passed 2.80 sec
136 Start 42: http-client-multi-post-stag-h1-pipe
13730/73 Test #42: http-client-multi-post-stag-h1-pipe ......... Passed 1.51 sec
138 Start 41: http-client-multi-post-stag-pipe
13931/73 Test #46: http-client-post-m .......................... Passed 1.59 sec
140 Start 48: http-client-post-m-h1
14132/73 Test #48: http-client-post-m-h1 ....................... Passed 1.10 sec
142 Start 23: http-client-multi-pipe
14333/73 Test #41: http-client-multi-post-stag-pipe ............ Passed 1.51 sec
144 Start 29: http-client-multi-restrict-pipe
14534/73 Test #23: http-client-multi-pipe ...................... Passed 1.09 sec
146 Start 24: http-client-multi-h1-pipe
14735/73 Test #29: http-client-multi-restrict-pipe ............. Passed 0.74 sec
148 Start 30: http-client-multi-restrict-h1-pipe
14936/73 Test #24: http-client-multi-h1-pipe ................... Passed 1.14 sec
150 Start 45: http-client-post
15137/73 Test #30: http-client-multi-restrict-h1-pipe .......... Passed 1.14 sec
152 Start 38: http-client-multi-post-h1-pipe
15338/73 Test #45: http-client-post ............................ Passed 0.30 sec
154 Start 37: http-client-multi-post-pipe
15539/73 Test #38: http-client-multi-post-h1-pipe .............. Passed 0.49 sec
156 Start 47: http-client-post-h1
15740/73 Test #37: http-client-multi-post-pipe ................. Passed 0.31 sec
158 Start 50: hs_evlib_foreign_event
15941/73 Test #47: http-client-post-h1 ......................... Passed 0.29 sec
160 Start 66: ss-tf
16142/73 Test #50: hs_evlib_foreign_event ...................... Passed 22.02 sec
162 Start 49: hs_evlib_foreign_uv
16343/73 Test #49: hs_evlib_foreign_uv ......................... Passed 21.03 sec
164 Start 51: ss-warmcat
16544/73 Test #51: ss-warmcat .................................. Passed 2.69 sec
166 Start 59: ss-smd
16745/73 Test #59: ss-smd ...................................... Passed 1.78 sec
168 Start 10: api-test-secure-streams
16946/73 Test #10: api-test-secure-streams ..................... Passed 1.34 sec
170 Start 11: http-client-warmcat
17147/73 Test #11: http-client-warmcat ......................... Passed 0.27 sec
172 Start 58: sspost-warmcat
17348/73 Test #58: sspost-warmcat .............................. Passed 0.84 sec
174 Start 12: http-client-warmcat-h1
17549/73 Test #12: http-client-warmcat-h1 ...................... Passed 0.25 sec
176 Start 2: api-test-jose
17750/73 Test #2: api-test-jose ............................... Passed 0.27 sec
178 Start 70: ws-client-rx-warmcat
17951/73 Test #70: ws-client-rx-warmcat ........................ Passed 0.27 sec
180 Start 56: ki_ssproxyctx
18152/73 Test #56: ki_ssproxyctx ............................... Passed 0.12 sec
182 Start 68: ki_ssproxy
18353/73 Test #68: ki_ssproxy .................................. Passed 0.11 sec
184 Start 64: ki_mulssprxsmd_sspc
18554/73 Test #64: ki_mulssprxsmd_sspc ......................... Passed 0.10 sec
186 Start 61: ki_ssprxsmd_sspc
18755/73 Test #61: ki_ssprxsmd_sspc ............................ Passed 0.11 sec
188 Start 13: http-client-h2-rxflow-warmcat
18956/73 Test #13: http-client-h2-rxflow-warmcat ............... Passed 0.28 sec
190 Start 14: http-client-h2-rxflow-warmcat-h1
19157/73 Test #14: http-client-h2-rxflow-warmcat-h1 ............ Passed 0.34 sec
192 Start 16: http-client-hugeurl-warmcat-h1
19358/73 Test #16: http-client-hugeurl-warmcat-h1 .............. Passed 0.16 sec
194 Start 15: http-client-hugeurl-warmcat
19559/73 Test #15: http-client-hugeurl-warmcat ................. Passed 0.16 sec
196 Start 72: ki_wcs_srv
19760/73 Test #72: ki_wcs_srv .................................. Passed 0.12 sec
198 Start 44: ki_hcp_srv
19961/73 Test #44: ki_hcp_srv .................................. Passed 0.11 sec
200 Start 20: ki_hcmp_srv
20162/73 Test #20: ki_hcmp_srv ................................. Passed 0.11 sec
202 Start 18: ki_hcm_srv
20363/73 Test #18: ki_hcm_srv .................................. Passed 0.11 sec
204 Start 7: api-test-lws_struct_sqlite
20564/73 Test #7: api-test-lws_struct_sqlite .................. Passed 0.03 sec
206 Start 1: api-test-gencrypto
20765/73 Test #1: api-test-gencrypto .......................... Passed 0.02 sec
208 Start 6: api-test-lws_struct-json
20966/73 Test #6: api-test-lws_struct-json .................... Passed 0.01 sec
210 Start 4: api-test-lws_dsh
21167/73 Test #4: api-test-lws_dsh ............................ Passed 0.01 sec
212 Start 8: api-test-lws_tokenize
21368/73 Test #8: api-test-lws_tokenize ....................... Passed 0.01 sec
214 Start 9: api-test-lwsac
21569/73 Test #9: api-test-lwsac .............................. Passed 0.00 sec
216 Start 3: api-test-lejp
21770/73 Test #3: api-test-lejp ............................... Passed 0.00 sec
218 Start 53: ki_ssproxy
21971/73 Test #53: ki_ssproxy .................................. Passed 0.11 sec
22072/73 Test #66: ss-tf ....................................... Passed 55.51 sec
221 Start 5: api-test-lws_smd
22273/73 Test #5: api-test-lws_smd ............................ Passed 4.22 sec
223
224100% tests passed, 0 tests failed out of 73
225
226Total Test time (real) = 137.76 sec
227```
228
229## Considerations for creating tests
230
231### Timeout
232
233The default test timeout is 1500s, for that reason it's good practice to set
234a more suitable `TIMEOUT` property on every test.
235
236### Working Directory
237
238Server-side test apps usually need to be run from their `./minimal-examples/...`
239directory so they can access their assets like index.html etc.
240
241However when building with `-DLWS_WITH_MBEDTLS=1` then even client-side apps
242need to be run from their directory, since they need to get the trusted CA for
243warmcat.com or libwebsockets.org additionally.
244
245For that reason it's good practice to set the `WORKING_DIRECTORY` property to
246the home dir of the example app in all cases.
247
248### Spawning Buddies
249
250Many networking tests need to either spawn a client or a server in order to
251have a "buddy" to talk to during the test for the opposing side. This is a
252bit awkward in cmake since it does not directly support spawning daemons as
253test dependencies.
254
255Lws provides helper scripts for unix type targets in `./scripts/ctest-background.sh`
256and `./scripts/ctest-background-kill.sh`, which spawn background processes,
257save the pid in a decorated /tmp file and can later take the process down. This
258also has arrangements to dump the log of any background process that exited
259early.
260
261To arrange the buddy to run aligned with the test, you first explain to cmake
262how to start and stop the buddy using phony tests to make a "fixture" in cmake
263terms.
264
265In this example, taken from minimal-http-client-multi, we arrange for
266minimal-http-server-tls to be available for our actual test. The starting and
267stopping definition, for "st_hcm_srv" and "ki_hcm_srv":
268
269```
270 add_test(NAME st_hcm_srv COMMAND
271 ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
272 hcm_srv $<TARGET_FILE:lws-minimal-http-server-tls>
273 --port ${PORT_HCM_SRV} )
274 add_test(NAME ki_hcm_srv COMMAND
275 ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
276 hcm_srv $<TARGET_FILE_NAME:lws-minimal-http-server-tls>
277 --port ${PORT_HCM_SRV})
278```
279
280... and binding those together so cmake knows they start and stop a specific
281named fixture "hcm_srv", itself with an 800s timeout
282
283```
284 set_tests_properties(st_hcm_srv PROPERTIES
285 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-tls
286 FIXTURES_SETUP hcm_srv
287 TIMEOUT 800)
288 set_tests_properties(ki_hcm_srv PROPERTIES
289 FIXTURES_CLEANUP hcm_srv)
290```
291
292... and finally, adding the "hcm_srv" fixture as a requirement on the actual
293test (http-client-multi) we are testing
294
295```
296 set_tests_properties(http-client-multi
297 PROPERTIES
298 FIXTURES_REQUIRED "hcm_srv"
299 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client-multi
300 TIMEOUT 50)
301```
302
303Once all that explaining is done, ctest itself will take care about starting
304and killing hcm_srv before and after http-client-multi test.
305
306### Buddy sockets and test concurrency
307
308For tests with local buddies using tcp sockets inside the same VM or systemd-
309nspawn networking context, you cannot just use a well-known port like 7681.
310
311ctest itself is usually executed concurrently, and Sai is typically building
312multiple different instances concurrently as well (typically 3), so it may be
313running different ctests inside the same VM simultaneously.
314
315Different tests can have their own convention for port ranges, to solve the
316problem about Sai running different tests concurrently inside one ctest.
317
318For the case there are multiple ctests running, we can use the env var
319`$ENV{SAI_INSTANCE_IDX}`, which is an ordinal like 0 or 1, to further ensure
320that port selections won't conflict. If not using Sai, you can just set this
321in the evironment yourself to reflect your build instance index.
322
323```
324 #
325 # instantiate the server per sai builder instance, they are running in the same
326 # machine context in parallel so they can tread on each other otherwise
327 #
328 set(PORT_HCM_SRV "7670")
329 if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0")
330 set(PORT_HCM_SRV 7671)
331 endif()
332 if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1")
333 set(PORT_HCM_SRV 7672)
334 endif()
335 if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2")
336 set(PORT_HCM_SRV 7673)
337 endif()
338 if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3")
339 set(PORT_HCM_SRV 7674)
340 endif()
341```
342
343This is complicated enough that the best approach is copy an existing simple
344case like the CMakeLists.txt for minimal-http-client and change the names and
345ports to be unique.
346
README.debugging.md
1# Tips on debugging with lws
2
3## Problem with the library, or your code?
4
5Because lws is only really used when already combined with user code,
6it can be a headache figuring out if the actual problem is inside lws
7or in the user code.
8
9If it's in lws, I would really like to solve it, but if it's in your
10code, that's your problem. Finding out which side it's on when it
11involves your code is also something you need to try to resolve.
12
13The minimal examples are useful because if they demonstrate the same
14problem, it's something about your platform or lws itself, I have the
15minimal examples so I can test it and find out if it's your platform.
16If I can reproduce it, it's my problem.
17
18## Debug builds
19
20With cmake, build with `-DCMAKE_BUILD_TYPE=DEBUG` to build in extra
21logging, and use a log level bitmap of eg, 1039 or 1151 to enable
22the extra logs for print.
23
24The minimal examples take a -d xxx commandline parameter so you can
25select the logging level when you run it.
26
27The extra logging can be very useful to understand the sequencing of
28problematic actions.
29
30## Valgrind
31
32If your problems involve heap corruption or use-after-free, Valgrind
33is indespensible. It's simple to use, if you normally run `xxx`, just
34run `valgrind xxx`. Your code will run slower, usually something
35like 2 - 4x slower but it depends on the exact code. However you will
36get a backtrace as soon as there is some kind of misbehaviour of either
37lws or your code.
38
39lws is developed using valgrind routinely and strives to be completely
40valgrind-clean. So typically any problems reported are telling you
41about problems in user code (or my bugs).
42
43## Traffic dumping
44
45The best place for dumping traffic, assuming you are linking against a
46tls library, is `lws_ssl_capable_read()` and `lws_ssl_capable_write()`
47in either `./lib/tls/openssl/openssl-ssl.c` or
48`./lib/tls/mbedtls/mbedtls-ssl.c` according to which tls library you
49are using. There are default-`#if 0` sections in each function like
50
51```
52#if 0
53 /*
54 * If using mbedtls type tls library, this is the earliest point for all
55 * paths to dump what was received as decrypted data from the tls tunnel
56 */
57 lwsl_notice("%s: len %d\n", __func__, len);
58 lwsl_hexdump_notice(buf, len);
59#endif
60```
61
62Enable these to get hexdumps for all unencrypted data in both directions.
63
64
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.event-libs.md
1# lws event library support
2
3## v4.0 and below
4
5Before v4.1, lws allowed selecting some event library support for inclusion
6in the libwebsockets library
7
8Option|Feature
9---|---
10`LWS_WITH_GLIB`|glib
11`LWS_WITH_LIBEVENT`|libevent
12`LWS_WITH_LIBUV`|libuv
13`LWS_WITH_LIBEV`|libev
14
15The user code can select by `info->options` flags at runtime which event loop
16it wants to use.
17
18The only restriction is that libev and libevent can't coexist, because their
19header namespace conflicts.
20
21## v4.1 and above
22
23Lws continues to support the old way described above, but there's an additional
24new cmake option that decides how they are built if any are selected,
25`LWS_WITH_EVLIB_PLUGINS`.
26
27The old behaviour is set by `LWS_WITH_EVLIB_PLUGINS=0`, for UNIX platforms, this
28is set to 1 by default. This causes the enabled event lib support to each be built into
29its own dynamically linked plugin, and lws will bring in the requested support alone
30at runtime after seeing the `info->options` flags requested by the user code.
31
32This has two main benefits, first the conflict around building libevent and libev
33together is removed, they each build isolated in their own plugin; the libwebsockets
34core library build doesn't import any of their headers (see below for exception).
35And second, for distro packaging, the event lib support plugins can be separately
36packaged, and apps take dependencies on the specific event lib plugin package, which
37itself depends on the libwebsockets core library. This allows just the needed
38dependencies for the packageset without forcing everything to bring everything in.
39
40Separately, lws itself has some optional dependencies on libuv, if you build lwsws
41or on Windows you want plugins at all. CMake will detect these situations and
42select to link the lws library itself to libuv if so as well, independent of whatever
43is happening with the event lib support.
44
45## evlib plugin install
46
47The produced plugins are named
48
49event lib|plugin name
50---|---
51glib|`libwebsockets-evlib_glib.so`
52event|`libwebsockets-evlib_event.so`
53uv|`libwebsockets-evlib_uv.so`
54ev|`libwebsockets-evlib_ev.so`
55
56The evlib plugins are installed alongside libwebsockets.so/.a into the configured
57library dir, it's often `/usr/local/lib/` by default on linux.
58
59Lws looks for them at runtime using the build-time-configured path.
60
61## Component packaging
62
63The canonical package name is `libwebsockets`, the recommended way to split the
64packaging is put the expected libs and pkgconfig in `libwebsockets` or `libwebsockets-core`,
65the latter is followed by the provided cmake, and produce an additional package per build
66event library plugin, named, eg `libwebsockets-evlib_glib`, which has a dependency on
67`libwebsockets[-core]`.
68
69Applications that use the default event loop can directly require `libwebsockets[-core]`,
70and application packages that need specific event loop support can just require, eg,
71`libwebsockets-evlib_glib`, which will bring that in and the core lws pieces in one step.
72There is then no problem with multiple apps requiring different event libs, they will
73bring in all the necessary pieces which will not conflict either as packages or at
74runtime.
75
76## `LWS_WITH_DISTRO_RECOMMENDED`
77
78The cmake helper config `LWS_WITH_DISTRO_RECOMMENDED` is adapted to build all the
79event libs with the event lib plugin support enabled.
80
81
README.event-loops-intro.md
1# Considerations around Event Loops
2
3Much of the software we use is written around an **event loop**. Some examples
4
5 - Chrome / Chromium, transmission, tmux, ntp SNTP... [libevent](https://libevent.org/)
6 - node.js / cjdns / Julia / cmake ... [libuv](https://archive.is/64pOt)
7 - Gstreamer, Gnome / GTK apps ... [glib](https://people.gnome.org/~desrt/glib-docs/glib-The-Main-Event-Loop.html)
8 - SystemD ... sdevent
9 - OpenWRT ... uloop
10
11Many applications roll their own event loop using poll() or epoll() or similar,
12using the same techniques. Another set of apps use message dispatchers that
13take the same approach, but are for cases that don't need to support sockets.
14Event libraries provide crossplatform abstractions for this functoinality, and
15provide the best backend for their event waits on the platform automagically.
16
17libwebsockets networking operations require an event loop, it provides a default
18one for the platform (based on poll() for Unix) if needed, but also can natively
19use any of the event loop libraries listed above, including "foreign" loops
20already created and managed by the application.
21
22## What is an 'event loop'?
23
24Event loops have the following characteristics:
25
26 - they have a **single thread**, therefore they do not require locking
27 - they are **not threadsafe**
28 - they require **nonblocking IO**
29 - they **sleep** while there are no events (aka the "event wait")
30 - if one or more event seen, they call back into user code to handle each in
31 turn and then return to the wait (ie, "loop")
32
33### They have a single thread
34
35By doing everything in turn on a single thread, there can be no possibility of
36conflicting access to resources from different threads... if the single thread
37is in callback A, it cannot be in two places at the same time and also in
38callback B accessing the same thing: it can never run any other code
39concurrently, only sequentially, by design.
40
41It means that all mutexes and other synchronization and locking can be
42eliminated, along with the many kinds of bugs related to them.
43
44### They are not threadsafe
45
46Event loops mandate doing everything in a single thread. You cannot call their
47apis from other threads, since there is no protection against reentrancy.
48
49Lws apis cannot be called safely from any thread other than the event loop one,
50with the sole exception of `lws_cancel_service()`.
51
52### They have nonblocking IO
53
54With blocking IO, you have to create threads in order to block them to learn
55when your IO could proceed. In an event loop, all descriptors are set to use
56nonblocking mode, we only attempt to read or write when we have been informed by
57an event that there is something to read, or it is possible to write.
58
59So sacrificial, blocking discrete IO threads are also eliminated, we just do
60what we should do sequentially, when we get the event indicating that we should
61do it.
62
63### They sleep while there are no events
64
65An OS "wait" of some kind is used to sleep the event loop thread until something
66to do. There's an explicit wait on file descriptors that have pending read or
67write, and also an implicit wait for the next scheduled event. Even if idle for
68descriptor events, the event loop will wake and handle scheduled events at the
69right time.
70
71In an idle system, the event loop stays in the wait and takes 0% CPU.
72
73### If one or more event, they handle them and then return to sleep
74
75As you can expect from "event loop", it is an infinite loop alternating between
76sleeping in the event wait and sequentially servicing pending events, by calling
77callbacks for each event on each object.
78
79The callbacks handle the event and then "return to the event loop". The state
80of things in the loop itself is guaranteed to stay consistent while in a user
81callback, until you return from the callback to the event loop, when socket
82closes may be processed and lead to object destruction.
83
84Event libraries like libevent are operating the same way, once you start the
85event loop, it sits in an inifinite loop in the library, calling back on events
86until you "stop" or "break" the loop by calling apis.
87
88## Why are event libraries popular?
89
90Developers prefer an external library solution for the event loop because:
91
92 - the quality is generally higher than self-rolled ones. Someone else is
93 maintaining it, a fulltime team in some cases.
94 - the event libraries are crossplatform, they will pick the most effective
95 event wait for the platform without the developer having to know the details.
96 For example most libs can conceal whether the platform is windows or unix,
97 and use native waits like epoll() or WSA accordingly.
98 - If your application uses a event library, it is possible to integrate very
99 cleanly with other libraries like lws that can use the same event library.
100 That is extremely messy or downright impossible to do with hand-rolled loops.
101
102Compared to just throwing threads on it
103
104 - thread lifecycle has to be closely managed, threads must start and must be
105 brought to an end in a controlled way. Event loops may end and destroy
106 objects they control at any time a callback returns to the event loop.
107
108 - threads may do things sequentially or genuinely concurrently, this requires
109 locking and careful management so only deterministic and expected things
110 happen at the user data.
111
112 - threads do not scale well to, eg, serving tens of thousands of connections;
113 web servers use event loops.
114
115## Multiple codebases cooperating on one event loop
116
117The ideal situation is all your code operates via a single event loop thread.
118For lws-only code, including lws_protocols callbacks, this is the normal state
119of affairs.
120
121When there is other code that also needs to handle events, say already existing
122application code, or code handling a protocol not supported by lws, there are a
123few options to allow them to work together, which is "best" depends on the
124details of what you're trying to do and what the existing code looks like.
125In descending order of desirability:
126
127### 1) Use a common event library for both lws and application code
128
129This is the best choice for Linux-class devices. If you write your application
130to use, eg, a libevent loop, then you only need to configure lws to also use
131your libevent loop for them to be able to interoperate perfectly. Lws will
132operate as a guest on this "foreign loop", and can cleanly create and destroy
133its context on the loop without disturbing the loop.
134
135In addition, your application can merge and interoperate with any other
136libevent-capable libraries the same way, and compared to hand-rolled loops, the
137quality will be higher.
138
139### 2) Use lws native wsi semantics in the other code too
140
141Lws supports raw sockets and file fd abstractions inside the event loop. So if
142your other code fits into that model, one way is to express your connections as
143"RAW" wsis and handle them using lws_protocols callback semantics.
144
145This ties the application code to lws, but it has the advantage that the
146resulting code is aware of the underlying event loop implementation and will
147work no matter what it is.
148
149### 3) Make a custom lws event lib shim for your custom loop
150
151Lws provides an ops struct abstraction in order to integrate with event
152libraries, you can find it in ./includes/libwebsockets/lws-eventlib-exports.h.
153
154Lws uses this interface to implement its own event library plugins, but you can
155also use it to make your own customized event loop shim, in the case there is
156too much written for your custom event loop to be practical to change it.
157
158In other words this is a way to write a customized event lib "plugin" and tell
159the lws_context to use it at creation time. See [minimal-http-server.c](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/http-server/minimal-http-server-eventlib-custom/minimal-http-server.c)
160
161### 4) Cooperate at thread level
162
163This is less desirable because it gives up on unifying the code to run from a
164single thread, it means the codebases cannot call each other's apis directly.
165
166In this scheme the existing threads do their own thing, lock a shared
167area of memory and list what they want done from the lws thread context, before
168calling `lws_cancel_service()` to break the lws event wait. Lws will then
169broadcast a `LWS_CALLBACK_EVENT_WAIT_CANCELLED` protocol callback, the handler
170for which can lock the shared area and perform the requested operations from the
171lws thread context.
172
173### 5) Glue the loops together to wait sequentially (don't do this)
174
175If you have two or more chunks of code with their own waits, it may be tempting
176to have them wait sequentially in an outer event loop. (This is only possible
177with the lws default loop and not the event library support, event libraries
178have this loop inside their own `...run(loop)` apis.)
179
180```
181 while (1) {
182 do_lws_wait(); /* interrupted at short intervals */
183 do_app_wait(); /* interrupted at short intervals */
184 }
185```
186
187This never works well, either:
188
189 - the whole thing spins at 100% CPU when idle, or
190
191 - the waits have timeouts where they sleep for short periods, but then the
192 latency to service on set of events is increased by the idle timeout period
193 of the wait for other set of events
194
195## Common Misunderstandings
196
197### "Real Men Use Threads"
198
199Sometimes you need threads or child processes. But typically, whatever you're
200trying to do does not literally require threads. Threads are an architectural
201choice that can go either way depending on the goal and the constraints.
202
203Any thread you add should have a clear reason to specifically be a thread and
204not done on the event loop, without a new thread or the consequent locking (and
205bugs).
206
207### But blocking IO is faster and simpler
208
209No, blocking IO has a lot of costs to conceal the event wait by blocking.
210
211For any IO that may wait, you must spawn an IO thread for it, purely to handle
212the situation you get blocked in read() or write() for an arbitrary amount of
213time. It buys you a simple story in one place, that you will proceed on the
214thread if read() or write() has completed, but costs threads and locking to get
215to that.
216
217Event loops dispense with the threads and locking, and still provide a simple
218story, you will get called back when data arrives or you may send.
219
220Event loops can scale much better, a busy server with 50,000 connections active
221does not have to pay the overhead of 50,000 threads and their competing for
222locking.
223
224With blocked threads, the thread can do no useful work at all while it is stuck
225waiting. With event loops the thread can service other events until something
226happens on the fd.
227
228### Threads are inexpensive
229
230In the cases you really need threads, you must have them, or fork off another
231process. But if you don't really need them, they bring with them a lot of
232expense, some you may only notice when your code runs on constrained targets
233
234 - threads have an OS-side footprint both as objects and in the scheduler
235
236 - thread context switches are not slow on modern CPUs, but have side effects
237 like cache flushing
238
239 - threads are designed to be blocked for arbitrary amounts of time if you use
240 blocking IO apis like write() or read(). Then how much concurrency is really
241 happening? Since blocked threads just go away silently, it is hard to know
242 when in fact your thread is almost always blocked and not doing useful work.
243
244 - threads require their own stack, which is on embedded is typically suffering
245 from a dedicated worst-case allocation where the headroom is usually idle
246
247 - locking must be handled, and missed locking or lock order bugs found
248
249### But... what about latency if only one thing happens at a time?
250
251 - Typically, at CPU speeds, nothing is happening at any given time on most
252 systems, the event loop is spending most of its time in the event wait
253 asleep at 0% cpu.
254
255 - The POSIX sockets layer is disjoint from the actual network device driver.
256 It means that once you hand off the packet to the networking stack, the POSIX
257 api just returns and leaves the rest of the scheduling, retries etc to the
258 networking stack and device, descriptor queuing is driven by interrupts in
259 the driver part completely unaffected by the event loop part.
260
261 - Passing data around via POSIX apis between the user code and the networking
262 stack tends to return almost immediately since its onward path is managed
263 later in another, usually interrupt, context.
264
265 - So long as enough packets-worth of data are in the network stack ready to be
266 handed to descriptors, actual throughput is completely insensitive to jitter
267 or latency at the application event loop
268
269 - The network device itself is inherently serializing packets, it can only send
270 one thing at a time. The networking stack locking also introduces hidden
271 serialization by blocking multiple threads.
272
273 - Many user systems are decoupled like the network stack and POSIX... the user
274 event loop and its latencies do not affect backend processes occurring in
275 interrupt or internal thread or other process contexts
276
277## Conclusion
278
279Event loops have been around for a very long time and are in wide use today due
280to their advantages. Working with them successfully requires understand how to
281use them and why they have the advantages and restrictions they do.
282
283The best results come from all the participants joining the same loop directly.
284Using a common event library in the participating codebases allows completely
285different code can call each other's apis safely without locking.
286
README.fault-injection.md
1# `lws_fi` Fault Injection
2
3Most efforts during development go towards trying to make the system do what
4it is supposed to do during normal operation.
5
6But to provide reliable quality there's a need to not just test the code paths
7for normal operation, but also to be able to easily confirm that they act
8correctly under various fault conditions that may be difficult to arrange at
9test-time. It's otherwise very easy for error conditions that are low
10probability to be overlooked and turn out to do the wrong thing, eg, try to
11clean up things they had not actually initialized, or forget to free things etc.
12
13Code handling the operational failures we want to check may be anywhere,
14including during early initialization or in user code before lws intialization.
15
16To help with this lws has a `LWS_WITH_SYS_FAULT_INJECTION` build option that
17provides a simple but powerful api for targeted fault injection in any lws or
18user code, and provides a wide range of well-known internal faults inside lws
19you can trigger from outside.
20
21## Fault contexts and faults
22
23The basic idea is objects in the user code can choose to initialize "fault
24contexts" inside objects, that list named, well-known "faults" that the code
25supoorts and that the user wants to inject.
26
27Although these "fault contexts" can be embedded in objects directly at object
28creation time, eg, for lws in the lws_context creation info struct, or the
29client connection info struct, or Secure Stream info struct, it's usually
30inconvenient to pass the desired faults directly deep into the code and attach
31them at creation time. Eg, if you want to cause a fault in a wsi instantiated
32by a Secure Stream, that is internal lws code one step removed from the Secure
33Stream object creation making it difficult to arrange.
34
35For that reason, faults have a targeted inheritance scheme using namespace
36paths, it's usually enough to just list the faults you want at context creation
37time and they will be filter down to the internal objects you want to target
38when they are created later.
39
40![Fault Injection Overview](../doc-assets/fault-injection.png)
41
42A fault injection request is made in `lws_fi_t` objects, specifying the
43fault name and whether, and how often to inject the fault.
44
45The "fault context" objects `lws_fi_ctx_t` embedded in the creation info
46structs are linked-lists of `lws_fi_t` objects. When Fault Injection is enabled
47at build-time, the key system objects like the `lws_context`, `lws_vhost`, `wsi`
48and Secure Stream handles / SSPC handles contain their own `lws_fi_ctx_t` lists
49that may have any number of `lws_fi_t` added to them.
50
51When downstream objects are created, eg, when an lws_context creates a Secure
52Stream, in addition to using any faults provided directly in the SS info,
53the lws_context faults are consulted to see if any relate to that streamtype
54and should be applied.
55
56Although faults can be added to objects at creation, it is far more convenient
57to just pass a list of faults you want into the lws_context and have the
58objects later match them using namespacing, described later.
59
60## Integrating fault injection conditionals into code in private lws code
61
62A simple query api `lws_fi(fi_ctx, "name")` is provided that returns 0 if no
63fault to be injected, or 1 if the fault should be synthesized. If there is no
64rule matching "name", the answer is always to not inject a fault, ie, returns 0.
65
66Similarly for convenience if FAULT_INJECTION is disabled at build, the `lws_fi()`
67call always returns the constant `0`.
68
69By default then just enabling Fault Injection at build does not have any impact
70on code operation since the user must also add the fault injection rules he
71wants to the objects's Fault Injection context.
72
73## Integrating fault injection conditionals into user code with public apis
74
75These public apis query the fault context in a wsi, lws_context, ss handle, or
76sspc handle (client side of proxy) to find any matching rule, if so they return
771 if the conditions (eg, probability) are met and the fault should be injected.
78
79These allow user code to use the whole Fault Injection system without having to
80understand anything except the common object like a wsi they want to query and
81the name of the fault rule they are checking.
82
83|FI context owner|Public API|
84|---|---|
85|lws_context|`int lws_fi_user_context_fi(struct lws_context *ctx, const char *rule)`|
86|wsi|`int lws_fi_user_wsi_fi(struct lws *wsi, const char *rule)`|
87|ss handle|`int lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *rule)`|
88|sspc handle|`int lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *rule)`|
89
90For example, the minimal-http-client user code example contains this in its
91ESTABLISHED callback
92
93```
94 if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est"))
95 return -1;
96```
97
98which can be triggered by running it with
99
100`lws-minimal-http-client --fault-injection 'wsi/user_reject_at_est'`, causing
101
102```
103...
104[2021/03/11 13:41:05:2769] U: Connected to 46.105.127.147, http response: 200
105[2021/03/11 13:41:05:2776] W: lws_fi: Injecting fault unk->user_reject_at_est
106[2021/03/11 13:41:05:2789] E: CLIENT_CONNECTION_ERROR: HS: disallowed at ESTABLISHED
107...
108```
109
110When `LWS_WITH_SYS_FAULT_INJECTION` is disabled, these public apis become
111preprocessor defines to `(0)`, so the related code is removed by the compiler.
112
113## Types of fault injection "when" strategy
114
115The api keeps track of each time the context was asked and uses this information
116to drive the decision about when to say yes, according to the type of rule
117
118|Injection rule type|Description|
119|---|---|
120|`LWSFI_ALWAYS`|Unconditionally inject the fault|
121|`LWSFI_DETERMINISTIC`|after `pre` times without the fault, the next `count` times exhibit the fault`|
122|`LWSFI_PROBABILISTIC`|exhibit a fault `pre` percentage of the time|
123|`LWSFI_PATTERN`|Reference `pre` bits pointed to by `pattern` and fault if the bit set, pointing to static array|
124|`LWSFI_PATTERN_ALLOC`|Reference `pre` bits pointed to by `pattern` and fault if the bit set, pointing to allocated array, freed when fault goes out of scope|
125
126Probabalistic choices are sourced from a PRNG with a seed set in the context
127creation info Fault Injection Context. By default the lws helper
128`lws_cmdline_option_handle_builtin()` sets this to the time in us, but it can
129be overridden using `--fault-seed <decimal>`, and the effective PRNG seed is
130logged when the commandline options are initially parsed.
131
132## Addings Fault Injection Rules to `lws_fi_ctx_t`
133
134Typically the lws_context is used as the central, toplevel place to define
135faults. This is done by adding prepared `lws_fi_t` objects on the stack one by
136one to the context creation info struct's `.fic` member, using
137`lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);`, this will allocate and copy
138the provided `fi` into the allocation, and attach it to the `lws_fi_ctx_t` list.
139
140When the context (or other object using the same scheme) is created, it imports
141all the faults from the info structure `.fic` and takes ownership of them,
142leaving the info `.fic` empty and ready to go out of scope.
143
144## Passing in fault injection rules
145
146A key requirement is that Fault Injection rules must be availble to the code
147creating an object before the object has been created. This is why the user
148code prepares a Fault Injection context listing his rules in the creation info
149struct, rather than waiting for the object to be created and then attach Fault
150Injection rules... it's too late then to test faults during the creation.
151
152## Directly applying fault contexts
153
154You can pass in a Fault Injection context prepared with lws_fi_t added to it
155when creating the following kinds of objects
156
157|Object being created|info struct|Fault injection Context member|
158|---|---|---|
159|lws context|struct lws_context_creation_info|`fic`|
160|vhost|struct lws_context_creation_info|`fic`|
161|Secure Stream|struct lws_ss_info|`fic`|
162|client wsi|struct lws_client_connect_info|`fic`|
163
164However typically the approach is just provide a list of faults at context
165creation time, and let the objects match and inherit using namespacing,
166described next.
167
168## Using the namespace to target specific instances
169
170Lws objects created by the user can directly have a Fault Injection context
171attached to them at creation time, so the fault injection objects directly
172relate to the object.
173
174But in other common scenarios, there is no direct visibility of the object that
175we want to trigger faults in, it may not exist until some time later. Eg, we
176want to trigger faults in the listen socket of a vhost. To allow this, the
177fault names can be structured with a /path/ type namespace so objects created
178later can inherit faults.
179
180Notice that if you are directly creating the vhost, Secure Stream or wsi, you
181can directly attach the subrule yourself without the namespacing needed. The
182namespacing is used when you have access to a higher level object at creation-
183time, like the lws_context, and it will itself create the object you want to
184target without your having any direct access to it.
185
186|namespace form|effect|
187|---|---|
188|**vh=myvhost/**subrule|subrule is inherited by the vhost named "myvhost" when it is created|
189|**vh/**subrule|subrule is inherited by any vhost when it is created|
190|**ss=mystream/**subrule|subrule is inherited by SS of streamtype "mystream" (also covers SSPC / proxy client)|
191|**ss/**subrule|subrule is inherited by all SS of any streamtype (also covers SSPC / proxy client)|
192|**wsi=myname/**subrule|subrule is inherited by client wsi created with `info->fi_wsi_name` "myname"|
193|**wsi/**subrule|subrule is inherited by any wsi|
194
195Namespaces can be combined, for example `vh=myvhost/wsi/listenskt` will set the
196`listenskt` fault on wsi created by the server vhost "myvhost", ie, it will
197cause the listen socket for the vhost to error out on creation.
198
199In the case of wsi migration when it's the network connection wsi on an h2
200connection that is migrated to be SID 1, the attached faults also migrate.
201
202Here is which Fault Injection Contexts each type of object inherits matching
203Fault Injection rules from:
204
205|Object type|Initialized with|Inherit matching faults from|
206|---|---|---|
207|context|`struct lws_context_creation_info` .fic|-|
208|vhost|`struct lws_context_creation_info` .fic|context FIC|
209|client wsi|`struct lws_client_connect_info` .fic|context FIC, vhost FIC|
210|ss / sspc|`lws_ss_info_t` .fic|context FIC|
211|ss / sspc wsi|-|context FIC, vhost FIC, ss / sspc .fic|
212
213Since everything can be reached from the lws_context fault context, directly or
214by additional inheritence, and that's the most convenient to set from the
215outside, that's typically the original source of all injected faults.
216
217## Integration with minimal examples
218
219All the minimal examples that use the `lws_cmdline_option_handle_builtin()` api
220can take an additional `--fault-injection "...,..."` switch, which automatically
221parses the comma-separated list in the argument to add faults with the given
222name to the lws_context. For example,
223
224`lws-minimal-http-client --fault-injection "wsi/dnsfail"`
225
226will force all wsi dns lookups to fail for that run of the example.
227
228### Specifying when to inject the fault
229
230By default, if you just give the name part, if the namespace is absent or
231matches an object, the fault will be injected every time. It's also possible
232to make the fault inject itself at a random probability, or in a cyclic pattern,
233by giving additional information in brackets, eg
234
235|Syntax|Used with|Meaning|
236|---|---|---|
237|`wsi/thefault`|lws_fi()|Inject the fault every time|
238|`wsi/thefault(10%)`|lws_fi()|Randomly inject the fault at 10% probability|
239|`wsi/thefault(.............X.X)`|lws_fi()|Inject the fault on the 14th and 16th try, every 16 tries|
240|`wsi/thefault2(123..456)`|lws_fi_range()|Pick a number between 123 and 456|
241
242You must quote the strings containing these symbols, since they may otherwise be
243interpreted by your shell.
244
245The last example above does not decide whether to inject the fault via `lws_fi()`
246like the others. Instead you can use it via `lws_fi_range()` as part of the
247fault processing, on a secondary fault injection name. For example you may have
248a fault `myfault` you use with `lws_fi()` to decide when to inject the fault,
249and then a second, related fault name `myfault_delay` to allow you to add code
250to delay the fault action by some random amount of ms within an externally-
251given range. You can get a pseudo-random number within the externally-given
252range by calling `lws_fi_range()` on `myfault_delay`, and control the whole
253thing by giving, eg, `"myfault(10%),myfault_delay(123..456)"`
254
255## Well-known fault names in lws
256
257|Scope|Namespc|Name|Fault effect|
258|---|---|---|---|
259|context||`ctx_createfail1`|Fail context creation immediately at entry|
260|context||`ctx_createfail_plugin_init`|Fail context creation as if a plugin init failed (if plugins enabled)|
261|context||`ctx_createfail_evlib_plugin`|Fail context creation due to event lib plugin failed init (if evlib plugins enabled)|
262|context||`ctx_createfail_evlib_sel`|Fail context creation due to unable to select event lib|
263|context||`ctx_createfail_oom_ctx`|Fail context creation due to OOM on context object|
264|context||`ctx_createfail_privdrop`|Fail context creation due to failure dropping privileges|
265|context||`ctx_createfail_maxfds`|Fail context creation due to unable to determine process fd limit|
266|context||`ctx_createfail_oom_fds`|Fail context creation due to OOM on fds table|
267|context||`ctx_createfail_plat_init`|Fail context creation due to platform init failed|
268|context||`ctx_createfail_evlib_init`|Fail context creation due to event lib init failed|
269|context||`ctx_createfail_evlib_pt`|Fail context creation due to event lib pt init failed|
270|context||`ctx_createfail_sys_vh`|Fail context creation due to system vhost creation failed|
271|context||`ctx_createfail_sys_vh_init`|Fail context creaton due to system vhost init failed|
272|context||`ctx_createfail_def_vh`|Fail context creation due to default vhost creation failed|
273|context||`ctx_createfail_ss_pol1`|Fail context creation due to ss policy parse start failed (if policy enabled)|
274|context||`ctx_createfail_ss_pol2`|Fail context creation due to ss policy parse failed (if policy enabled)|
275|context||`ctx_createfail_ss_pol3`|Fail context creation due to ss policy set failed (if policy enabled)|
276|context||`cache_createfail`|Fail `lws_cache` creation due to OOM|
277|context||`cache_lookup_oom`|Fail `lws_cache` lookup due to OOM|
278|vhost|`vh`|`vh_create_oom`|Fail vh creation on vh object alloc OOM|
279|vhost|`vh`|`vh_create_oom`|Fail vh creation on vh object alloc OOM|
280|vhost|`vh`|`vh_create_pcols_oom`|Fail vh creation at protocols alloc OOM|
281|vhost|`vh`|`vh_create_access_log_open_fail`|Fail vh creation due to unable to open access log (LWS_WITH_ACCESS_LOG)|
282|vhost|`vh`|`vh_create_ssl_srv`|Fail server ssl_ctx init|
283|vhost|`vh`|`vh_create_ssl_cli`|Fail client ssl_ctx init|
284|vhost|`vh`|`vh_create_srv_init`|Fail server init|
285|vhost|`vh`|`vh_create_protocol_init`|Fail late protocol init (for late vhost creation)|
286|srv vhost|`vh=xxx/wsi`|`listenskt`|Causes `socket()` allocation for vhost listen socket to fail|
287|cli wsi|`wsi`|`dnsfail`|Sync: `getaddrinfo()` is not called and a EAI_FAIL return synthesized, Async: request not started and immediate fail synthesized|
288|cli wsi|`wsi`|`sendfail`|Attempts to send data on the wsi socket fail|
289|cli wsi|`wsi`|`connfail`|Attempts to connect on the wsi socket fail|
290|cli wsi|`wsi`|`createfail`|Creating the client wsi itself fails|
291|udp wsi|`wsi`|`udp_rx_loss`|Drop UDP RX that was actually received, useful with probabalistic mode|
292|udp wsi|`wsi`|`udp_tx_loss`|Drop UDP TX so that it's not actually sent, useful with probabalistic mode|
293|srv ss|`ss`|`ss_srv_vh_fail`|Secure Streams Server vhost creation forced to fail|
294|cli ss|`ss`|`ss_no_streamtype_policy`|The policy for the streamtype is made to seem as if it is missing|
295|sspc|`ss`|`sspc_fail_on_linkup`|Reject the connection to the proxy when we hear it has succeeded, it will provoke endless retries|
296|sspc|`ss`|`sspc_fake_rxparse_disconnect_me`|Force client-proxy link parse to seem to ask to be disconnected, it will provoke endless retries|
297|sspc|`ss`|`sspc_fake_rxparse_destroy_me`|Force client-proxy link parse to seem to ask to destroy the SS, it will destroy the SS cleanly|
298|sspc|`ss`|`sspc_link_write_fail`|Force write on the link to fail, it will provoke endless retries|
299|sspc|`ss`|`sspc_create_oom`|Cause the sspc handle allocation to fail as if OOM at creation time|
300|sspc|`ss`|`sspc_fail_metadata_set`|Cause the metadata allocation to fail|
301|sspc|`ss`|`sspc_rx_fake_destroy_me`|Make it seem that client's user code *rx() returned DESTROY_ME|
302|sspc|`ss`|`sspc_rx_metadata_oom`|Cause metadata from proxy allocation to fail|
303|ssproxy|`ss`|`ssproxy_dsh_create_oom`|Cause proxy's creation of DSH to fail|
304|ssproxy|`ss`|`ssproxy_dsh_rx_queue_oom`|Cause proxy's allocation in the onward SS->P[->C] DSH rx direction to fail as if OOM, this causes the onward connection to disconnect|
305|ssproxy|`wsi`|`ssproxy_client_adopt_oom`|Cause proxy to be unable to allocate for new client - proxy link connection object|
306|ssproxy|`wsi`|`ssproxy_client_write_fail`|Cause proxy write to client to fail|
307|ssproxy|`wsi`|`sspc_dsh_ss2p_oom`|Cause ss->proxy dsh allocation to fail|
308|ssproxy|`ss`|`ssproxy_onward_conn_fail`|Act as if proxy onward client connection failed immediately|
309|ssproxy|`ss`|`ssproxy_dsh_c2p_pay_oom`|Cause proxy's DSH alloc for C->P payload to fail|
310|ss|`ss`|`ss_create_smd`|SMD: ss creation smd registration fail|
311|ss|`ss`|`ss_create_vhost`|Server: ss creation acts like no vhost matching typename (only for `!vhost`)|
312|ss|`ss`|`ss_create_pcol`|Server: ss creation acts like no protocol given in policy|
313|ss|`ss`|`ss_srv_vh_fail`|Server: ss creation acts like unable to create vhost|
314|ss|`ss`|`ss_create_destroy_me`|ss creation acts like CREATING state returned DESTROY_ME|
315|ss|`ss`|`ss_create_no_ts`|Static Policy: ss creation acts like no trust store|
316|ss|`ss`|`ss_create_smd_1`|SMD: ss creation acts like CONNECTING said DESTROY_ME|
317|ss|`ss`|`ss_create_smd_2`|SMD: ss creation acts like CONNECTED said DESTROY_ME|
318|ss|`ss`|`ss_create_conn`|Nailed up: ss creation client connection fails with DESTROY_ME|
319|wsi|`wsi`|`timedclose`|(see next) Cause wsi to close after some time|
320|wsi|`wsi`|`timedclose_ms`|Range of ms for timedclose (eg, "timedclose_ms(10..250)"|
321
322## Well-known namespace targets
323
324Namespaces can be used to target these more precisely, for example even though
325we are only passing the faults we want inject at the lws_context, we can use
326the namespace "paths" to target only the wsis created by other things.
327
328To target wsis from SS-based connections, you can use `ss=stream_type_name/`,
329eg for captive portal detection, to have it unable to find its policy entry:
330
331`ss=captive_portal_detect/ss_no_streamtype_policy` (disables CPD from operating)
332
333...to force it to fail to resolve the server DNS:
334
335`ss=captive_portal_detect/wsi/dnsfail` (this makes CPD feel there is no internet)
336
337...to target the connection part of the captive portal testing instead:
338
339`ss=captive_portal_detect/wsi/connfail` (this also makes CPD feel there is no internet)
340
341### Well-known internal wsi type names
342
343Wsi created for internal features like Async DNS processing can also be targeted
344
345|wsi target|Meaning|
346|---|---|
347|`wsi=asyncdns/`|UDP wsi used by lws Async DNS support to talk to DNS servers|
348|`wsi=dhcpc/`|UDP wsi used by lws DHCP Client|
349|`wsi=ntpclient/`|UDP wsi used by lws NTP Client|
350
351For example, passing in at lws_context level `wsi=asyncdns/udp_tx_loss`
352will force async dns to be unable to resolve anything since its UDP tx is
353being suppressed.
354
355At client connection creation time, user code can also specify their own names
356to match on these `wsi=xxx/` namespace parts, so the faults only apply to
357specific wsi they are creating themselves later. This is done by setting the
358client creation info struct `.fi_wsi_name` to the string "xxx".
359
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-cache.md
1# Client http cookie storage, caching and application
2
3lws now has the option to store incoming cookies in a Netscape cookie jar file
4persistently, and auto-apply relevant cookies to future outgoing requests.
5
6A L1 heap cache of recent cookies is maintained, along with LRU tracking and
7removal of entries from cache and the cookie jar file according to their cookie
8expiry time.
9
10The cookie handling is off by default per-connection for backwards compatibility
11and to avoid unexpected tracking.
12
13## Enabling at build-time
14
15Make sure `-DLWS_WITH_CACHE_NSCOOKIEJAR=1` is enabled at cmake (it is on by
16default now).
17
18## Configuring the cookie cache
19
20The cookie cache is managed through context creation info struct members.
21
22|member|function|
23|---|---|
24|`.http_nsc_filepath`|Filepath to store the cookie jar file at|
25|`.http_nsc_heap_max_footprint`|0, or Max size in bytes for the L1 heap cache|
26|`.http_nsc_heap_max_items`|0, or Max number of cookies allowed in L1 heap cache|
27|`.http_nsc_heap_max_payload`|0, or Largest cookie we are willing to handle|
28
29## Enabling per-connection in lws
30
31To enable it on connections at lws level, add the flag `LCCSCF_CACHE_COOKIES` to
32the client connection info struct `.ssl_connection` flags.
33
34## Enabling per-connection in Secure Streams policy
35
36To enable it on Secure Streams, in the streamtype policy add
37
38```
39 "http_cookies": true
40```
41
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.http_parser.md
1# Notes on http parser corner cases
2
3## Dealing with %00
4
5%00 is considered illegal in
6
7 - the path part of the URL. A lot of user code handles it as a NUL terminated string,
8 even though the header get apis are based around length. So it is disallowed to
9 avoid ambiguity.
10
11 - the name part of a urlarg, like ?name=value
12
13%00 is valid in
14
15 - the value part of a urlarg, like ?name=value
16
17When the parser sees %00 where it is not allowed, it simply drops the connection.
18
19## Note on proper urlarg handling
20
21urlargs are allowed to contain non-NUL terminated binary. So it is important to
22use the length-based urlarg apis
23
24 - `lws_hdr_copy_fragment()`
25 - `lws_get_urlarg_by_name_safe()`
26
27The non-length based urlarg api
28
29 - `lws_get_urlarg_by_name()`
30
31...is soft-deprecated, it's still allowed but it will be fooled by the first %00
32seen in the argument into truncating the argument. Use `lws_get_urlarg_by_name_safe()`
33instead.
34
README.jit-trust.md
1# JIT trust
2
3![JIT Trust logo](../doc-assets/jit-trust-logo.png)
4
5## Background
6
7Most systems using openssl rely on a system trust bundle that openssl was
8compiled to load at library init. This is a bit expensive, since it
9instantiates over 120 CA X.509 certs, but most modern Linux systems don't really
10notice the permanent use of 1MB or so of heap from init, the advantage is client
11connections have all the trusted root certs available in memory to perform
12validation.
13
14![Using system trust bundles](../doc-assets/jit-trust-system-trust.png)
15
16For the kind of systems that choose mbedtls, they will typically either be
17burdened by or not even have enough ram to take this approach.
18
19If the device only connects to endpoints that are signed by a specific
20CA, you can just prepare the connection with the known trusted CA, that's
21the approach the examples take. This method should still be used for critical
22connections to the cloud, for example provide the necessary CA cert in the
23Secure Streams policy, or at vhost creation time.
24
25![Using system trust bundles](../doc-assets/jit-trust-single-trust.png)
26
27However if you also have a browser type application that could connect anywhere,
28but you don't have heap spare to preload all the CAs, you need something like
29"JIT trust".
30
31## JIT trust overview
32
33The basic approach is to connect to the server to retrieve its certificates,
34then study the certificates to determine the identity of the missing trusted
35cert we should be trying to validate with.
36
37![JIT Trust overview](../doc-assets/jit-trust-overview.png)
38
39We attempt to get the trusted cert from some local or remote store, and retry
40the connection having instantiated the missing CA cert as trusted for that
41connection, if it is one that we do actually trust. If it lies about what CA it
42needs to validate, or we do not trust the one it asks for, subsequent
43connections will fail.
44
45If it asked for a trusted CA that we trust, and the relationship was valid, the
46tls negotiation should then complete successfully, and we can cache the CA cert
47and the host -> CA cert pre-trust requirement so future connections can work
48first time.
49
50## Subject Key Id and Authority Key Id
51
52All of the certificates publish a unique-enough personal "Subject Key ID" or
53SKID blob. These are typically 20-byte hashes based on the cert public key.
54
55When a server certificate is issued by the CA, an entry is made first in the
56certificate noting the SKID of the certificate that will be used to sign it,
57in an "Authority Key ID", or AKID, extension. The certificate is then signed by
58the parent certificate private key to prove it was issued by the real owner of
59the CA or intermediate certificate.
60
61![X.509 validation paths](../doc-assets/jit-trust-paths.png)
62
63Basically this AKID on a certificate is guiding the validator with
64information about which certificate it claims is next in the chain of trust
65leading back to a trusted CA. Lying about it doesn't help an attacker,
66because we're only using the AKID to get the CA certificate and then try to do
67the full signature check using it, if it's not really signed by the AKID cert it
68told, or anything else wrong, the actual validation will just fail.
69
70A chain that terminates in a CA certificate is complete, and can undergo full
71validation using the tls library.
72
73## Converting the Mozilla trust bundle for JIT trust
74
75Lws provides a bash script `./scripts/mozilla-trust-gen.sh` that can fetch the
76latest Mozilla CA trust bundle for certs usable for tls validation, and convert
77it to three different forms to allow maintaining the trust bundle in different
78ways for different kinds of device to consume.
79
80 - as a webroot directory, so you can server trusted DERs, with
81 symlink indexes to the CA certs by SKID and issuer/serial
82
83 - as an atomic binary blob, currently about 143KB, with structure
84 at the start pointing to DER certs and indexes inside
85
86 - a C-compiler friendly `uint8_t` array version of the blob,
87 so it can be compiled into .rodata directly if necessary.
88
89Currently there are 128 certs in the trust bundle, and the whole blob is about
90143KB uncompressed.
91
92## Considerations about maintaining the trust blob
93
94Mozilla update their trust bundle at intervals, and there have been at least
95three cases where they have removed or distrusted CAs from it by their own
96decision, because they have issued dangerous certificates, (like one for `*`
97that will validate anything at all). Certifacte owners may also revoke their
98own certificates for any reason and issue replacements.
99
100The certs in the trust bundle expire, currently 10/128 will expire within 3
101years and 50/128 over the next 10 years. So new and replacement certificates
102are also being added at intervals.
103
104Part of using the trust bundle is building in some way to update what is trusted
105over the lifetime of the device, which may exceed 10 years.
106
107Depending on the device, it may not be any problem to keep the trust blob in the
108firmware, and update the firmware ongoing every few months. So you could build
109it into the firmware using the C array include file (the minimal example takes
110this approach).
111
112Another device may have difficulty updating the firmware outside of emergencies,
113it could keep the trust blob in a separate area and update it separately.
114Having it as a single blob makes it easy to fetch and update.
115
116Finally constrained devices, say in ESP32 class, may not have space or desire
117to store the trust blob in the device at all, it could query a remote server on
118demand to check for any trusted CA matching a given AKID and retrieve and cache
119it in volatile ram. This would use the webroot produced by the script, via tls
120and a fixed CA cert outside this system.
121
122## Format of the JIT trust blob
123
124The trust blob layout is currently
125
126```
12700: 54 42 4c 42 Magic "TBLB"
12804: 00 01 MSB-first trust blob layout version
12906: XX XX MSB-first count of certificates
13008: XX XX XX XX MSB-first trust blob generation unix time
1310c: XX XX XX XX MSB-first offset from blob start of cert length table
13210: XX XX XX XX MSB-first offset from blob start of SKID length table
13314: XX XX XX XX MSB-first offset from blob start of SKID table
13418: XX XX XX XX MSB-first total blob length
135
1361c: XX .. XX DER certs (start at +0x1c)
137 : XX .. XX DER cert length table (MSB-first 16-bit per cert)
138 : XX .. XX SKID length table (8-bit per cert)
139 : XX .. XX SKID table (variable per cert)
140```
141
142## Enabling JIT Trust
143
144```
145$ cmake .. -DLWS_WITH_TLS_JIT_TRUST=1
146```
147
148## Minimal example for JIT Trust
149
150`minimal-examples/http-client/minimal-http-client-jit-trust` is built if JIT
151Trust is enabled at cmake and `-DLWS_WITH_MINIMAL_EXAMPLES=1`. This is based on
152minimal-http-client, except the loading of the system trust bundle is defeated,
153so by default it does not trust anything and cannot complete any tls connection.
154It includes the mozilla trust blob as a header file when built.
155
156It tries to do an http client connection twice, the first time fails but JIT
157Trust determines which trusted CA cert is missing, retreives it from the trust
158blob and creates the necessary temporary vhost with the correct CA cert(s)
159trusted. On the next retry, the connection succeeds.
160
161## Processing of x509 AKID and SKIDs
162
163We study each x509 cert sent by the server in turn. We parse out the SKID and
164AKID on each one and stash them (up to 4 deep).
165
166After the initial validation fails due to lack of any trusted CA, lws has
167collected all the AKID and SKIDs that were in certs sent by the server. Since
168these may be sent in any order, may be malicious, and may even contain the
169(untrusted) root CA, they are sorted into a trust path using the AKID and SKID
170relationships.
171
172To cover cross-signing and cases where the root cert(s) were wrongly sent by
173a misconfigured server, all of the AKIDs in the stash are queried against the
174trusted CA store. In cross-signing, multiple intermediates are provided with
175the same SKID, that all match the server certificate AKID parent. Since we
176might meet certificates that trust multiple valid CAs that can validate the
177certificate, we support up to three CA certs imported.
178
179A user `lws_system_ops` handler performs the query, so it can consist of any
180kind of backing store or remote lookup. Helpers are provided to query the JIT
181trust mozilla blob, so the system helper is small in the typical case, just
182calling lws helpers.
183
184The results (up to three CA certs to account for cross-signing scenarios) are
185collected and a 1hr TTL cache entry made for the hostname and the SKIDs of the
186matched CAs, if there is no existing JIT vhost with its tls context configured
187with the needed trusted CAs, one is created.
188
189When the connection is retried, lws checks the cache for the hostname having
190a binding to an existing JIT vhost, if that exists the connection proceeds
191bound to that. If there is a cache entry but no JIT vhost, one is created using
192the information in the cache entry.
193
194## Efficiency considerations
195
196From cold, the JIT Trust flow is
197
1981. A sacrificial connection is made to get the server certs
1992. Query the JIT Trust database for AKIDs mentioned in the certs (this may be
200done asynchronously)
2013. Create a temporary vhost with the appropriate trusted certs enabled in it,
202 and add an entry in the cache for this hostname to the SKIDs of the CAs
203 enabled on this temporary vhost
2044. Retry, querying the cache to bind the connection to the right temporary vhost
205
206An lws_cache in heap is maintained so step 1 can be skipped while hostname->
207SKID items exist in the cache. If the items expire or are evicted, it just
208means we have to do step 1 again.
209
210For a short time, the vhost created in step 3 is allowed to exist when idle, ie
211when no connections are actively using it. In the case the vhost exists and
212the cache entry exists for the hostname, the connection can proceed successfully
213right away without steps 1 through 3.
214
215## APIs related to JIT Trust
216
217Systems that support JIT trust define an `lws_system_ops` callback
218that does whatever the system needs to do for attempting to acquire
219a trusted cert with a specified SKID or issuer/serial.
220
221```
222int (*jit_trust_query)(struct lws_context *cx, const uint8_t *skid, size_t skid_len, void *got_opaque);
223```
224
225The ops handler doesn't have to find the trusted cert immediately before
226returning, it is OK starting the process and later if successful calling a
227helper `lws_tls_jit_trust_got_cert_cb()` with the `got_opaque` from the query.
228This will cache the CA cert so it's available at the next connection retry for
229preloading.
230
231An helper suitable for `ops->jit_trust_query` using trust blob lookup in .rodata
232is provided in `lws_tls_jit_trust_blob_queury_skid()`, the callback above should
233be called with its results as shown in the minimal example.
234
235## Runtime tuning for JIT Trust
236
237The context creation info struct has a couple of runtime-tunable settings
238related to JIT Trust.
239
240`.jitt_cache_max_footprint`: default 0 means no limit, otherwise the hostname->
241SKID cache is kept below this many bytes in heap, by evicting LRU entries.
242
243`.vh_idle_grace_ms`: default 0 means 5000ms, otherwise sets the length of time
244a JIT Trust vhost is allowed to exist when it has no connections using it.
245Notice that, eg, h2 connections have their own grace period when they become
246idle, to optimize reuse, this period does not start until any h2 network
247connection bound to the vhost has really closed.
248
249## Considerations around http redirects
250
251HTTP redirects are transactions that tell the client to go somewhere else to
252continue, typically a 301 response with a Location: header explaining where to
253go.
254
255JIT Trust supports redirects to hosts with the same or different trust
256requirements, each step in the redirect is treated as a new connection that will
257fail, try to create a vhost with the right trust and work on the retry.
258
259Lws rejects by default protocol downgrades (https -> http) on redirects, the
260example used a context option `LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS` to
261override this.
262
263## Works out of the box on recent mbedtls and openssl
264
265No modifications are needed to either tls library.
266
267## Compatibility Testing
268
269A list of the top 100 sites each from the US and the ROW were combined to
270produce 156 unqiue domain names [1]
271
272The Mbedtls build of JIT trust minimal example was run against each of these
273doing a GET on path `/` and restricted to h1 (`--server xxx --h1`). In some
274cases, the server at the base domain name is broken or down, as verified using
275ssllabs.com as a second opinion. These domains only resolve properly using
276`www.` prefix.
277
278In some cases the sites check the user agent and return a 4xx, these are taken
279as success for this test, since there was no problem at the tls layer.
280
281|site|h1|h2|comment|
282|---|---|---|---|
283|adobe.com|✓|✓||
284|allegro.pl|✓|✓||
285|allrecipes.com|✓|✓||
286|amazon.co.jp|✓|✓||
287|amazon.com|✓|✓||
288|amazon.co.uk|✓|✓||
289|amazon.de|✓|✓||
290|amazon.fr|✓|✓||
291|amazon.in|✓|✓||
292|amazon.it|✓|✓||
293|aol.com|✓|✓||
294|apartments.com|✓|✓||
295|apple.com|✓|✓||
296|ar.wikipedia.org|✓|✓||
297|att.com|✓|✓||
298|bankofamerica.com|✓|✓||
299|bbc.com|✓|✓||
300|bbc.co.uk|✓|✓||
301|bestbuy.com|✕|✓|redirect-> `www.` then h1: timeout, h2: 403 forbidden... geolocated?|
302|booking.com|✓|✓||
303|britannica.com|✓|✓||
304|bulbagarden.net|✓|✓||
305|businessinsider.com|✓|✓||
306|ca.gov|✓|✓||
307|caixa.gov.br|✕|✕|TLS trust works fine. Continuously redirects to self... sends set-cookie that we don't return yet|
308|capitalone.com|✓|✓||
309|cbssports.com|✓|✓||
310|cdc.gov|✓|✓||
311|chase.com|✓|✓||
312|chrome.google.com|✓|✓||
313|cnbc.com|✓|✓||
314|cnet.com|✓|✓||
315|cnn.com|✓|✓||
316|cookpad.com|✓|✓||
317|costco.com|✕|✓|TLS trust works fine. But with or without `www.` server does not reply within 15s on h1, sends 403 OK on h2... Curl acts the same as we do, firefox works... geolocated?||
318|craigslist.org|✓|✓||
319|dailymotion.com|✓|✓||
320|de.wikipedia.org|✓|✓||
321|dictionary.com|✓|✓||
322|ebay.com|✓|✓||
323|ebay.co.uk|✓|✓||
324|en.wikipedia.org|✓|✓||
325|epicgames.com|✓|✓||
326|espn.com|✓|✓||
327|es.wikipedia.org|✓|✓||
328|etsy.com|✓|✓||
329|expedia.com|✓|✓||
330|facebook.com|✓|✓||
331|fandom.com|✓|✓||
332|fedex.com|✓|✓||
333|finance.yahoo.com|✓|✓||
334|www.foodnetwork.com|✓|✓|`www.` served correctly, base domain is misconfigured with expired cert, confirmed with ssllabs + curl|
335|forbes.com|✓|✓||
336|foxnews.com|✓|✓||
337|fr.wikipedia.org|✓|✓||
338|gamepedia.com|✓|✓||
339|genius.com|✓|✓||
340|glassdoor.com|✓|✓||
341|globo.com|✓|✓||
342|google.com|✓|✓||
343|healthline.com|✓|✓||
344|homedepot.com|✓|✓||
345|hulu.com|✓|✓||
346|hurriyet.com.tr|✓|✓||
347|id.wikipedia.org|✓|✓||
348|ign.com|✓|✓||
349|ikea.com|✓|✓|`www.` served correctly, base domain is misconfigured with nonresponsive server, confirmed with ssllabs|
350|ilovepdf.com|✓|✓||
351|imdb.com|✓|✓||
352|indeed.com|✓|✓||
353|indiatimes.com|✓|✓||
354|instagram.com|✓|✓||
355|investopedia.com|✓|✓||
356|irs.gov|✓|✓||
357|it.wikipedia.org|✓|✓||
358|ivi.ru|✓|✓||
359|ja.wikipedia.org|✓|✓||
360|kakaku.com|✓|✓||
361|khanacademy.org|✓|✓||
362|kinopoisk.ru|✓|✓||
363|leboncoin.fr|✓|✓||
364|linkedin.com|✓|✓||
365|live.com|✓|✓||
366|lowes.com|✓|✓||
367|macys.com|✕|✓|TLS trust works fine. Continuously redirects to self... `www.` same, curl acts same but OK if given -b -c, so akami cookie storage issue|
368|mail.ru|✓|✓||
369|mail.yahoo.com|✓|✓||
370|mapquest.com|✓|✓||
371|mayoclinic.org|✓|✓||
372|medicalnewstoday.com|✓|✓||
373|mercadolivre.com.br|✓|✓||
374|merriam-webster.com|✓|✓||
375|microsoft.com|✓|✓||
376|msn.com|✓|✓||
377|namu.wiki|✓|✓||
378|nbcnews.com|✓|✓||
379|netflix.com|✓|✓||
380|nih.gov|✓|✓||
381|nl.wikipedia.org|✓|✓||
382|ny.gov|✓|✓||
383|nytimes.com|✓|✓||
384|ok.ru|✓|✓||
385|onet.pl|✓||
386|orange.fr|✓|✓||
387|paypal.com|✓|✓||
388|pinterest.com|✓|✓||
389|pixiv.net|✓|✓||
390|play.google.com|✓|✓||
391|pl.wikipedia.org|✓|✓||
392|www.programme-tv.net|✓|✓|OK with `www.`, without `www.` TLS trust works fine but server does not reply, same with curl|
393|pt.wikipedia.org|✓|✓||
394|quizlet.com|✓|✓||
395|quora.com|✓|✓|||
396|rakuten.co.jp|✓|✓||
397|realtor.com|✓|✓||
398|reddit.com|✓|✓||
399|reverso.net|✓|✓||
400|roblox.com|✓|✓||
401|rottentomatoes.com|✓|✓||
402|ru.wikipedia.org|✓|✓||
403|sahibinden.com|✓|✓||
404|smallpdf.com|✓|✓||
405|speedtest.net|✓|✓||
406|spotify.com|✓|✓||
407|steampowered.com|✓|✓||
408|target.com|✓|✓||
409|theguardian.com|✓|✓||
410|tripadvisor.com|✓|✓||
411|tr.wikipedia.org|✓|✓||
412|twitch.tv|✓|✓||
413|twitter.com|✓|✓||
414|uol.com.br|✓|✓||
415|ups.com|✓|✓||
416|urbandictionary.com|✓|✓||
417|usatoday.com|✓|✓||
418|usnews.com|✕|✓|TLS trust works fine. Needs `www.` else server doesn't respond in 15s, sends 403 on h2, Curl acts the same, geolocated?|
419|usps.com|✓|✓||
420|verizon.com|✓|✓||
421|vk.com|✓|✓||
422|walmart.com|✓|✓||
423|washingtonpost.com|✓|✓||
424|weather.com|✓|✓||
425|webmd.com|✓|✓||
426|whatsapp.com|✓|✓||
427|wowhead.com|✓|✓||
428|wp.pl|✓|✓||
429|www.gov.uk|✓|✓||
430|xfinity.com|✓|✓||
431|yahoo.co.jp|✓|✓||
432|yahoo.com|✓|✓||
433|yandex.ru|✓|✓||
434|yellowpages.com|✓|✓||
435|yelp.com|✓|✓||
436|youtube.com|✓|✓||
437|zh.wikipedia.org|✓|✓||
438|zillow.com|✓|✓||
439
440[1]
441```
442wget -O- https://ahrefs.com/blog/most-visited-websites/ | grep most-visited-websites-us | \
443 sed -E 's/class="column-2">/|/g' | tr '|' '\n' | \
444 sed 's/<.*//g' | grep -v Domain | grep -v Josh | sort | uniq
445```
446
447
README.json-lejp.md
1# LEJP JSON Stream Parser
2
3|||
4|---|---|---|
5|cmake| `LWS_WITH_LEJP`|
6|Header| ./include/libwebsockets/lws-lejp.h|
7|api-test| ./minimal-examples/api-tests/api-test-lejp/|
8|test app| ./test-apps/test-lejp.c -> libwebsockets-test-lejp|
9
10LEJP is a lightweight JSON stream parser.
11
12The features are:
13
14 - completely immune to input fragmentation, give it any size blocks of JSON as
15 they become available, 1 byte, or 100K at a time give identical parsing
16 results
17 - input chunks discarded as they are parsed, whole JSON never needed in memory
18 - nonrecursive, fixed stack usage of a few dozen bytes
19 - no heap allocations at all, just requires ~500 byte context usually on
20 caller stack
21 - creates callbacks to a user-provided handler as members are parsed out
22 - no payload size limit, supports huge / endless strings bigger than
23 system memory
24 - collates utf-8 text payloads into a 250-byte chunk buffer in the json parser
25 context object for ease of access
26
27## Type handling
28
29LEJP leaves all numbers in text form, they are signalled in different callbacks
30according to int or float, but delivered as text strings in the first
31`ctx->npos` chars of `ctx->buf`.
32
33For numeric types, you would typically use `atoi()` or similar to recover the
34number as a host type.
35
36## Callback reasons
37
38The user callback does not have to handle any callbacks, it only needs to
39process the data for the ones it is interested in.
40
41|Callback reason|JSON structure|Associated data|
42|---|---|---|
43|`LEJPCB_CONSTRUCTED`|Created the parse context||
44|`LEJPCB_DESTRUCTED`|Destroyed the parse context||
45|`LEJPCB_COMPLETE`|The parsing completed OK||
46|`LEJPCB_FAILED`|The parsing failed||
47|`LEJPCB_VAL_TRUE`|boolean true||
48|`LEJPCB_VAL_FALSE`|boolean false||
49|`LEJPCB_VAL_NULL`|explicit NULL||
50|`LEJPCB_PAIR_NAME`|The name part of a JSON `key: value` map pair|`ctx->buf`|
51|`LEJPCB_VAL_STR_START`|A UTF-8 string is starting||
52|`LEJPCB_VAL_STR_CHUNK`|The next string chunk|`ctx->npos` bytes in `ctx->buf`|
53|`LEJPCB_VAL_STR_END`|The last string chunk|`ctx->npos` bytes in `ctx->buf`|
54|`LEJPCB_ARRAY_START`|An array is starting||
55|`LEJPCB_ARRAY_END`|An array has ended||
56|`LEJPCB_OBJECT_START`|A JSON object is starting||
57|`LEJPCB_OBJECT_END`|A JSON object has ended||
58
59## Handling JSON UTF-8 strings
60
61When a string is parsed, an advisory callback of `LECPCB_VAL_STR_START` occurs
62first. No payload is delivered with the START callback.
63
64Payload is collated into `ctx->buf[]`, the valid length is in `ctx->npos`.
65
66For short strings or blobs where the length is known, the whole payload is
67delivered in a single `LECPCB_VAL_STR_END` callback.
68
69For payloads larger than the size of `ctx->buf[]`, `LECPCB_VAL_STR_CHUNK`
70callbacks occur delivering each sequential bufferload.
71
72The last chunk (which may be zero length) is delievered by `LECPCB_VAL_STR_END`.
73
74## Parsing paths
75
76LEJP maintains a "parsing path" in `ctx->path` that represents the context of
77the callback events. As a convenience, at LEJP context creation time, you can
78pass in an array of path strings you want to match on, and have any match
79checkable in the callback using `ctx->path_match`, it's 0 if no active match,
80or the match index from your path array starting from 1 for the first entry.
81
82|CBOR element|Representation in path|
83|---|---|
84|JSON Array|`[]`|
85|JSON Map|`.`|
86|JSON Map entry key string|`keystring`|
87
88
89
90## Comparison with LECP (CBOR parser)
91
92LECP is based on the same principles as LEJP and shares most of the callbacks.
93The major differences:
94
95 - LEJP value callbacks all appear in `ctx->buf[]`, ie, floating-point is
96 provided to the callback in ascii form like `"1.0"`. CBOR provides a more
97 strict typing system, and the different type values are provided either in
98 `ctx->buf[]` for blobs or utf-8 text strtings, or the `item.u` union for
99 converted types, with additional callback reasons specific to each type.
100
101 - CBOR "maps" use `_OBJECT_START` and `_END` parsing callbacks around the
102 key / value pairs. LEJP has a special callback type `PAIR_NAME` for the
103 key string / integer, but in LECP these are provided as generic callbacks
104 dependent on type, ie, generic string callbacks or integer ones, and the
105 value part is represented according to whatever comes.
106
107
108
README.jwt.md
1# JWT support in lws
2
3lws supports the common usage scenarios of JWS (signed) JWT generation,
4parsing and transferring in and out as http cookies. Care is taken to provide
5helpers that implement the current security best practices for cookie handling
6and JWT validation. All of the common algorithms like ES512 are supported
7along with JWK generation and handling apis.
8
9The build options needed are `-DLWS_WITH_JOSE=1` `-DLWS_WITH_GENCRYPTO=1`.
10
11Underlying JOSE primitives are exposed as apis, some JWT specific primitives
12and finally a JWT-via http cookie level creation apis each building on top of
13what was underneath.
14
15The higher level APIs are provided additionally because they have the most
16opportunity for implementation pitfalls like not validating alg carefully, or
17not using the latest cookie security options; the provided APIs handle that
18centrally for you. If your needs vary from what the higher level apis are
19doing, you can cut-and-paste out those implementations and create your own
20using the public lower level apis.
21
22## LWS JWT fields
23
24Lws JWT uses mainly well-known fields
25
26Field|Std|Meaning
27---|---|---
28iss|yes|Issuer, typically the domain like "warmcat.com"
29aud|yes|Audience, typically a url path like "https://warmcat.com/sai"
30iat|yes|Unix-time "Issued At"
31nbf|yes|Unix-time "Not Before"
32exp|yes|Unix-time "Expired"
33sub|yes|Subject, eg, a username or user email
34csrf|no|A random 16-char hex token generated with the JWT for use in links specific to the JWT bearer
35ext|no|Application-specific JSON sub-object with whatever fields you need, eg, `"authorization": 1`
36
37## Approach for JWT as session token
38
39Once JWTs are produced, they are autonomous bearer tokens, if they are not kept
40secret between the browser and the site, they will be accepted as evidence for
41having rights to the session from anyone.
42
43Requiring https, and various other cookie hardening techniques make it more
44difficult for them to leak, but it is still necessary to strictly constrain the
45token's validity time, usually to a few tens of minutes or how long it takes a
46user to login and get stuff done on the site in one session.
47
48## CSRF mitigation
49
50Cross Site Request Forgery (CSRF) is a hacking scenario where an authorized
51user with a valid token is tricked into clicking on an external link that
52performs some action with side-effects on the site he has active auth on. For
53example, he has a cookie that's logged into his bank, and the link posts a form
54to the bank site transferring money to the attacker.
55
56Lws JWT mitigates this possibility by putting a random secret in the generated
57JWT; when the authorized user presents his JWT to generate the page, generated
58links that require auth to perform their actions include the CSRF string from
59that user's current JWT.
60
61When the user clicks those links intentionally, the CSRF string in the link
62matches the CSRF string in the currently valid JWT that was also provided to
63the server along with the click, and all is well.
64
65An attacker does not know the random, ephemeral JWT CSRF secret to include in
66forged links, so the attacker-controlled action gets rejected at the server as
67having used an invalid link.
68
69The checking and link manipulation need to be implemented in user code / JS...
70lws JWT provides the random CSRF secret in the JWT and makes it visible to the
71server when the incoming JWT is processed.
72
73## Need for client tracking of short JWT validity times
74
75Many links or references on pages do not require CSRF strings, only those that
76perform actions with side-effects like deletion or money transfer should need
77protecting this way.
78
79Due to CSRF mitigation, generated pages containing the protected links
80effectively have an expiry time linked to that of the JWT, since only the bearer
81of the JWT used to generate the links on the page can use them; once that
82expires actually nobody can use them and the page contents, which may anyway
83be showing content that only authenticated users can see must be invalidated and
84re-fetched. Even if the contents are visible without authentication, additional
85UI elements like delete buttons that should only be shown when authenticated
86will wrongly still be shown
87
88For that reason, the client should be informed by the server along with the
89authentication status, the expiry time of it. The client should then by itself
90make arrangements to refresh the page when this time is passed,
91either showing an unauthenticated version of the same page if it exists, or by
92redirecting to the site homepage if showing any of the contents required
93authentication. The user can then log back in using his credientials typically
94stored in the browser's password store and receive a new short-term JWT with a
95new random csrf token along with a new page using the new csrf token in its
96links.
97
98## Considerations for long-lived connections
99
100Once established as authorized, websocket links may be very long-lived and hold
101their authorization state at the server. Although the browser monitoring the
102JWT reloading the page on auth expiry should mitigate this, an attacker can
103choose to just not do that and have an immortally useful websocket link.
104
105At least for actions on the long-lived connection, it should not only confirm
106the JWT authorized it but that the current time is still before the "exp" time
107in the JWT, this is made available as `expiry_unix_time` in the args struct
108after successful validation.
109
110Ideally the server should close long-lived connections according to their auth
111expiry time.
112
113## JWT lower level APIs
114
115The related apis are in `./include/libwebsockets/lws-jws.h`
116
117### Validation of JWT
118
119```
120int
121lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
122 const char *alg_list, const char *com, size_t len,
123 char *temp, int tl, char *out, size_t *out_len);
124```
125
126### Composing and signing JWT
127
128```
129int
130lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
131 const char *alg, char *out, size_t *out_len, char *temp,
132 int tl, const char *format, ...);
133```
134
135## JWT creation and cookie get / set API
136
137Both the validation and signing apis use the same struct to contain their
138aguments.
139
140```
141struct lws_jwt_sign_set_cookie {
142 struct lws_jwk *jwk;
143 /**< entry: required signing key */
144 const char *alg;
145 /**< entry: required signing alg, eg, "ES512" */
146 const char *iss;
147 /**< entry: issuer name to use */
148 const char *aud;
149 /**< entry: audience */
150 const char *cookie_name;
151 /**< entry: the name of the cookie */
152 char sub[33];
153 /**< sign-entry, validate-exit: subject */
154 const char *extra_json;
155 /**< sign-entry, validate-exit:
156 * optional "ext" JSON object contents for the JWT */
157 size_t extra_json_len;
158 /**< validate-exit:
159 * length of optional "ext" JSON object contents for the JWT */
160 const char *csrf_in;
161 /**< validate-entry:
162 * NULL, or an external CSRF token to check against what is in the JWT */
163 unsigned long expiry_unix_time;
164 /**< sign-entry: seconds the JWT and cookie may live,
165 * validate-exit: expiry unix time */
166};
167
168int
169lws_jwt_sign_token_set_http_cookie(struct lws *wsi,
170 const struct lws_jwt_sign_set_cookie *i,
171 uint8_t **p, uint8_t *end);
172int
173lws_jwt_get_http_cookie_validate_jwt(struct lws *wsi,
174 struct lws_jwt_sign_set_cookie *i,
175 char *out, size_t *out_len);
176```
177
README.libressl.md
1## Background
2
3libressl is another fork of Openssl.
4
5## Example build for libressl itself
6
7If you unpack or clone into `/path/to/libressl` and enter that dir...
8
9```
10$ mkdir build
11$ cd build
12$ cmake ..
13$ make -j8
14```
15
16## Example build for lws against libressl
17
18You can just build lws as you would for a specific version of openssl
19
20```
21$ mkdir build
22$ cd build
23$ cmake .. -DLWS_OPENSSL_LIBRARIES='/path/to/libressl/build/tls/libtls.a;/path/to/libressl/build/ssl/libssl.a;/path/to//libressl/build/crypto/libcrypto.a' -DLWS_OPENSSL_INCLUDE_DIRS=/path/to/libressl/include -DLWS_WITH_MINIMAL_EXAMPLES=1
24$ make -j8
25```
26
27Libressl by default will look for a trust bundle in `/usr/local/etc/ssl/cert.pem`, you either have to
28symlink this to your trust bundle if that doesnt happen to be where it is, or give your app the trusted CA
29specifically as is done for MBEDTLS and WOLFSSL in the examples.
30
31In Fedora, the system trust store can be found at `/etc/pki/tls/cert.pem`, so you can symlink it
32
33```
34$ sudo mkdir -p /usr/local/etc/ssl
35$ sudo ln -sf /etc/pki/tls/cert.pem /usr/local/etc/ssl/cert.pem
36```
37
38after that you can run examples from the build dir, eg,
39
40```
41$ ./bin/lws-minimal-http-client
42[2021/02/08 20:10:52:0781] U: LWS minimal http client [-d<verbosity>] [-l] [--h1]
43[2021/02/08 20:10:52:0784] N: LWS: 4.1.99-v4.1.0-269-g762ef33fca, loglevel 1031
44[2021/02/08 20:10:52:0784] N: NET CLI SRV H1 H2 WS IPv6-absent
45[2021/02/08 20:10:52:0786] N: ++ [wsi|0|pipe] (1)
46[2021/02/08 20:10:52:0787] N: ++ [vh|0|netlink] (1)
47[2021/02/08 20:10:52:0802] N: ++ [vh|1|default] (2)
48[2021/02/08 20:10:52:1850] N: ++ [wsicli|0|GET/h1/warmcat.com] (1)
49[2021/02/08 20:10:52:2982] N: ++ [mux|0|h2_sid1_(wsicli|0|GET/h1/warmcat.com)] (1)
50[2021/02/08 20:10:52:3271] U: Connected to 46.105.127.147, http response: 200
51[2021/02/08 20:10:52:3335] U: RECEIVE_CLIENT_HTTP_READ: read 4087
52[2021/02/08 20:10:52:3335] U: RECEIVE_CLIENT_HTTP_READ: read 4096
53[2021/02/08 20:10:52:3526] U: RECEIVE_CLIENT_HTTP_READ: read 4087
54[2021/02/08 20:10:52:3526] U: RECEIVE_CLIENT_HTTP_READ: read 4096
55[2021/02/08 20:10:52:3543] U: RECEIVE_CLIENT_HTTP_READ: read 4087
56[2021/02/08 20:10:52:3543] U: RECEIVE_CLIENT_HTTP_READ: read 4096
57[2021/02/08 20:10:52:3545] U: RECEIVE_CLIENT_HTTP_READ: read 3502
58[2021/02/08 20:10:52:3546] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
59[2021/02/08 20:10:52:3546] N: -- [wsi|0|pipe] (0) 276.019ms
60[2021/02/08 20:10:52:3547] N: -- [mux|0|h2_sid1_(wsicli|0|GET/h1/warmcat.com)] (0) 56.417ms
61[2021/02/08 20:10:52:3566] N: -- [vh|1|default] (1) 276.384ms
62[2021/02/08 20:10:52:3566] N: -- [wsicli|0|GET/h1/warmcat.com|default|h2|h2] (0) 171.599ms
63[2021/02/08 20:10:52:3567] N: -- [vh|0|netlink] (0) 277.974ms
64[2021/02/08 20:10:52:3567] U: Completed: OK
65```
66
67
README.lifecycle.md
1# lws lifecycles
2
3## Context
4
5![context lifecycle](/doc-assets/lifecycle-context.png)
6
7## Client wsi
8
9![client wsi](/doc-assets/lifecycle-wsi.png)
10
11## Server wsi
12
13![server wsi](/doc-assets/lifecycle-server-wsi.png)
14
15## role-specific events
16
17role|client|server
18---|---|---
19http COMPLETED|`LWS_CALLBACK_COMPLETED_CLIENT_HTTP`|-
20http RECEIVE|`LWS_CALLBACK_RECEIVE_CLIENT_HTTP`|`LWS_CALLBACK_RECEIVE_HTTP`
21http WRITEABLE|`LWS_CALLBACK_CLIENT_HTTP_WRITEABLE`|`LWS_CALLBACK_HTTP_WRITEABLE`
22http CLOSE|`LWS_CALLBACK_CLOSED_CLIENT_HTTP`|`LWS_CALLBACK_CLOSED_HTTP`
23http BIND|`LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL`|`LWS_CALLBACK_HTTP_BIND_PROTOCOL`
24http DROP|`LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL`|`LWS_CALLBACK_HTTP_DROP_PROTOCOL`
25
26role|client|server
27---|---|---
28ws ESTABLISHED|`LWS_CALLBACK_CLIENT_ESTABLISHED`|`LWS_CALLBACK_ESTABLISHED`
29ws RECEIVE|`LWS_CALLBACK_CLIENT_RECEIVE`|`LWS_CALLBACK_RECEIVE`
30ws WRITEABLE|`LWS_CALLBACK_CLIENT_WRITEABLE`|`LWS_CALLBACK_SERVER_WRITEABLE`
31ws CLOSE|`LWS_CALLBACK_CLIENT_CLOSED`|`LWS_CALLBACK_CLOSED`
32ws BIND|`LWS_CALLBACK_WS_CLIENT_BIND_PROTOCOL`|`LWS_CALLBACK_WS_BIND_PROTOCOL`
33ws DROP|`LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL`|`LWS_CALLBACK_WS_DROP_PROTOCOL`
34
35role|client|server
36---|---|---
37raw ESTABLISHED|`LWS_CALLBACK_RAW_CONNECTED`|`LWS_CALLBACK_RAW_ADOPT`
38raw RECEIVE|`LWS_CALLBACK_RAW_RX`|`LWS_CALLBACK_RAW_RX`
39raw WRITEABLE|`LWS_CALLBACK_RAW_WRITEABLE`|`LWS_CALLBACK_RAW_WRITEABLE`
40raw CLOSE|`LWS_CALLBACK_RAW_CLOSE`|`LWS_CALLBACK_RAW_CLOSE`
41raw BIND|`LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL`|`LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL`
42raw DROP|`LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL`|`LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL`
43
44
README.logging.md
1# lws logging
2
3# `lwsl_` logging apis
4
5LWS has traditionally provided logging arrangements that are not indirected
6through the lws context, because logging may be needed before and after the
7context existence. For that reason the original logging arrangements are
8processwide.
9
10By default the logs are emitted on stdout, but this can be overridden
11using `lws_set_log_level()` and either syslog (provided by `lwsl_emit_syslog()`)
12or custom log emission is possible if you point it to your own.
13
14Currently the following log levels are defined
15
16|name|function|release|meaning|
17|---|---|---|---|
18|`LLL_ERR`|`lwsl_err()`|y|Serious operation errors anyone needs to know|
19|`LLL_WARN`|`lwsl_warn()`|y|Operation errors you may need to know|
20|`LLL_USER`|`lws_user()`|y|Information user code wants you to know|
21|`LLL_NOTICE`|`lwsl_notice()`|y|Information about what lws is doing useful for logging|
22|`LLL_INFO`|`lwsl_info()`|n|Detailed information about what lws is doing|
23|`LLL_DEBUG`|`lwsl_debug()`|n|Very detailed information about what lws is doing|
24|`LLL_PARSER`|`lwsl_parser()`|n|Very detailed information about parsing|
25|`LLL_HEADER`|`lwsl_header()`|n|Very detailed information about header processing|
26|`LLL_EXT`|`lwsl_ext()`|n|Very detailed information about ws extensions|
27|`LLL_CLIENT`|`lwsl_client()`|n|Very detailed information about client connections|
28|`LLL_LATENCY`|`lwsl_latency()`|n|detailed latency stats|
29|`LLL_THREAD`|`lwsl_thread()`|n|detailed threadpool information|
30
31The first four log levels are built into lws even on Release builds, the others
32are only built in Debug builds.
33
34You can select between Debug and Release builds using cmake `-DCMAKE_BUILD_TYPE=`
35`DEBUG` or `Release`
36
37`lws_set_log_level()` is used to OR together the logging bitfields you want to
38see emitted, only log levels that were built in can be enabled since the code for them
39is just not there otherwise.
40
41## Finegrained control of log level build
42
43You can deviate from the default log inclusion for release / debug by overriding it
44at cmake, using `LWS_LOGGING_BITFIELD_SET` and `LWS_LOGGING_BITFIELD_CLEAR`.
45
46For example you can set `-DLWS_LOGGING_BITFIELD_SET="LLL_INFO|LLL_DEBUG"`, which will
47cause those log level traces to be built in even in Release mode. Clear works
48similarly to defeat build of specific log levels.
49
50## Object tags in lws
51
52Commonly logging wants to refer to an object in a repeatable way, the usual way to
53do this is with `%p` to print the object pointer. But this has a couple of drawbacks,
54first the same memory may be freed and reallocated for a different instance of the same
55or another object, causing confusion, and second when multiple processes are allocating
56objects and logging, the same address may be allocated in different process also causing
57confusion.
58
59Lws has introduced unique tag strings to refer to object identity in logging instead, these
60contain various information such as a 64-bit ordinal for the group the object belongs
61to that won't repeat even if reallocated to the same address (until 2^64 allocations,
62anyway).
63
64Tags are fixed at object creation time for the whole object lifetime, although in some
65cases the tag may be appended to... accepted server wsis for example don't have much
66information available to form the tag until they start to indicate what they want to
67do.
68
69At their simplest the tags look like this (in a log indicating creation)
70
71```
72[2020/12/27 08:49:19:2956] N: ++ (4) [wsi|5|h2]
73```
74
75It means a wsi has been created with the tag `[wsi|5|h2]`, and after that, there are 4
76active objects in the wsi group.
77
78The corresponding object destruction log with the tag is
79
80```
81[2020/12/27 08:49:24:4226] N: -- (3) 5.126s [wsi|5|h2]
82```
83
84it indicates the object's tag, that it lived for 5.126s and after its destruction,
85there are 3 objects in its group left.
86
87### Compound tags
88
89If the object has bindings, the tag can reflect that, eg
90
91```
92[2020/12/27 08:49:19:4787] N: ++ (2) [wsiSScli|6|d_h1]
93[2020/12/27 08:49:19:4793] N: ++ (2) [wsicli|6|GET/h1/httpbin.org/([wsiSScli|6|d_h1])]
94```
95
96the first log is describing a proxied SS client connection at the proxy, and the second
97is a wsi bound to the SS object from the first log to do the outgoing client action.
98
99## Tags in user code
100
101When user code wants to refer to a tagged object like a wsi or vhost, there are helpers
102that return a `const char *` containing the tag
103
104|tag accessors|
105|---|
106|`lws_wsi_tag(wsi)`|
107|`lws_vh_tag(vh)`|
108|`lws_ss_tag(h)`|
109
110# New logging context apis
111
112From v4.3 on lws additionally provides wrappers that issue logs into a
113"log context" object, one of these is embedded in the lws_context, lws_vhost,
114wsi, ss and sspc handles. These follow the same general approach as before, but
115allow logs to be issued in "the context" of any of those objects, and to fall
116back sanely if the object pointer is NULL.
117
118The traditional process scope logs and emit management remain available as
119before, and if you do not set custom log contexts, the new log apis use the
120processwide log context emit and mask as before too.
121
122Here's a summary of the differences:
123
124|Traditional process scope logs|New log context apis|
125|---|---|
126|Single processwide log context|Defaults to processwide, but object can use custom log contexts|
127|Single processwide emit function|Emit function per log context|
128|Single processwide log mask|log mask is in log context, objects can be bound to custom log contexts at creation time|
129|Require trailing `\n` in format|Trailing `\n` added if not present|
130|Manual `__func__`|`__func__` added in wrapper macros automatically|
131|Manual tag addition|Object tag prepended automatically|
132|No hierarchy|Log contexts may refer to parent log contexts, which may prepend to child logs|
133|Macros per level (eg, `lwsl_err(...)`)|Macros per object type / level (eg, `lwsl_wsi_err(wsi, ...)`)|
134
135In addition to being able to control the emit function and log level for
136individual log contexts, eg, for a particular wsi, the log functions understand
137how to prepend object-specific information such as tags and `__func__`
138automatically. They also do not need a trailing `\n` in the format string. So
139the new context aware logs remove boilerplate from the logging calls while
140making the log information more consistent.
141
142So comparing this kind of logging the processwide and log context aware ways:
143
144```
145[2021/06/25 09:39:34:7050] N: [669282|wsicli|4|GET/h1/libwebsockets.org|default]: _lws_generic_transaction_completed_active_conn: ...
146```
147
148|Type|Example code|
149|---|---|
150|Process scope apis|`lwsl_notice("%s: %s: mylog %d\n", __func__, lws_wsi_tag(wsi), n);`|
151|New log context apis|`lwsl_wsi_notice(wsi, "mylog %d", n);`|
152
153The log context / object-aware apis do not replace the processwide logging but
154augment it, and the new apis default to use the original processwide emit
155function and log mask, so the behaviours are the same. The original processwide
156log apis themselves are unchanged.
157
158At lws_context creation time, you can set the context info `.log_cx` to a user
159defined log context which is inherited by objects created in that lws_context by
160default. Vhost creation, wsi creation and ss / sspc creation all allow passing
161a user log_cx to customize how logs for that object are handled.
162
163## Using the new logging apis
164
165This table describes the different ways to issue an ERROR verbosity log, it
166works the same for info, notice, warn, etc.
167
168|Scope|Api example|Functionality|
169|---|---|---|
170|Old, Processwide|lwsl_err(...)|Traditional processwide error log|
171|lws_context|lwsl_cx_err(context, ...)|error log bound to lws_context|
172|lws_vhost|lwsl_vhost_err(vh, ...)|error log bound to lws_vhost|
173|lws_wsi|lwsl_wsi_err(wsi, ...)|error log bound to wsi|
174|lws_ss|lwsl_ss_err(handle, ...)|error log bound to secure stream|
175
176Similarly hexdumps can be bound to different log contexts
177
178|Scope|Api example|Functionality|
179|---|---|---|
180|Old, Processwide|lwsl_hexdump_err(...)|Traditional processwide error hexdump|
181|lws_context|lwsl_hexdump_cx_err(context, ...)|error hexdump bound to lws_context|
182|lws_vhost|lwsl_hexdump_vhost_err(vh, ...)|error hexdump bound to lws_vhost|
183|lws_wsi|lwsl_hexdump_wsi_err(wsi, ...)|error hexdump bound to wsi|
184|lws_ss|lwsl_hexdump_ss_err(handle, ...)|error hexdump bound to secure stream|
185
186## Creating and using custom log contexts
187
188The log context object is public, in `libwebsockets/lws-logs.h`, currently it
189is like this
190
191```
192typedef void (*lws_log_emit_t)(int level, const char *line);
193typedef void (*lws_log_emit_cx_t)(struct lws_log_cx *cx, int level,
194 const char *line, size_t len);
195typedef void (*lws_log_prepend_cx_t)(struct lws_log_cx *cx, void *obj,
196 char **p, char *e);
197typedef void (*lws_log_use_cx_t)(struct lws_log_cx *cx, int _new);
198typedef struct lws_log_cx {
199 union {
200 lws_log_emit_t emit; /* legacy emit function */
201 lws_log_emit_cx_t emit_cx; /* LLLF_LOG_CONTEXT_AWARE */
202 } u;
203 lws_log_use_cx_t refcount_cb;
204 /**< NULL, or a function called after each change to .refcount below,
205 * this enables implementing side-effects like opening and closing
206 * log files when the first and last object binds / unbinds */
207 lws_log_prepend_cx_t prepend;
208 /**< NULL, or a cb to optionally prepend a string to logs we are a
209 * parent of */
210 struct lws_log_cx *parent;
211 /**< NULL, or points to log ctx we are a child of */
212 void *opaque;
213 /**< ignored by lws, used to pass config to emit_cx, eg, filepath */
214 void *stg;
215 /**< ignored by lws, may be used a storage by refcount_cb / emit_cx */
216 uint32_t lll_flags;
217 /**< mask of log levels we want to emit in this context */
218 int32_t refcount;
219 /**< refcount of objects bound to this log context */
220} lws_log_cx_t;
221```
222
223The emit function is a union because the traditional logs and the old emit
224functions are also implemented using the new log contexts internally. For
225new log context-aware code, you would use `.u.emit_cx` and set the flag
226`LLLF_LOG_CONTEXT_AWARE` on `.lll_flags`.
227
228Lws also exports some common emit and refcount functions so you don't have to
229reinvent the wheel
230
231|Dest|emit member|`.lll_flags`|emit|`.refcount_cb`|`.opaque`|
232|---|---|---|---|---|---|
233|stderr|`.u.emit`|-|`lwsl_emit_stderr`|NULL|NULL|
234|file|`.u.emit_cx`|`LLLF_LOG_CONTEXT_AWARE`|`lws_log_emit_cx_file`|`lws_log_use_cx_file`|`(const char *)filepath`|
235
236For example, a custom log context that emits to a configurable file can be
237declared like this (lws exports the needed helpers already)
238
239```
240static lws_log_cx_t my_log_cx = {
241 .lll_flags = LLLF_LOG_CONTEXT_AWARE |
242 LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER,
243 .refcount_cb = lws_log_use_cx_file,
244 .u.emit_cx = lws_log_emit_cx_file,
245 .opaque = "/tmp/mylogpath.log" /* also settable at runtime */
246};
247```
248
249To bind the lws_context to this log context, set `log_cx` in the context
250creation info struct
251
252```
253 info.log_cx = &my_log_cx;
254```
255
256### Log context hierarchy
257
258Log contexts may also point to a parent log context... the top level log context
259defines the emit function to be used, but parent log contexts are consulted by
260calling their prepend function if any, to annotate logs with information from
261parent levels.
262
263### Log context prepend function
264
265Logs contexts may define a "prepend" function callback, that knows how to
266represent the object in a brief string to be prepended to other logs. For
267example the wsi-aware log context layer knows how to provide the wsi tag
268when called.
269
270Prepend functions should add `:<space>` after their output, if any, since these
271will appear before the start of other logs.
272
273### Log context opaque member
274
275The `.opaque` member is available for passing in configuration to the emit and
276refcount_cb members. Lws does not use this itself at all.
277
278### Log context refcounting
279
280An expected use for custom log contexts is emitting to a specific file, and
281then binding one or more objects to that log context. Since it's too expensive
282to keep opening and closing the output file per log, it means we need to know
283when we bind to the first object and unbind from the last, so we can keep the
284file handle open.
285
286For this reason the log contexts have a refcount, and an opaque `void *stg`
287availble for the emit and refounct_cb to use how they see fit, eg, for storing
288the output log file descriptor.
289
README.lws_cache.md
1# lws_cache: Flexible single and multilevel caching
2
3lws_cache implements a single- or multi-level cache for generic payload items
4that are **keyed by a unique string**.
5
6![lws_cache overview](../doc-assets/lws_cache-1.png)
7
8L1 cache is always stored on heap, but it may be hooked up to additional levels
9of cache objects with different backing storage. The last level always contains
10a complete set of cached items, earlier levels may be empty or contain a partial
11set of objects.
12
13User code can define its own subclassed lws_cache objects with custom storage
14formats and media, while being able to take advantage of a suitably-sized L1
15heap cache to minimize the cost of repeated access.
16
17![lws_cache overview](../doc-assets/lws_cache-2.png)
18
19You can find examples of how to create, use and destroy single and multilevel
20caches in `minimal-examples/api-tests/api-test-lws_cache`
21
22## Cache size restriction, LRU and TTL
23
24The max heap footprint of its items and max number of items can be capped. LRU
25tracking is performed so the least recently relevant items are evicted first.
26It's also possible to limit the maximum size of any single payload.
27
28Time To Live (TTL) tracking is also performed automatically, so cached items
29auto-expire if a non-zero TTL is provided when the object is created. A user
30callback can be defined to get called when an item is about to be removed from
31a particular cache level, in case any housekeeping needed.
32
33## Atomicity
34
35Items in L1 can be accessed in heap casually and reliably if the following is
36borne in mind:
37
38 - Any return to the event loop may perform removal of cache items due to TTL
39expiry
40
41 - Any operation that writes new items may evict items from non-last
42cache levels which have limits to the footprint or item count to make room for
43it, using LRU ordering.
44
45In short process cache results before returning to the event loop or writing
46or removing items in the cache.
47
48## Cache creation
49
50Caches are created using an info struct `struct lws_cache_creation_info`
51that should be zeroed down. Most members are optional and can be left at zero,
52a pointer to the lws_context and a short cache name are mandatory.
53
54```
55struct lws_cache_ttl_lru *
56lws_cache_create(const struct lws_cache_creation_info *info);
57```
58
59How caches work is defined by an "ops struct" that the cache is bound to at
60creation time. `lws_cache_ops_heap` ops struct is provided by lws, you can
61define your own to implement your own specialized cache level. See
62`./include/libwebsockets/lws-cache-ttl.h` for the definition.
63
64## Cache destruction
65
66Created cache levels should be destroyed when you are finished with them.
67
68```
69void
70lws_cache_destroy(struct lws_cache_ttl_lru **cache);
71```
72
73For L1, in heap, this frees any allocations. For other levels, eg, with file
74storage for the items, this would close the file and leave any entries as they
75are.
76
77## Writethrough
78
79```
80int
81lws_cache_write_through(struct lws_cache_ttl_lru *cache,
82 const char *specific_key, const uint8_t *source,
83 size_t size, lws_usec_t expiry, void **ppay);
84```
85
86The combined caches are always accessed via the L1 cache, writing new items is
87done at L1 and writes through to each cache layer immediately, so new items go
88into the backing store without delay, but are available from heap for read.
89
90If existing keys are rewritten, the previous item of the same key is deleted
91from all levels of the cache before writing the new one.
92
93## Removal
94
95Removal also is performed at all cache levels at once.
96
97```
98int
99lws_cache_item_remove(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
100```
101
102internally earlier cache levels can evict cached items just at their level, but
103this is triggered automatically and not by api.
104
105A wildcard key is supported, removing all items matching, eg "myitem*".
106
107## Get by key
108
109```
110int
111lws_cache_item_get(struct lws_cache_ttl_lru *cache, const char *specific_key,
112 const void **pdata, size_t *psize);
113```
114
115Apis are provided to get the blob related to a specific key, if it exists at
116any cache layer. Again this should use L1, it will bring a copy of the item
117into L1 if one is not already there, so it can be accessed from heap.
118
119## Lookup with wildcards
120
121```
122int
123lws_cache_lookup(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
124 const void **pdata, size_t *psize);
125```
126
127lws_cache also supports **lookup** queries that contain wildcards or otherwise match
128on multiple keys according to cache-specific rules. These queries do not return
129a single item, instead they return lists of keys that match, in a blob of its
130own that is also cached in L1.
131
132The user can walk the lookup results blob using a provided helper api
133
134```
135int
136lws_cache_results_walk(lws_cache_results_t *walk_ctx);
137```
138
139After recovering each result key this way, the user code can use the _get api
140to access the blob for each indiviudally.
141
142The lookup results themselves are cached in L1, any new key that matches the
143wildcard lookup in any cached results, or any deletion of items with keys
144matching the cached wildcard lookup invalidate the affected cached lookup
145results so they will be regenerated next time.
146
147In the typical case after a lookup, at least for a while the lookup results blob
148and all items mentioned in the lookup results will already be in L1 and cheaply
149accessible.
150
151## Expunging
152
153An api is also provided to "expunge" or completely empty all cache levels and
154corresponding backing stores.
155
156```
157int
158lws_cache_expunge(struct lws_cache_ttl_lru *cache);
159```
160
161
README.lws_conmon.md
1## `lws_conmon` apis
2
3`LWS_WITH_CONMON` build option enables `lws_conmon` apis for user code... these add
4some staticistic and information to client connections that can use useful for devices
5to introspect how the connection to their servers is actually performing.
6
7The public apis can be found in `libwebsockets/lws-conmon.h`.
8
9A struct is provided that describes
10
11 - the peer sockaddr the wsi actually connected to, if any
12
13 - a deep copy of the aggregate DNS results (struct addrinfo list) that the
14 client had access to for the peer
15
16 - the number of us dns lookup took
17
18 - the number of us the socket connection took
19
20 - the number of us the tls link establishment took
21
22 - the number of us from the transaction request to the first response, if
23 the protocol has a transaction concept
24
25Because the user code may want to hold on to the DNS list for longer than the
26life of the wsi that originated it, the `lws_conmon_wsi_take()` api allows
27the ownership of the allocated list to be transferred to the user code (as
28well as copying data out into the user's struct so it no longer has any
29dependency on wsi lifetime either). The DNS list copy in the struct must be
30released at some point by calling `lws_conmon_release()`, but that
31can be at any time afterwards.
32
33The lws-minimal-http-client example shows how user code can use the apis, build
34lws with the `LWS_WITH_CONMON` cmake option and run with `--conmon` to get a
35dump of the collected information.
36
37
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_map.md
1# lws_map generic map abstraction
2
3|||
4|---|---|---|
5|cmake|core feature|
6|Header| ./include/libwebsockets/lws-map.h|
7|api-test| ./minimal-examples/api-tests/api-test-lws_map/|
8
9lws_map provides a robust abstraction for containing a collection of items that
10map key objects to value objects, where both the key and value objects may
11differ in size each time and have any type.
12
13Its one-level linked-list hashtables are useful up to hundreds or low thousands
14of items in the map on may platforms.
15
16The map itself and the items inside it are opaque.
17
18## Creating and destroying the map
19
20The user should prepare a `lws_map_info_t` object, it's legal for it to be
21all zeros to select defaults, an 8-way hashtable with item allocation from heap,
22simple bytewise key comparison, and xor / shift key hashing. These are often
23what you want simplifying construction.
24
25The info object allows user override of item allocator, freeing, key comparison
26and object hashing, allowing custom objects to be keys if desired.
27
28Custom allocator / free implementations for using lwsac for item allocation are
29provided to simplify that case.
30
31Just call `lws_map_create()` with the info struct to create the map, later it
32and all its contents can be destroyed with `lws_map_destroy()`. The info struct
33can go out of scope immediately after the create call.
34
35```
36lws_map_t *
37lws_map_create(const lws_map_info_t *info);
38void
39lws_map_destroy(lws_map_t **pmap);
40```
41
42## Keys in lws_map
43
44Items are managed in the map by a key, this may be, eg, a string, but it also
45can be an arbitrary object itself. If comparing keys takes more than a simple
46bytewise comparison, the map creation info struct ._compare() operation should
47be overridden with a user-supplied one that knows how to use the user's
48custom key objects.
49
50Keys are not required to be the same length, so objects with variable size
51overallocation can be used as keys.
52
53Keys and values are copied into allocations inside the map, the original objects
54they are copied from may go out of scope after item creation assuming there are
55no pointers to them copied in the objects themselves.
56
57## Adding items to a map
58
59The map's info._alloc allocator is used for creating items. By default that
60just creates into the heap.
61
62If you create a new item with the same key as an existing one, the existing one
63is destroyed before the new one is created. So there is only one item allowed
64at a given key at a time.
65
66To allocate and create a new item containing the key and value, use
67`lws_map_item_create()`
68
69```
70lws_map_item_t *
71lws_map_item_create(lws_map_t *map,
72 const lws_map_key_t key, size_t keylen,
73 const lws_map_value_t value, size_t valuelen);
74```
75
76Eg,
77
78```
79 if (!lws_map_item_create(map, (lws_map_key_t)&my_key,
80 sizeof(my_key),
81 (lws_map_value_t)"4567", 4))
82 /* fail */
83```
84
85
86In the case the key is a string, there is a ..._ks wrapper to simplify usage
87
88```
89 if (!lws_map_item_create_ks(map, "123", (lws_map_value_t)"4567", 4))
90 /* fail */
91```
92
93## Lookups in the map
94
95You can retreive a pointer to an item in the map with a give key using
96
97```
98lws_map_item_t *
99lws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen);
100```
101
102The item is opaque, but there are accessors
103
104|Accessor|Function|
105|---|---|
106|`lws_map_item_key(lws_map_item_t *_item)`|get a pointer to the item key|
107|`lws_map_item_value(lws_map_item_t *_item)`|get a pointer to the item value|
108|`lws_map_item_key_len(lws_map_item_t *_item)`|get the key length|
109|`lws_map_item_value_len(lws_map_item_t *_item)`|get the value length|
110
111Again there is a ..._ks() helper to simplify C strings as keys
112
113```
114 item = lws_map_item_lookup_ks(map, "abc");
115 if (!item)
116 /* fail */
117```
118
README.lws_metrics.md
1## `lws_metrics`
2
3### Introduction
4
5`lws_metrics` records and aggregates **events** at all lws layers.
6
7There are three distinct parts:
8
9 - the architecture inside lws for collecting and aggregating / decimating the
10 events and maintaining statistics about them, these are lws_metric objects
11
12 - an external handler for forwarding aggregated metrics. An lws_system ops
13 interface to pass on the aggregated metrics to an external backend. lws
14 presents its own public metrics objects and leaves it to the external
15 code to have a shim to marry the lws metrics up to whatever is needed in the
16 metrics backend
17
18 - a policy for when to emit each type of aggregated information to the external
19 handler. This can be specified in the generic Secure Streams policy, or
20 a linked-list of lws_metric_policy_t object passed it at context creation in
21 `info.metrics_policies`.
22
23The external backend interface code may itself make use of lws connectivity apis
24including Secure Streams itself, and lws metrics are available on that too.
25
26### `lws_metrics` policy-based reporting
27
28Normally metrics implementations are fixed at build-time and cannot change
29without a coordinated reflash of devices along with a change of backend schema.
30
31`lws_metrics` separates out the objects and code necessary to collect and
32aggregate the data cheaply, and the reporting policy that controls if, or how
33often, the results are reported to the external handler.
34
35![policy based metrics](/doc-assets/lws_metrics-policy.png)
36
37Metrics are created with a namespace name and the policy applies itself to those
38by listing the names, with wildcards allowed, the policy applies to, eg if
39specified in the Secure Streams JSON policy
40
41```
42 ...
43 "metrics": [
44 {
45 "name": "tensecs",
46 "us_schedule": 10000000,
47 "report": "cpu.*"
48 }, {
49 "name": "30secs",
50 "us_schedule": 30000000,
51 "report": "n.cn.*, n.http.*, n.ss.*, vh.*"
52 }
53 ],
54 ...
55```
56
57Metrics that do not have a reporting policy do not report, but continue to
58aggregate measurements in case they are bound to a policy dynamically later.
59
60### Freeform metrics naming
61
62There is no predefined metrics schema, metrics objects, including those created
63by applications, can independently choose their own name in a namespace like
64"cpu.srv" or "n.cn.dns", and can set a prefix for all metrics names created in a
65context (by setting `info.metrics_prefix` at context creation time).
66
67This allows multiple processes in a single device to expose copies of the same
68metrics in an individually addressable way, eg, if the UI process specifies the
69prefix "ui", then its lws metrics like "cpu.srv" will actually be created as
70"ui.cpu.srv".
71
72Applications can freely define their own `lws_metrics` measurements with their
73own names in the namespace too, without central registration, and refer to those
74names in the reporting policy same as any other metric names.
75
76If the metrics backend requires a fixed schema, the mapping between the
77`lws_metrics` names and the backend schema indexes will be done in the
78`lws_system` external reporting api implementation alone. Metrics objects
79contain a `void * backend_opaque` that is ignored by lws and can be set and
80read by the external reporting handler implementation to facilitate that.
81
82### Histogram metrics tagging
83
84Histogram metrics track differently-qualified results in the same metric, for
85example the metric `n.cn.failures` maintains separate result counts for all
86variations and kinds of failure.
87
88```
89[2021/03/01 06:34:05:6570] U: my_metric_report: ssproxy.n.cn.failures{ss="badcert_selfsigned",hostname="invalidca.badcert.warmcat.com",peer="46.105.127.147",tls="invalidca"} 2
90[2021/03/01 06:34:05:6573] U: my_metric_report: ssproxy.n.cn.failures{hostname="invalidca.badcert.warmcat.com",peer="46.105.127.147",tls="invalidca"} 1
91[2021/03/01 06:34:05:6576] U: my_metric_report: ssproxy.n.cn.failures{ss="badcert_expired",hostname="warmcat.com",peer="46.105.127.147",tls="expired"} 2
92[2021/03/01 06:34:05:6578] U: my_metric_report: ssproxy.n.cn.failures{hostname="warmcat.com",peer="46.105.127.147",tls="expired"} 1
93[2021/03/01 06:34:05:6580] U: my_metric_report: ssproxy.n.cn.failures{ss="badcert_hostname",hostname="hostname.badcert.warmcat.com",peer="46.105.127.147",tls="hostname"} 2
94[2021/03/01 06:34:05:6583] U: my_metric_report: ssproxy.n.cn.failures{hostname="hostname.badcert.warmcat.com",peer="46.105.127.147",tls="hostname"} 1
95[2021/03/01 06:34:05:6585] U: my_metric_report: ssproxy.n.cn.failures{dns="nores -2"} 8
96```
97
98The user handler for metrics is expected to iterate these, in the provided
99examples (eg, minimal-secure-streams-testsfail)
100
101```
102#if defined(LWS_WITH_SYS_METRICS)
103static int
104my_metric_report(lws_metric_pub_t *mp)
105{
106 lws_metric_bucket_t *sub = mp->u.hist.head;
107 char buf[192];
108
109 do {
110 if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
111 lwsl_user("%s: %s\n", __func__, buf);
112 } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
113
114 /* 0 = leave metric to accumulate, 1 = reset the metric */
115
116 return 1;
117}
118
119static const lws_system_ops_t system_ops = {
120 .metric_report = my_metric_report,
121};
122
123#endif
124```
125
126### `lws_metrics` decimation
127
128Event information can easily be produced faster than it can be transmitted, or
129is useful to record if everything is working. In the case that things are not
130working, then eventually the number of events that are unable to be forwarded
131to the backend would overwhelm the local storage.
132
133For that reason, the metrics objects are designed to absorb and summarize a
134potentially large number of events cheaply by aggregating them, so even extreme
135situations can be tracked meaningfully inbetween dumps to the backend.
136
137There are two approaches:
138
139 - "aggregation": decimate keeping a uint64 mean + sum, along with a max and min
140
141 - "histogram": keep a linked-list of different named buckets, with a 64-bit
142 counter for the number of times an event in each bucket was observed
143
144A single metric aggregation object has separate "go / no-go" counters, since
145most operations can fail, and failing operations act differently.
146
147`lws_metrics` 'aggregation' supports decimation by
148
149 - a mean of a 64-bit event metric, separate for go and no-go events
150 - counters of go and no-go events
151 - a min and max of the metric
152 - keeping track of when the sample period started
153
154![metrics decimation](/doc-assets/lws_metrics-decimation.png)
155
156In addition, the policy defines a percentage variance from the mean that
157optionally qualifies events to be reported individually.
158
159The `lws_metrics` 'histogram' allows monitoring of different outcomes to
160produce counts of each outcome in the "bucket".
161
162### `lws_metrics` flags
163
164When the metrics object is created, flags are used to control how it will be
165used and consumed.
166
167For example to create a histogram metrics object rather than the default
168aggregation type, you would give the flag `LWSMTFL_REPORT_HIST` at creation
169time.
170
171|Flag|Meaning|
172|---|---|
173|`LWSMTFL_REPORT_OUTLIERS`|track outliers and report them internally|
174|`LWSMTFL_REPORT_OUTLIERS_OOB`|report each outlier externally as they happen|
175|`LWSMTFL_REPORT_INACTIVITY_AT_PERIODIC`|explicitly externally report no activity at periodic cb, by default no events in the period is just not reported|
176|`LWSMTFL_REPORT_MEAN`|the mean is interesting for this metric|
177|`LWSMTFL_REPORT_ONLY_GO`|no-go pieces invalid and should be ignored, used for simple counters|
178|`LWSMTFL_REPORT_DUTY_WALLCLOCK_US`|the aggregated sum or mean can be compared to wallclock time|
179|`LWSMTFL_REPORT_HIST`|object is a histogram (else aggregator)|
180
181### Built-in lws-layer metrics
182
183lws creates and maintains various well-known metrics when you enable build
184with cmake `-DLWS_WITH_SYS_METRICS=1`:
185
186#### Aggregation metrics
187|metric name|scope|type|meaning|
188---|---|---|---|
189`cpu.svc`|context|monotonic over time|time spent servicing, outside of event loop wait|
190`n.cn.dns`|context|go/no-go mean|duration of blocking libc DNS lookup|
191`n.cn.adns`|context|go/no-go mean|duration of SYS_ASYNC_DNS lws DNS lookup|
192`n.cn.tcp`|context|go/no-go mean|duration of tcp connection until accept|
193`n.cn.tls`|context|go/no-go mean|duration of tls connection until accept|
194`n.http.txn`|context|go (2xx)/no-go mean|duration of lws http transaction|
195`n.ss.conn`|context|go/no-go mean|duration of Secure Stream transaction|
196`n.ss.cliprox.conn`|context|go/no-go mean|time taken for client -> proxy connection|
197`vh.[vh-name].rx`|vhost|go/no-go sum|received data on the vhost|
198`vh.[vh-name].tx`|vhost|go/no-go sum|transmitted data on the vhost|
199
200#### Histogram metrics
201|metric name|scope|type|meaning|
202|---|---|---|---|
203`n.cn.failures`|context|histogram|Histogram of connection attempt failure reasons|
204
205#### Connection failure histogram buckets
206|Bucket name|Meaning|
207|---|---|
208`tls/invalidca`|Peer certificate CA signature missing or not trusted|
209`tls/hostname`|Peer certificate CN or SAN doesn't match the endpoint we asked for|
210`tls/notyetvalid`|Peer certificate start date is in the future (time wrong?)|
211`tls/expired`|Peer certificate is expiry date is in the past|
212`dns/badsrv`|No DNS result because couldn't talk to the server|
213`dns/nxdomain`|No DNS result because server says no result|
214
215The `lws-minimal-secure-streams` example is able to report the aggregated
216metrics at the end of execution, eg
217
218```
219[2021/01/13 11:47:19:9145] U: my_metric_report: cpu.svc: 137.045ms / 884.563ms (15%)
220[2021/01/13 11:47:19:9145] U: my_metric_report: n.cn.dns: Go: 4, mean: 3.792ms, min: 2.470ms, max: 5.426ms
221[2021/01/13 11:47:19:9145] U: my_metric_report: n.cn.tcp: Go: 4, mean: 40.633ms, min: 17.107ms, max: 94.560ms
222[2021/01/13 11:47:19:9145] U: my_metric_report: n.cn.tls: Go: 3, mean: 91.232ms, min: 30.322ms, max: 204.635ms
223[2021/01/13 11:47:19:9145] U: my_metric_report: n.http.txn: Go: 4, mean: 63.089ms, min: 20.184ms, max: 125.474ms
224[2021/01/13 11:47:19:9145] U: my_metric_report: n.ss.conn: Go: 4, mean: 161.740ms, min: 42.937ms, max: 429.510ms
225[2021/01/13 11:47:19:9145] U: my_metric_report: vh._ss_default.rx: Go: (1) 102, NoGo: (1) 0
226[2021/01/13 11:47:19:9145] U: my_metric_report: vh.le_via_dst.rx: Go: (22) 28.165Ki
227[2021/01/13 11:47:19:9145] U: my_metric_report: vh.le_via_dst.tx: Go: (1) 267
228[2021/01/13 11:47:19:9145] U: my_metric_report: vh.api_amazon_com.rx: Go: (1) 1.611Ki, NoGo: (1) 0
229[2021/01/13 11:47:19:9145] U: my_metric_report: vh.api_amazon_com.tx: Go: (3) 1.505Ki
230```
231
232lws-minimal-secure-stream-testsfail which tests various kinds of connection failure
233reports histogram results like this
234
235```
236[2021/01/15 13:10:16:0933] U: my_metric_report: n.cn.failures: tot: 36, [ tls/invalidca: 5, tls/expired: 5, tls/hostname: 5, dns/nxdomain: 21 ]
237```
238
239## Support for openmetrics
240
241Openmetrics https://tools.ietf.org/html/draft-richih-opsawg-openmetrics-00
242defines a textual metrics export format comaptible with Prometheus. Lws
243provides a protocol plugin in `./plugins/protocol_lws_openmetrics_export`
244that enables direct export for prometheus scraping, and also protocols to
245proxy openmetrics export for unreachable servers.
246
README.lws_plugins.md
1# lws_plugins
2
3Lws now offers apis to manage your own user plugins with `LWS_WITH_PLUGINS_API`.
4Lws uses these apis internally for protocol plugins and event loop plugins
5if they're selected for build. But they are also exported for user code to
6use them how you like.
7
8## Creating your plugin export
9
10### Specifying your plugin export type
11
12Lws plugins have a single exported struct with a specified header and a user
13defined remainder. The public `lws_plugin_header_t` describes the common
14plugin export header, it's defined via libwebsockets.h as
15
16```
17typedef struct lws_plugin_header {
18 const char *name;
19 const char *_class;
20
21 unsigned int api_magic;
22 /* set to LWS_PLUGIN_API_MAGIC at plugin build time */
23
24 /* plugin-class specific superclass data follows */
25} lws_plugin_header_t;
26```
27
28The exported symbol name itself must match the plugin filename, for
29example if the symbol name is `my_plugin`, then the filename of the
30plugin might be `libmyapp-my_plugin.so` or similar... the matching
31part is after the first `-` or `_`, up to the first `.`. The exact
32details differ by platform but these rules cover the supported
33platforms. If lws has the filename of the plugin, it can then
34deduce the symbol export it should look for in the plugin.
35
36`name` is a freeform human-readable description for the plugin.
37
38`_class` is shared by your plugins and used to select them from other kinds
39of plugin that may be in the same dir. So choose a unique name like
40`"myapp xxx plugin"` or whatever shared by all plugins of that class.
41
42`api_magic` is set to `LWS_PLUGIN_API_MAGIC` to detect if the plugin is
43incompatible with the lws plugin apis version.
44
45So for example your plugin type wrapping the header might look like
46
47```
48typedef struct myapp_plugin {
49 lws_plugin_header_t hdr; /* must be first */
50
51 /* optional extra data like function pointers from your plugin */
52 mytype_t mymember;
53 /* ... */
54} myapp_plugin_t;
55```
56
57Typically, you will put function pointers to whatever capability your plugin
58class offers as the additional members.
59
60## Building your own plugins
61
62Plugins are built standalone, cmake is recommended but you can do what you want.
63
64The only requirement is the single visible export of the plugin name, eg
65
66```
67const myapp_plugin_t my_plugin = {
68 .hdr = {
69 "my_plugin",
70 "myapp xxx plugin",
71 LWS_PLUGIN_API_MAGIC
72 },
73
74 .mymember = my_plugin_init,
75 /*...*/
76};
77```
78
79## Bringing in plugins at runtime
80
81Lws provides an api to import plugins into the process space and another to
82remove and destroy plugins.
83
84You can take two approaches depending on what you're doing, either bring in and
85later destroy a whole class of plugins at once, and walk them via a linked-list,
86or bring in and later destroy a single specific plugin from the class by filtering
87on its specific export name.
88
89See `include/libwebsockets/lws-protocols-plugins.h` for documentation.
90
91```
92LWS_VISIBLE LWS_EXTERN int
93lws_plugins_init(struct lws_plugin **pplugin, const char * const *d,
94 const char *_class, const char *filter,
95 each_plugin_cb_t each, void *each_user);
96
97LWS_VISIBLE LWS_EXTERN int
98lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each,
99 void *each_user);
100```
101
102`struct lws_plugin` is a public struct that contains the linked-list of loaded
103plugins and a pointer to its exported header object, so you can walk this
104after loading.
105
106
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# lws_sul2 and system suspend
64
65In v4.1, alongside the existing `lws_sul` apis there is a refactor and additional
66functionality aimed at negotiating system suspend, while remaining completely
67backwards-compatible with v3.2+ lws_sul apis.
68
69Devicewide suspend is basically the withdrawal of CPU availability for an unbounded
70amount of time, so what may have been scheduled by the user code may miss its time
71slot because the cpu was down and nothing is getting serviced. Whether that is
72actively desirable, OK, a big disaster, or a failure that will be corrected at other
73layers at the cost of, eg, some additional latency, depends on the required device
74behaviours and the function of the user code that was scheduled, and its meaning to
75the system.
76
77Before v4.1, lws just offers the same scheduling service for everything both internal
78and arranged by user code, and has no way to know what is critical for the device to
79operate as intended, and so must force wake from suspend, or if for that scheduled
80event 'failure [to get the event] is an option'.
81
82For example locally-initiated periodic keepalive pings not happening may allow
83persistently dead (ie, no longer passing data) connections to remain unrenewed, but
84eventually when suspend ends for another reason, the locally-initiated PING probes
85will resume and it will be discovered and if the connectivity allows, corrected.
86
87If the device's function can handle the latency of there being no connectivity in
88suspend under those conditions until it wakes for another reason, it's OK for these
89kind of timeouts to be suppressed during suspend and basically take the power saving
90instead. If for a particular device it's intolerable to ever have a silently dead
91connection for more than a very short time compared to suspend durations, then these
92kind of timeouts must have the priority to wake the whole device from suspend so
93they continue to operate unimpeded.
94
95That is just one example, lws offers generic scheduler services the user code can
96exploit for any purpose, including mission-critical ones. The changes give the user
97code a way to tell lws if a particular scheduled event is important enough to the
98system operation to wake the system from devicewide suspend.
99
100
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|`LWS_SYSTATE_CONTEXT_DESTROYING`|Context is going down and smd with it|
211
212### Inserting a notifier
213
214You should create an object `lws_system_notify_link_t` in non-const memory and zero it down.
215Set the `notify_cb` member and the `name` member and then register it using either
216`lws_system_reg_notifier()` or the `.register_notifier_list`
217member of the context creation info struct to make sure it will exist early
218enough to see all events. The context creation info method takes a list of
219pointers to notify_link structs ending with a NULL entry.
220
221
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 `main` 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 `main`, and can be
17reproduced by developers, it usually gets attention, often immediately.
18
19If the problem doesn't exist on `main`, you can either use `main` 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 the development branch. So you should not consume tags like
13v4.0.0 but build into your planning that you will need to follow v4.0-stable in
14order to stay on top 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## Development
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 development" below for why it's managed like
31that.
32
33![all work happens on main](../doc-assets/lws-relpol-1.svg)
34
35If you have patches (you are a hero) they should be targeted at `main`.
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 +main:m && git reset --hard m
43```
44
45This fetches current remote development branch 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 development.
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 development seems in good shape and various new developments seem
57to be working, it's copied out into a versioned stable branch, like `v4.0-stable`.
58
59![stable branches are copied from development](../doc-assets/lws-relpol-2.svg)
60
61The initial copy is tagged with, eg, `v4.0.0`.
62
63(At that time, development's logical version is set to "...99", eg, `v4.0.99` so
64version comparisons show that development version is "later" than any other
65v4.0 version, which will never reach 99 point releases itself, but "earlier"
66than, eg, v4.1.)
67
68## Backport policy
69
70Development continues, and as part of that usually bugs are reported and / or
71fixes found that may apply not just to current development, but the version of
72the development branch that 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 main 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 the development branch
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. Developing 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.routing.md
1# Lws routing
2
3lws is mainly built around POSIX sockets and operates from the
4information available from those. But in some cases, it needs to go
5a step further and monitor and understand the device routing table.
6
7## Recognizing loss of routability
8
9On mobile devices, switching between interfaces and losing / regaining
10connections quickly is a given. But POSIX sockets do not act like
11that, the socket remains connected until something times it out if it
12no longer has a route to its peer, and the tcp timeouts can be in the
13order of minutes.
14
15In order to do better, lws must monitor and understand how the routing
16table relates to existing connections, dynamically.
17
18## Linux: netlink
19
20For linux-based devices you can build in netlink-based route monitoring
21with `-DLWS_WITH_NETLINK=1`, lws aquires a copy of the routing table
22when the context / pt starts up and modifies it according to netlink
23messages from then on.
24
25On Linux routing table events do not take much care about backing out
26changes made on interface up by, eg, NetworkManager. So lws also
27monitors for link / interface down to remove the related routes.
28
29## Actions in lws based on routing table
30
31Both server and client connections now store their peer sockaddr in the
32wsi, and when the routing table changes, all active wsi on a pt are
33checked against the routing table to confirm the peer is still
34routable.
35
36For example if there is no net route matching the peer and no gateway,
37the connection is invalidated and closed. Similarly, if we are
38removing the highest priority gateway route, all connections to a peer
39without a net route match are invalidated. However connections with
40an unaffected matching net route like 127.0.0.0/8 are left alone.
41
42## Intergration to other subsystems
43
44If SMD is built in, on any route change a NETWORK message
45`{"rt":"add|del"}` is issued.
46
47If SMD is built in, on any route change involving a gateway, a NETWORK
48message `{"trigger":"cpdcheck", "src":"gw-change"}` is issued. If
49Captive Portal Detection is built in, this will cause a new captive
50portal detection sequence.
51
52
README.tcp_fastopen.md
1# `TCP_FASTOPEN` support in lws
2
3Lws supports enabling TCP_FASTOPEN oper-vhost for listen sockets.
4
5## Enabling per vhost serving
6
7Set the `info.fo_listen_queue` to nonzero at vhost creation. Different
8platforms interpret this number differently, zero always disables it
9but on Linux, the number is interpreted as a SYN queue length.
10
11On FreeBSD, OSX and Windows, the number is basically a bool, with the
12extra restriction OSX and Windows only allows 0 or 1.
13
14## Enabling Linux for serving with TCP_FASTOPEN
15
16To configure the kernel for listening socket TCP_FASTOPEN, you need
17
18```
19# sysctl -w net.ipv4.tcp_fastopen=3
20```
21
22## Enabling BSD for serving with TCP_FASTOPEN
23
24At least on FreeBSD, you need to set the net.inet.tcp.fastopen.enabled
25sysctl to 1
26
27## Enabling Windows for serving with TCP_FASTOPEN
28
29```
30> netsh int tcp set global fastopenfallback=disabled
31> netsh int tcp show global
32```
33
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 parent process, and deletes this file when the parent 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.tls-sessions.md
1# Using TLS Session resumption
2
3Lws supports clientside session caching and session resumption on both mbedtls
4and openssl-type tls library backends, to accellerate connection re-
5establishment.
6
7## Background
8
9TLS specifies logical "sessions" that get "established" on both sides when the
10tls tunnel is negotiated... these are the object that gets validated by the
11certificate PKI. They each have a server-unique "Session ID" of up to 32 bytes
12each.
13
14Normally the default is that there is a new session negotiated per connection,
15so multiple connections to the same endpoint each negotiate fresh sessions from
16scratch.
17
18However tls servers typically maintain a cache of recent sessions, and where
19both the server and client still have a copy of a previously-negotiated session
20around, support the client explicitly requesting additional connections binding
21to the old session by asking for it by its Session ID at negotiation time.
22
23### Re-use of validated sessions
24
25The advantage is that the timeconsuming key exchange part of the negotiation can
26be skipped, and a connection-specific AES key agreed at both sides just by
27hashing on the secret held in the session object at each side. This allows new
28tunnels to be established much faster after the first, while the session from
29the first is still valid and available at both sides.
30
31Both the server and client may apply their own lifetime restriction to their
32copy of the session, the first side to expire it will cause a new session to be
33forced at the next reuse attempt. Lifetimes above 24h are not recommended by
34RFC5246.
35
36### Multiple concurrent use of validated sessions
37
38In addition, the session's scope is any connection to the server that knows the
39original session ID, because individual new AES keys are hashed from the session
40secret, multiple connections to the same endpoint can take advantage of a single
41valid session object.
42
43### Difference from Session Tickets
44
45TLS also supports sessions as bearer tokens, but these are generally considered
46as degrading security. Lws doesn't support Session Tickets, just reuse by
47Session IDs.
48
49## Support in lws
50
51Server-side TLS generally has session caching enabled by default. For client
52side, lws now enables `LWS_WITH_TLS_SESSIONS` at cmake by default, which adds
53a configurable tls session cache that is automatically kept updated with a
54MRU-sorted list of established sessions.
55
56It's also possible to serialize sessions and save and load them, but this has to
57be treated with caution.
58
59Filling, expiring and consulting the session cache for client connections is
60performed automatically.
61
62### tls library differences
63
64Mbedtls supports clientside session caching in lws, but it does not have a
65session message arrival callback to synchronize updating the client session
66cache like openssl does.
67
68Separately, the session cb in boringssl is reportedly nonfunctional at the
69moment.
70
71To solve both cases, lws will schedule a check for the session at +500ms after
72the tls negotiation completed, and for the case the connection doesn't last
73500ms or the server is slow issuing the message, also attempt to update the
74cache at the time the tls connection object is closing.
75
76### Session namespacing in lws
77
78Internally sessions are referred to by a vhostname.hostname.port tuple.
79
80### Configuring the clientside cache
81
82Session caches in lws exist in and are bound to the vhost. Different vhosts may
83provide different authentication (eg, client certs) to the same endpoint that
84another connection should not be able to take advantage of.
85
86The max size of this cache can be set at `.tls_session_cache_max` in the vhost
87creation info struct, if left at 0 then a default of 10 is applied.
88
89The Time-To-Live policy for sessions at the client can be set in seconds at
90`.tls_session_timeout`, by default whatever the tls library thinks it should be,
91perhaps 300s.
92
93You can disable session caching for a particular vhost by adding the vhost
94option flag `LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE` to `.options` at
95vhost creation time.
96
97### Session saving and loading
98
99Trying to make sessions really persistent is supported but requires extra
100caution. RFC5246 says
101
102 Applications that may be run in relatively insecure environments should not
103 write session IDs to stable storage.
104
105The issue is that while in process memory the session object is relatively
106secure compared to sensitive secrets and tls library data already in process
107memory.
108
109But when serialized to, eg, some external, unencrypted medium, the accessibility
110of what is basically a secret able to decrypt tls connections can become a
111security hazard. It's left to the user to take any necessary steps to secure
112sessions stored that way.
113
114For openssl, Public APIs are provided in `libwebsockets/lws-tls-sessions.h` to
115serialize any session in the cache associated with a vhost/host/port tuple, and
116to preload any available session into a vhost session cache by describing the
117endpoint hostname and port.
118
119The session saving and loading apis aren't supported for mbedtls yet.
120
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
47You can simulate udp packetloss at tx and rx by using the Fault Injection apis
48with the well-known fault names "udp_tx_loss" and "udp_rx_loss", typically
49with the probabilistic setting, in commandline format something like
50`--fault-injection "wsi/udp_tx_loss(10%)"`
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 `main`
11README.md.
12
13