Skip to content

Commit eb5ee93

Browse files
committed
gnutls-h3
1 parent 8a422a7 commit eb5ee93

280 files changed

Lines changed: 9215 additions & 2004 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.sai.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212
},
1313
"netbsd-OSX-bigsur/x86_64-intel-i3/llvm": {
1414
"build": [
15-
"mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib MACOSX_DEPLOYMENT_TARGET=15.7 cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make ${cmake}",
15+
"mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib MACOSX_DEPLOYMENT_TARGET=15.7 cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DLWS_GNUTLS_INCLUDE_DIRS=/usr/local/include -DLWS_GNUTLS_LIBRARIES=/usr/local/lib/libgnutls.dylib ${cmake}",
1616
"cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install",
1717
"cd build ; export LD_LIBRARY_PATH=\"$HOME/jobs/$SAI_VN/src/build/lib\" ; ctest -j$SAI_PARALLEL --output-on-failure --repeat until-pass:3",
1818
"cd build && SAI_CPACK=\"-G ZIP\" ${cpack}"
1919
]
2020
},
2121
"netbsd-OSX-tahoe/aarch64-apple-m1/llvm": {
2222
"build": [
23-
"mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib MACOSX_DEPLOYMENT_TARGET=26 cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make ${cmake}",
23+
"mkdir -p build destdir; cd build; CCACHE_DISABLE=1 LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib MACOSX_DEPLOYMENT_TARGET=26 cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DLWS_GNUTLS_INCLUDE_DIRS=/System/Volumes/Data/opt/homebrew/Cellar/gnutls/3.8.13_2/include -DLWS_GNUTLS_LIBRARIES=/System/Volumes/Data/opt/homebrew/Cellar/gnutls/3.8.13_2/lib/libgnutls.dylib ${cmake}",
2424
"cd build && make -j$SAI_PARALLEL && rm -rf ../destdir && make -j$SAI_PARALLEL DESTDIR=../destdir install",
2525
"cd build ; export LD_LIBRARY_PATH=\"$HOME/jobs/$SAI_VN/src/build/lib\" ; ctest -j$SAI_PARALLEL --output-on-failure --repeat until-pass:3",
2626
"cd build && SAI_CPACK=\"-G ZIP\" ${cpack}"
@@ -156,10 +156,10 @@
156156
"cmake": "-DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_TLS_SESSIONS=1"
157157
},
158158
"h1only-examples": {
159-
"cmake": "-DLWS_WITH_HTTP2=0 -DLWS_WITH_MINIMAL_EXAMPLES=1"
159+
"cmake": "-DLWS_WITH_HTTP3=0 -DLWS_WITH_HTTP2=0 -DLWS_WITH_MINIMAL_EXAMPLES=1"
160160
},
161161
"h1only-notls": {
162-
"cmake": "-DLWS_WITH_HTTP2=0 -DLWS_WITH_SSL=OFF"
162+
"cmake": "-DLWS_WITH_HTTP3=0 -DLWS_WITH_HTTP2=0 -DLWS_WITH_SSL=OFF"
163163
},
164164
"unix-domain": {
165165
"cmake": "-DUNIX_SOCK=1"
@@ -203,7 +203,7 @@
203203
"cmake": "-DLWS_WITH_MBEDTLS=1 -DLWS_WITHOUT_TESTAPPS=1"
204204
},
205205
"mbedtls": {
206-
"cmake": "-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_QUIC=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG"
206+
"cmake": "-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP3=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG"
207207
},
208208
"mbedtls-metrics": {
209209
"cmake": "-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_SYS_METRICS=1"

CMakeLists-implied-options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ if (LWS_WITH_HTTP2)
281281
endif()
282282
if (LWS_WITH_HTTP3)
283283
set(LWS_ROLE_H3 1)
284+
set(LWS_ROLE_WT 1)
284285
endif()
285286
if (LWS_WITH_CGI)
286287
set(LWS_ROLE_CGI 1)

CMakeLists.txt

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,17 @@ option(LWS_WITH_NETWORK "Compile with network-related code" ON)
148148
option(LWS_ROLE_H1 "Compile with support for http/1 (needed for ws)" ON)
149149
option(LWS_ROLE_WS "Compile with support for websockets" ON)
150150
option(LWS_ROLE_MQTT "Build with support for MQTT client" OFF)
151-
option(LWS_ROLE_QUIC "Build with support for QUIC transport" OFF)
151+
if (DEFINED LWS_WITH_UDP AND NOT LWS_WITH_UDP)
152+
set(LWS_QUIC_DEFAULT OFF)
153+
else()
154+
set(LWS_QUIC_DEFAULT ON)
155+
endif()
156+
option(LWS_ROLE_QUIC "Build with support for QUIC transport" ${LWS_QUIC_DEFAULT})
152157
option(LWS_ROLE_DBUS "Compile with support for DBUS" OFF)
153158
option(LWS_ROLE_RAW_PROXY "Raw packet proxy" OFF)
154159
option(LWS_ROLE_RAW_FILE "Compile with support for raw files" ON)
155160
option(LWS_WITH_HTTP2 "Compile with server support for HTTP/2" ON)
156-
option(LWS_WITH_HTTP3 "Compile with support for HTTP/3" OFF)
161+
option(LWS_WITH_HTTP3 "Compile with support for HTTP/3" ${LWS_QUIC_DEFAULT})
157162
option(LWS_WITH_LS_QPACK "Compile tests against ls-qpack for correctness testing" OFF)
158163
option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF)
159164
option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out/err) APIs" OFF)
@@ -179,6 +184,9 @@ option(LWS_WITH_ALEXA "Enable Alexa example" OFF)
179184
option(LWS_WITH_GTK "Enable gtk example" OFF)
180185
option(LWS_WITH_FTS "Full Text Search support" OFF)
181186
option(LWS_WITH_SYS_ASYNC_DNS "Nonblocking internal IPv4 + IPv6 DNS resolver" OFF)
187+
if (LWS_WITH_HTTP3)
188+
set(LWS_WITH_SYS_ASYNC_DNS 1)
189+
endif()
182190
option(LWS_WITH_SYS_ASYNC_DNS_DNSSEC "Include DNSSEC parsing/validation in async-dns (requires crypto)" OFF)
183191
option(LWS_WITH_AUTHORITATIVE_DNS "Authoritative DNS zone signer / server" OFF)
184192
option(LWS_WITH_SYS_NTPCLIENT "Build in tiny ntpclient good for tls date validation and run via lws_system" OFF)
@@ -238,13 +246,30 @@ option(LWS_WITH_SSL "Include SSL support (defaults to OpenSSL or similar, mbedTL
238246
option(LWS_WITH_MBEDTLS "Use mbedTLS (>=2.0) replacement for OpenSSL. When setting this, you also may need to specify LWS_MBEDTLS_LIBRARIES and LWS_MBEDTLS_INCLUDE_DIRS" OFF)
239247
option(LWS_WITH_BEARSSL "Use BearSSL replacement for OpenSSL. When setting this, you also may need to specify LWS_BEARSSL_LIBRARIES and LWS_BEARSSL_INCLUDE_DIRS" OFF)
240248
set(LWS_BEARSSL_PROFILE "full" CACHE STRING "BearSSL profile to use (e.g. full, client, minimal)")
241-
if (WIN32)
242-
option(LWS_WITH_SCHANNEL "Use Windows SChannel for SSL" OFF)
243-
endif()
244249
option(LWS_WITH_BORINGSSL "Use BoringSSL replacement for OpenSSL" OFF)
245-
option(LWS_WITH_GNUTLS "Use GnuTLS for SSL" OFF)
250+
option(LWS_WITH_AWSLC "Use AWSLC replacement for OpenSSL" OFF)
246251
option(LWS_WITH_CYASSL "Use CyaSSL replacement for OpenSSL. When setting this, you also need to specify LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS" OFF)
247252
option(LWS_WITH_WOLFSSL "Use wolfSSL replacement for OpenSSL. When setting this, you also may need to specify LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS" OFF)
253+
254+
if (LWS_WITH_BEARSSL)
255+
set(LWS_ROLE_QUIC 0)
256+
set(LWS_WITH_HTTP3 0)
257+
endif()
258+
259+
if (WIN32 AND NOT (LWS_WITH_BORINGSSL OR LWS_WITH_AWSLC OR LWS_WITH_MBEDTLS OR LWS_WITH_WOLFSSL OR LWS_WITH_CYASSL OR LWS_WITH_BEARSSL OR LWS_WITH_GNUTLS))
260+
set(LWS_SCHANNEL_DEFAULT ON)
261+
else()
262+
set(LWS_SCHANNEL_DEFAULT OFF)
263+
endif()
264+
if (WIN32)
265+
option(LWS_WITH_SCHANNEL "Use Windows SChannel for SSL" ${LWS_SCHANNEL_DEFAULT})
266+
endif()
267+
268+
if (LWS_ROLE_QUIC AND NOT (LWS_WITH_BORINGSSL OR LWS_WITH_AWSLC OR LWS_WITH_MBEDTLS OR LWS_WITH_WOLFSSL OR LWS_WITH_CYASSL OR LWS_WITH_BEARSSL OR LWS_WITH_SCHANNEL OR ESP_PLATFORM OR LWS_WITH_ESP32))
269+
option(LWS_WITH_GNUTLS "Use GnuTLS for SSL" ON)
270+
else()
271+
set(LWS_WITH_GNUTLS OFF CACHE BOOL "Use GnuTLS for SSL" FORCE)
272+
endif()
248273
option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of the OS-installed CA root certs" ON)
249274
option(LWS_TLS_LOG_PLAINTEXT_RX "For debugging log the received plaintext as soon as decrypted" OFF)
250275
option(LWS_TLS_LOG_PLAINTEXT_TX "For debugging log the transmitted plaintext just before encryption" OFF)
@@ -599,7 +624,8 @@ endif()
599624
if (WIN32)
600625
message(STATUS "LWS_BUILTIN_PLUGIN_NAMES: ${LWS_BUILTIN_PLUGIN_NAMES}")
601626
message(STATUS "CONFIG_SCOPE: ${LWS_BUILTIN_PLUGIN_NAMES}")
602-
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/win32port/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/win32port/version.rc @ONLY)
627+
message("LWS_HAVE_SSL_set_tlsext_host_name: ${LWS_HAVE_SSL_set_tlsext_host_name}")
628+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/win32port/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/win32port/version.rc @ONLY)
603629
set(RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/win32port/version.rc)
604630
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/win32port/win32helpers")
605631
endif()
@@ -1257,19 +1283,22 @@ endif()
12571283

12581284
message(STATUS "LWS_BUILTIN_PLUGIN_NAMES: ${LWS_BUILTIN_PLUGIN_NAMES}")
12591285
message(STATUS "CONFIG_SCOPE: ${LWS_BUILTIN_PLUGIN_NAMES}")
1286+
message("LWS_HAVE_SSL_set_tlsext_host_name: ${LWS_HAVE_SSL_set_tlsext_host_name}")
12601287
configure_file(${PROJECT_SOURCE_DIR}/cmake/LwsCheckRequirements.cmake
12611288
${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LwsCheckRequirements.cmake
12621289
@ONLY)
12631290

12641291
message(STATUS "LWS_BUILTIN_PLUGIN_NAMES: ${LWS_BUILTIN_PLUGIN_NAMES}")
12651292
message(STATUS "CONFIG_SCOPE: ${LWS_BUILTIN_PLUGIN_NAMES}")
1293+
message("LWS_HAVE_SSL_set_tlsext_host_name: ${LWS_HAVE_SSL_set_tlsext_host_name}")
12661294
configure_file(${PROJECT_SOURCE_DIR}/cmake/LwsCheckRequirements.cmake
12671295
${PROJECT_BINARY_DIR}/LwsCheckRequirements.cmake
12681296
@ONLY)
12691297

12701298
# Generate version info for both build-tree and install-tree.
12711299
message(STATUS "LWS_BUILTIN_PLUGIN_NAMES: ${LWS_BUILTIN_PLUGIN_NAMES}")
12721300
message(STATUS "CONFIG_SCOPE: ${LWS_BUILTIN_PLUGIN_NAMES}")
1301+
message("LWS_HAVE_SSL_set_tlsext_host_name: ${LWS_HAVE_SSL_set_tlsext_host_name}")
12731302
configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config-version.cmake.in
12741303
${PROJECT_BINARY_DIR}/libwebsockets-config-version.cmake
12751304
@ONLY)
@@ -1281,6 +1310,7 @@ set(LWS__INCLUDE_DIRS
12811310
set(LIBWEBSOCKETS_INCLUDE_DIRS ${LWS__INCLUDE_DIRS} CACHE PATH "Libwebsockets include directories")
12821311
message(STATUS "LWS_BUILTIN_PLUGIN_NAMES: ${LWS_BUILTIN_PLUGIN_NAMES}")
12831312
message(STATUS "CONFIG_SCOPE: ${LWS_BUILTIN_PLUGIN_NAMES}")
1313+
message("LWS_HAVE_SSL_set_tlsext_host_name: ${LWS_HAVE_SSL_set_tlsext_host_name}")
12841314
configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config.cmake.in
12851315
${PROJECT_BINARY_DIR}/libwebsockets-config.cmake
12861316
@ONLY)
@@ -1324,6 +1354,7 @@ endif()
13241354
# Generate the lws_config.h that includes all the public compilation settings.
13251355
message(STATUS "LWS_BUILTIN_PLUGIN_NAMES: ${LWS_BUILTIN_PLUGIN_NAMES}")
13261356
message(STATUS "CONFIG_SCOPE: ${LWS_BUILTIN_PLUGIN_NAMES}")
1357+
message("LWS_HAVE_SSL_set_tlsext_host_name: ${LWS_HAVE_SSL_set_tlsext_host_name}")
13271358
configure_file(
13281359
"${PROJECT_SOURCE_DIR}/cmake/lws_config.h.in"
13291360
"${PROJECT_BINARY_DIR}/lws_config.h")
@@ -1410,6 +1441,7 @@ set(LIB_LIST_AT_END ${STRIPPED_LIB_LIST_AT_END})
14101441

14111442
message(STATUS "LWS_BUILTIN_PLUGIN_NAMES: ${LWS_BUILTIN_PLUGIN_NAMES}")
14121443
message(STATUS "CONFIG_SCOPE: ${LWS_BUILTIN_PLUGIN_NAMES}")
1444+
message("LWS_HAVE_SSL_set_tlsext_host_name: ${LWS_HAVE_SSL_set_tlsext_host_name}")
14131445
configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config.cmake.in
14141446
${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libwebsockets-config.cmake
14151447
@ONLY)

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
| TLS Library | Server TLS | Client TLS | QUIC Transport (TLS 1.3) | WSS / HTTPS | MQTT over TLS | ALPN (HTTP/2) | DTLS (WebRTC) | Session Cache | JIT Trust | GenCrypto |
1212
| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
13-
| **OpenSSL** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** |
13+
| **OpenSSL** | **Yes** | **Yes** | **No*** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** |
1414
| **LibreSSL** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **No** | **Yes** |
1515
| **AWS-LC** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **No** | **Yes** |
1616
| **BoringSSL** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **No** | **Yes** |
@@ -20,6 +20,9 @@
2020
| **SChannel** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **No** | **Yes** |
2121
| **BearSSL** | **Yes** | **Yes** | **No** | **Yes** | **Yes** | **Yes** | **No** | **Yes** | **Yes** | **Yes** |
2222

23+
\* *Note: Upstream OpenSSL does not provide the necessary QUIC TLS API (`SSL_set_quic_method`) to act as a cryptographic engine for LWS's QUIC transport. If you need QUIC/HTTP3 support, we recommend using BoringSSL, GnuTLS, WolfSSL, or the `quictls` fork of OpenSSL.*
24+
25+
2326
- DHT support built-in: `-DLWS_WITH_DHT=1`
2427

2528
** v4.5 is released, you can follow it on v4.5-stable **

READMEs/README.quic-0rtt.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# QUIC 0-RTT / Early Data
2+
3+
libwebsockets supports QUIC 0-RTT (Early Data) to allow clients to send data before the TLS 1.3 handshake fully completes, reducing latency for resuming connections.
4+
5+
Because 0-RTT data is susceptible to replay attacks, the implementation uses an explicit opt-in model. Existing applications using QUIC or HTTP/3 will ignore 0-RTT by default and continue operating with the standard `LWS_CALLBACK_CLIENT_ESTABLISHED`.
6+
7+
## How it works
8+
9+
When a client connection initiates a handshake with a server it has previously connected to, it can attempt to send 0-RTT data using early TLS secrets.
10+
- If the server accepts it, the client's 0-RTT data is processed immediately.
11+
- If the server rejects it, the connection falls back to the standard 1-RTT handshake.
12+
13+
## Enabling 0-RTT
14+
15+
To enable 0-RTT capabilities on a connection, both the client and server must explicitly allow it using flags and options:
16+
17+
### Client
18+
19+
When creating a client connection, set the `LCCSCF_ALLOW_EARLY_DATA` flag in the `ssl_connection` member of your `struct lws_client_connect_info`:
20+
21+
```c
22+
struct lws_client_connect_info i;
23+
memset(&i, 0, sizeof(i));
24+
// ...
25+
i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_EARLY_DATA;
26+
// ...
27+
lws_client_connect_via_info(&i);
28+
```
29+
30+
### Server
31+
32+
When creating the server vhost, add the `LWS_SERVER_OPTION_ALLOW_EARLY_DATA` flag to the vhost `options`:
33+
34+
```c
35+
struct lws_context_creation_info info;
36+
memset(&info, 0, sizeof(info));
37+
// ...
38+
info.options |= LWS_SERVER_OPTION_ALLOW_EARLY_DATA;
39+
// ...
40+
lws_create_context(&info);
41+
```
42+
43+
## Opting a Stream into 0-RTT
44+
45+
When early data is possible on a connection, the protocol callback will receive a new reason: `LWS_CALLBACK_CLIENT_ESTABLISHED_EARLY`.
46+
47+
To opt a specific stream into sending 0-RTT data, your callback **must return `1`** when handling this reason:
48+
49+
```c
50+
static int
51+
callback_example(struct lws *wsi, enum lws_callback_reasons reason,
52+
void *user, void *in, size_t len)
53+
{
54+
switch (reason) {
55+
case LWS_CALLBACK_CLIENT_ESTABLISHED_EARLY:
56+
/* We have an opportunity to send 0-RTT data.
57+
* Return 1 to opt-in and become writable immediately.
58+
* Return 0 (default) to ignore 0-RTT.
59+
*/
60+
return 1;
61+
62+
case LWS_CALLBACK_CLIENT_ESTABLISHED:
63+
/* The traditional handshake has completed. */
64+
break;
65+
66+
// ...
67+
}
68+
return 0;
69+
}
70+
```
71+
72+
If you return `1`, the stream opts into 0-RTT, and LWS will immediately call `lws_callback_on_writable(wsi)` for that stream so you can send your early data payload.
73+
74+
> [!NOTE]
75+
> Opting into 0-RTT does not skip the normal `LWS_CALLBACK_CLIENT_ESTABLISHED`. You will still receive `LWS_CALLBACK_CLIENT_ESTABLISHED` when the QUIC handshake actually completes.
76+
77+
## Handling Rejection and Idempotency
78+
79+
### Client-side Rejection Status
80+
81+
Since 0-RTT can be rejected by the server (e.g. if the server lost its session ticket keys), the client needs to know if the early data it sent was actually accepted.
82+
You can query the status of 0-RTT using the `lws_tls_0rtt_status(wsi)` API:
83+
84+
```c
85+
enum lws_0rtt_status status = lws_tls_0rtt_status(wsi);
86+
87+
if (status == LWS_0RTT_STATUS_REJECTED) {
88+
/* 0-RTT was rejected by the server. Any early data sent must be re-sent. */
89+
}
90+
```
91+
92+
### Server-side Idempotency
93+
94+
Because 0-RTT data can be intercepted and replayed by attackers, servers MUST ensure that any actions taken based on 0-RTT data are strictly idempotent (e.g., HTTP GET requests without side effects).
95+
96+
Servers can check if incoming data was received during the 0-RTT phase by calling `lws_rx_is_early_data(wsi)`:
97+
98+
```c
99+
if (lws_rx_is_early_data(wsi)) {
100+
/* Data was received via 0-RTT. Enforce idempotency!
101+
* Do not process state-changing requests like POST or DELETE here.
102+
*/
103+
}
104+
```

READMEs/README.quic.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,65 @@ SChannel is native to Windows, so no third-party TLS library compilation is requ
196196
cmake .. -DLWS_WITH_SCHANNEL=ON -DLWS_ROLE_QUIC=ON
197197
cmake --build . --config Release
198198
```
199+
200+
---
201+
202+
## Testing QUIC and HTTP/3 Compliance
203+
204+
lws uses `h3spec` to validate its QUIC and HTTP/3 implementation against the RFCs. The `ctest` infrastructure automatically discovers and runs the `h3spec` test suite against the `lws-minimal-quic-client-server` test application if the `h3spec` executable is found in your system's `PATH`.
205+
206+
### Enabling `h3spec` tests in CI or locally
207+
208+
To enable `h3spec` testing, simply download the pre-compiled static binary for your platform from the [h3spec GitHub releases](https://github.com/kazu-yamamoto/h3spec/releases) and place it somewhere in your `PATH` (e.g., `/usr/local/bin`).
209+
210+
**Example for Linux x86_64:**
211+
```bash
212+
wget https://github.com/kazu-yamamoto/h3spec/releases/download/v0.1.13/h3spec-linux-x86_64
213+
chmod +x h3spec-linux-x86_64
214+
sudo cp h3spec-linux-x86_64 /usr/local/bin/h3spec
215+
```
216+
217+
Once installed, re-run `cmake` on your lws build directory so it can discover the `h3spec` executable. Then, simply run `ctest` (or `make test`) as usual. The `h3spec` test will spawn a temporary test server in the background, run the compliance suite, and tear down the server automatically.
218+
219+
---
220+
221+
## Congestion Control
222+
223+
Libwebsockets features a pluggable QUIC Congestion Control architecture. By default, it uses a New Reno algorithm, but we also provide an implementation of CUBIC.
224+
225+
### Selecting a Congestion Control Algorithm
226+
227+
You can select the congestion control algorithm used for the context by configuring `quic_cc_ops` in `struct lws_context_creation_info`. We export two built-in implementations natively in `lws-quic.h`:
228+
229+
- `lws_cc_ops_newreno`
230+
- `lws_cc_ops_cubic`
231+
232+
Example of selecting CUBIC:
233+
```c
234+
struct lws_context_creation_info info;
235+
memset(&info, 0, sizeof(info));
236+
/* ... other config ... */
237+
info.quic_cc_ops = &lws_cc_ops_cubic;
238+
239+
struct lws_context *context = lws_create_context(&info);
240+
```
241+
242+
### Writing Your Own Congestion Control Algorithm
243+
244+
If you need a specialized algorithm (like BBR), you can easily plug it in by implementing the `struct lws_cc_ops` interface defined in `lws-quic.h`:
245+
246+
```c
247+
struct lws_cc_ops {
248+
void (*init)(struct lws *nwsi);
249+
void (*on_sent)(struct lws *nwsi, size_t bytes);
250+
void (*on_ack)(struct lws *nwsi, size_t bytes_acked, lws_usec_t rtt);
251+
void (*on_loss)(struct lws *nwsi, size_t bytes_lost);
252+
int (*can_send)(struct lws *nwsi, size_t bytes);
253+
lws_usec_t (*get_pacing_delay)(struct lws *nwsi, size_t bytes_to_send);
254+
};
255+
```
256+
257+
1. **State Management**: Inside `init()`, allocate your custom state structure and assign it to `nwsi->quic.qn->cc_state`.
258+
2. **Implement Hooks**: Fill out the remaining hooks to track `bytes_in_flight`, adjust `cwnd`, manage `ssthresh`, and handle loss/ack events.
259+
3. **Pacing**: `get_pacing_delay()` should return `0` if it's safe to send immediately, or the number of microseconds to delay the send.
260+
4. **Use It**: Assign a pointer to your custom `lws_cc_ops` struct to `info.quic_cc_ops` during context creation.

0 commit comments

Comments
 (0)