From 1fefa08a6087d35b78e215414eb581cf899a16a8 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Fri, 24 Jul 2026 15:19:51 -0700 Subject: [PATCH] net: support transferring net.BoundSocket to other threads Signed-off-by: Guy Bedford --- doc/api/errors.md | 12 ++-- doc/api/net.md | 11 ++++ doc/api/worker_threads.md | 4 +- lib/net.js | 65 ++++++++++++++++++- .../test-net-boundsocket-transfer-worker.js | 64 ++++++++++++++++++ test/parallel/test-net-transfer-guards.js | 39 ++++++++++- 6 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 test/parallel/test-net-boundsocket-transfer-worker.js diff --git a/doc/api/errors.md b/doc/api/errors.md index a7a7e6549f68e6..ae8e929dc25bbc 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -3004,8 +3004,9 @@ A call was made and the UDP subsystem was not running. ### `ERR_SOCKET_HANDLE_ADOPTED` An operation was attempted on a [`BoundSocket`][] that had already been adopted -by a [`net.Server`][] or [`net.Socket`][]. Once a bound socket is adopted, its -`address()` and `close()` methods can no longer be used. +by a [`net.Server`][] or [`net.Socket`][], or transferred to another thread. +Once a bound socket is adopted or transferred, its `address()` and `close()` +methods can no longer be used. @@ -3573,9 +3574,10 @@ The `Response` that has been passed to `WebAssembly.compileStreaming` or to ### `ERR_WORKER_HANDLE_NOT_TRANSFERABLE` -An attempt was made to transfer a `net.Socket` or `net.Server` to another thread -via a `worker_threads` `postMessage()` call while it was not in a transferable -state, for example because it had already started reading or had buffered data. +An attempt was made to transfer a `net.Socket`, `net.Server` or +`net.BoundSocket` to another thread via a `worker_threads` `postMessage()` call +while it was not in a transferable state, for example because it had already +started reading, had buffered data, or had already been adopted. diff --git a/doc/api/net.md b/doc/api/net.md index 988bc5669e7ff9..c4d74bf701c24a 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -789,6 +789,13 @@ server.listen(8000); A listening [`net.Server`][] can be transferred the same way, which moves the listening socket itself (and its pending accept queue) to the receiving thread. +An un-adopted TCP [`BoundSocket`][] can also be transferred, which moves the +bound (but not yet listening or connected) socket. This allows a port to be +reserved synchronously on one thread and adopted by a server or outgoing +connection on another. Pipe binds are not transferable. After the transfer, the +source `BoundSocket` behaves as if it had been adopted: `address()`, `fd()` and +`close()` throw [`ERR_SOCKET_HANDLE_ADOPTED`][]. + ### `new net.Socket([options])`