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 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 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 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 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 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 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 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 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 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 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 6 7## Client wsi 8 9 10 11## Server wsi 12 13 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 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 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 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 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 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 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 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 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 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 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 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 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 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