Skip to content

async-dns: send the A query before AAAA#3627

Open
zzblydia wants to merge 98 commits into
warmcat:mainfrom
zzblydia:main_20260709_AAAA
Open

async-dns: send the A query before AAAA#3627
zzblydia wants to merge 98 commits into
warmcat:mainfrom
zzblydia:main_20260709_AAAA

Conversation

@zzblydia

@zzblydia zzblydia commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

What

One-character fix in lws_async_dns_writeable(): >=>.

On the first send for a query, q->sent[0] == q->sent[1] == 0, so which = q->sent[0] >= q->sent[1] evaluates to 1 and the AAAA query goes out before A. That contradicts the comment in lws_async_dns_query() and READMEs/README.async-dns.md ("it always requests first A and then immediately afterwards AAAA").

With >, the first send picks A (0), the second send still emits AAAA — either via the writeable rearm while
sent[0] != sent[1], or via the q->responded & 1 path if the A response has already arrived — and retries keep alternating. Exactly one A and one AAAA are still emitted per query in every path.

Why response handling is unaffected

A/AAAA response matching does not depend on send order anywhere:

  • the record type is carried in the low bit of the tid at send time and
    recovered at parse time (n = 1 << (tid & 1)), so responses are matched by tid, not by arrival order;
  • completion remains q->responded == q->asked with asked = 3 unchanged;

Verification

Captured qtypes at the nameserver with a minimal client
(LWS_WITH_IPV6=ON, LWS_WITH_SYS_ASYNC_DNS=ON, ubuntu 24.04 and suse12sp5)

nameserver behavior before after
answers A=127.0.0.1, AAAA=::1 instantly AAAA, A → connects A, AAAA → connects
answers A, empty NOERROR for AAAA AAAA, A → connects A, AAAA → connects
answers both only after both queries AAAA, A A, AAAA

vikramdattu and others added 30 commits June 9, 2026 15:36
The mbedTLS 4 migration handled the generic (non-FreeRTOS) include
branch but missed the FreeRTOS paths, so an ESP-IDF v6 / mbedTLS 4
build hits removed-header errors:

- private-lib-tls.h includes <mbedtls/aes.h> and <mbedtls/gcm.h>
  unconditionally in the FreeRTOS branch; both were removed in
  mbedTLS 4. Gate behind !LWS_HAVE_MBEDTLS_V4, mirroring the generic
  branch.
- freertos-sockets.c includes the legacy <mbedtls/net.h> (removed in
  mbedTLS 4) when LWS_HAVE_MBEDTLS_NET_SOCKETS is unset, which it
  always is on FreeRTOS since the probe doesn't run there. Include
  <mbedtls/net_sockets.h> on mbedTLS 4: it still carries
  mbedtls_net_context and the MBEDTLS_ERR_NET_* codes used by the BIO
  callbacks even when MBEDTLS_NET_C is off.

Verified on a real IDF v6 / mbedTLS 4 build.
The m==16 (IPv6) numeric-literal path used ai/sa46 without deriving
them from the cache entry c, unlike the m==4 (IPv4) path just above.
When the cache entry already existed (the allocation block was not
entered), ai/sa46 were uninitialised, which GCC flags as
-Werror=maybe-uninitialized with IPv6 enabled. Mirror the IPv4 path.
Subject: [PATCH] freertos: don't leave SPAWN (and its siginfo_t dep) enabled

LWS_WITH_STUB defaults ON and implies LWS_WITH_SPAWN in
CMakeLists-implied-options.txt before the LWS_PLAT_FREERTOS block
disables STUB, so SPAWN stays on for FreeRTOS. There is no spawn support
on FreeRTOS, and the spawn API's siginfo_t typedef fails to build with
newer newlib (ESP-IDF v6). Force SPAWN off in the FreeRTOS block.
The OpenSSL-compat wrapper selects net_sockets.h over the v4-removed
net.h, and the MBEDTLS_SSL_NEW_SESSION_TICKET enum, via the
LWS_HAVE_MBEDTLS_NET_SOCKETS / LWS_HAVE_MBEDTLS_SSL_NEW_SESSION_TICKET
probes. Those don't run on FreeRTOS, so on an mbedTLS 4 build there the
v3 branch is compiled and breaks. Also accept LWS_HAVE_MBEDTLS_V4 so the
v4 path is taken wherever that's set.
IDF v6 switched to picolibc, whose errno is thread-local. lws forces
LWIP_PROVIDE_ERRNO and declares its own `extern int errno`, both
non-TLS, so objects fail to link against picolibc's TLS errno
("TLS definition ... mismatches non-TLS reference"). On mbedTLS 4
(a proxy for IDF v6) skip LWIP_PROVIDE_ERRNO and include <errno.h>
instead. Older IDF (newlib) is unchanged.
If lws_client_connect_via_info() never fully completes (e.g., DNS not resolvable, but glibc
is waiting?), the ah allocated during the h1 connect sequence is still attached to the wsi,
even though it is "pre-natal".

While we're in this state, before the connection failure is handled, if the user ends up calling
lws_context_destroy() e.g., in a libuv foreign loop, the ah pool is freed first.  However,
the wsi still has a dangling pointer to the ah.  Then in a later part of the context destroy sequence,
lws_pt_destroy() loops through the pre-natal wsis, and eventually accesses and dereferences the
dangling wsi->http.ah pointer.

In _lws_destroy_ah(), detach the wsi->http.ah pointer when we free it.
This seems safest, since _lws_destroy_ah() is called in a handful of contexts.
…u list is

 empty

lws_cache_item_evict_lru() silently does nothing when the lru list is
empty, but the eviction loop in lws_cache_heap_write() only checks the
footprint / item count limits.  If the limits still appear exceeded
after the cache has been fully emptied (eg, a single item larger than
max_footprint, or a stale current_footprint inherited from the
pre-existing accounting bug), the loop condition never changes and the
service thread spins forever inside the write, never returning to the
event loop.

Signed-off-by: minicx <minicx@disroot.org>
lws frees wsi->stash early in lws_http_client_connect_via_info2()
when LWS_WITH_SOCKS5 is enabled (even without an actual SOCKS5 proxy).
lws_cookie_write_nsc() handles this with a fallback to
lws_hdr_simple_ptr(), but lws_cookie_attach_cookies() did not,
returning -1 immediately when stash was NULL.

This caused cookie jar lookups to silently fail on builds with
LWS_WITH_SOCKS5 enabled (e.g. txiki.js on Linux), while working on
those without it (e.g. Android builds).

Add the same header-based fallback to lws_cookie_attach_cookies(),
matching the existing pattern in lws_cookie_write_nsc().
Signed-off-by: stropee <simon@sirocha.fr>
… in iface field on FreeRTOS/LwIP

Signed-off-by: stropee <simon@sirocha.fr>
On Windows, send() expects int for the third argument (len), but
socks5-client.c was casting the ssize_t value to (size_t).  MSVC
at /W3 warns C4267 about the implicit narrowing from size_t (64-bit)
to int (32-bit), and with /WX the warning becomes a fatal error
(C2220).

Fix the two send() sites by adding an explicit (int) cast guarded
with #if defined(WIN32), matching the existing pattern used in
output.c.

AG: use helper and fixup similar cases

Ref: txiki.js CI build (error C2220 at socks5-client.c:239,64)
We leave lws_buflist as it is since it is a public api.

We introduce an alternative solution lws_buflist2.  It offers a similar
api to lws_buflist, but it is based on lws_dll2_owner.

 - its footprint in the using struct is an lws_buflist2_owner.
 - allocations are tracked using lws_dll2... that solves problems that
   lws_buflist has having to iterate to find the tail, or total size, it
   already always tracks the tail and allocated size.
 - You can set the sanity limit size per-owner (lws_buflist is fixed)
ws: ss: hexdump before assert
Integrate OpenHiTLS as a new TLS backend option for libwebsockets,
providing an alternative to OpenSSL, mbedTLS, and other TLS libraries.

Core changes:
- CMake detection and build configuration for OpenHiTLS
- Complete TLS client and server implementation
- X.509 certificate operations (parse, verify, load)
- Crypto primitives: AES, RSA, EC, Hash operations
- TLS 1.2 and TLS 1.3 support with session management
- SNI, ALPN, and keylog callback support
- BSL_UIO wrapper layer for OpenHiTLS I/O abstraction

Technical details:
- New cmake/FindOpenHITLS.cmake for library detection
- Backend-specific code in lib/tls/openhitls/
- Integration with lws TLS abstraction layer
- Support for both memory and file-based certificates
- Error mapping between OpenHiTLS and lws error codes
rops_perform_user_POLLOUT_h2() ends by calling
lws_wsi_mux_action_pending_writeable_reqs(), which decides POLLOUT purely
from child streams' requested_POLLOUT and clears POLLOUT when no child
wants it.  It ignores the network connection's own queued protocol sends
(wsi->h2.h2n->pps), e.g. a connection- or stream-level WINDOW_UPDATE that
grants the peer receive-window credit.  When such a pps is queued but no
child stream currently wants POLLOUT, POLLOUT is cleared and the pps is
never flushed, so the peer never gets the credit and the transfer stalls.

This is easy to hit on the client with a bodyless request (e.g. a plain
GET): the request stream goes HALF_CLOSED_LOCAL as soon as the headers are
sent with END_STREAM, so no child wants POLLOUT, while the netconn still
needs to emit the WINDOW_UPDATE that opens the receive window.  The
response headers arrive but the body stalls at the flow-control window
(the stream window, or 65535 at the connection level) until the peer
resets the stream.

Fix: keep POLLOUT asserted while the netconn still has pps pending, before
falling through to the child-only reconciler.

Observed only with the mbedtls TLS backend; the byte-identical code under
GnuTLS/OpenSSL happens to flush via different read/POLLOUT interleaving,
which is likely why this has gone unnoticed.
lws-team and others added 22 commits June 28, 2026 12:02
On Windows LWS_ERRNO is WSAGetLastError(), so a full socket send buffer
reports WSAEWOULDBLOCK (10035), not the CRT EWOULDBLOCK. lws_plat_mbedtls_net_send
only matched EAGAIN/EWOULDBLOCK, so a backed-up send (e.g. a large HTTP/2 request
body upload, where the loopback/peer send buffer fills) was misreported as a fatal
MBEDTLS_ERR_NET_SEND_FAILED rather than a retryable WANT_WRITE, tearing down the
connection. The sibling lws_plat_mbedtls_net_recv already checks WSAEWOULDBLOCK;
mirror it in net_send.
Reported-by: Biniam F. Demissie <biniamfd@gmail.com>
This matches how *nix works with it
@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants