deno
25cfe2b0 - fix(ext/node): support ChildProcess.send with net.Server handles (#34948)

Commit
70 days ago
fix(ext/node): support ChildProcess.send with net.Server handles (#34948) ## Summary `subprocess.send('server', server)` from `node:child_process`, where `server` is an unlistened `net.createServer()`, threw: ``` error: Uncaught (in promise) Error: Not implemented: ChildProcess.send with non-TCP net.Server handle ``` An unlistened `net.Server` has a `null` underlying handle, and `getIpcHandleInfo` only accepted TCP handles. This makes `ChildProcess.send` with `net.Server` / `net.Socket` handles work in the cases Node supports. ## Changes - **Null handle → plain message.** An unlistened `net.Server` (or detached `net.Socket`) has a null underlying handle. `getIpcHandleInfo` now returns `null` in that case and the message is delivered without a handle, matching Node's `if (!handle) message = message.msg`. This is the exact case in the issue's repro. - **Non-TCP (Pipe / unix-socket) handles.** `net.Server` and `net.Socket` handles backed by a `Pipe` are now transferable. The IPC message records `nativeKind` (`"tcp"` | `"pipe"`) so the receiver reconstructs the correct wrap type. - **`net.Server.prototype.listen` Pipe branch.** A `Pipe` wrap exposes an `fd` getter, so without an explicit handle branch `listen(pipe)` fell into the `options.fd` path and re-opened the already-owned fd, failing with `EEXIST`. - **`uv_pipe_open_listener`** (mirrors the existing `uv_tcp_open_listener`). A pipe opened from an inherited *listening* fd must not eagerly create an `AsyncFd`; otherwise `uv_pipe_listen`'s `UnixListener` registration hits `epoll_ctl(EPOLL_CTL_ADD)` `EEXIST` on the same fd. `PipeWrap::open` dispatches to it for server pipes. ## Tests Adds `tests/specs/node/child_process_ipc_handle/`: - `unlistened_server_main.mjs` — the issue's repro (send an unlistened server; child receives the message with no handle). - `pipe_server_main.mjs` — transfer a listening unix-socket server; child reconstructs a working `net.Server`. Both run under `json` and `advanced` serialization. Full suite (10 tests) passes: `cargo test --test specs -- node::child_process_ipc_handle`. Note: a full connect round-trip over a *transferred unix-socket* server isn't asserted because `closeAfterSend` unlinks the socket file on the parent's `server.close()`, which is inherent to unix sockets (TCP keeps working because the bound port stays valid while the child's dup'd fd listens). Closes #34921 Closes denoland/divybot#502 Co-authored-by: divybot <divybot@users.noreply.github.com> Co-authored-by: Divy Srivastava <me@littledivy.com>
Author
Parents
Loading