Skip to content

[NODERAWSOCKETS] Bind-first connect for synchronous getsockname - #27566

Open
guybedford wants to merge 1 commit into
emscripten-core:mainfrom
guybedford:noderawsockets-connect-getsockname
Open

[NODERAWSOCKETS] Bind-first connect for synchronous getsockname#27566
guybedford wants to merge 1 commit into
emscripten-core:mainfrom
guybedford:noderawsockets-connect-getsockname

Conversation

@guybedford

Copy link
Copy Markdown
Collaborator

This fixes an ordering issue in the NODERAWSOCKETS TCP client connect path.

An unbound client connect() created a plain async net.Socket, with saddr/sport only recorded on the async 'connect' event, so getsockname() immediately after a non-blocking connect() returned 0.0.0.0:0. Kernel semantics assign the ephemeral source port synchronously at connect(), so callers that read the local address right after a non-blocking connect raced the event loop (reliably failing under load).

connect() on an unbound socket now binds an ephemeral port first, through the same eager synchronous bindHandle path an explicit bind() takes, then connects through the bound handle:

  • getsockname() reports the assigned port synchronously after connect(), matching kernel behavior
  • the local address updates to the real source address once the connection completes, and the port stays stable
  • both bind primitives (public net.BoundSocket, or the tcp_wrap fallback on older node) are synchronous, so this works across node versions

Test coverage: test_noderawsockets_connect_getsockname asserts the ephemeral port is non-zero immediately after a non-blocking connect() returns, before any event loop turn, and that it is unchanged once connected. The test is plain POSIX and passes natively against the host stack.

Made with AI assistance under my review

An unbound TCP client connect created a plain async net.Socket, with
saddr/sport only recorded on the async 'connect' event, so getsockname()
immediately after a non-blocking connect() returned 0.0.0.0:0. Kernel
semantics assign the ephemeral source port synchronously at connect(), so
callers (e.g. mio) that read the local address right after a non-blocking
connect raced the event loop.

connect() now binds an ephemeral port first through the same eager
synchronous bindHandle path an explicit bind() takes, then connects
through the bound handle, making getsockname() correct up front.
@guybedford
guybedford force-pushed the noderawsockets-connect-getsockname branch from 468d477 to f9fedd7 Compare August 19, 2026 15:53
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.

2 participants