From 11b628cccfe14fdcdf6c90893f2b514b04920344 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Wed, 10 Jun 2026 12:41:16 -0700 Subject: [PATCH] dgram: add synchronous Socket.prototype.bindSync() Provides sync non-blocking bind(2), without DNS lookup Signed-off-by: Guy Bedford --- doc/api/dgram.md | 40 ++++++ lib/dgram.js | 67 +++++++++- test/parallel/test-dgram-bind-sync.js | 172 ++++++++++++++++++++++++++ 3 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-dgram-bind-sync.js diff --git a/doc/api/dgram.md b/doc/api/dgram.md index e8efbcfd262b0e..baeaf0e9315c8d 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -363,6 +363,44 @@ socket.bind({ }); ``` +### `socket.bindSync([options])` + + + +* `options` {Object} + * `port` {integer} If omitted or `0`, the operating system will assign an + arbitrary unused port. **Default:** `0`. + * `address` {string} A numeric IP address to bind to. Unlike + [`socket.bind()`][], no DNS resolution is performed, so a host name is not + accepted. If omitted, the operating system binds to all addresses + (`'0.0.0.0'` for `udp4` sockets, `'::'` for `udp6`). +* Returns: {Object} The bound address as returned by [`socket.address()`][]. + +The synchronous counterpart of [`socket.bind()`][]. `bind(2)` is a local, +non-blocking system call, so the bind is performed inline and the resolved +address is returned immediately, including the operating-system-assigned +ephemeral port when `port` is `0`: + +```js +const dgram = require('node:dgram'); + +const socket = dgram.createSocket('udp4'); +const address = socket.bindSync({ address: '0.0.0.0', port: 0 }); +console.log(address); // e.g. { address: '0.0.0.0', family: 'IPv4', port: 53124 } +``` + +A bind failure such as `EADDRINUSE` is thrown synchronously rather than emitted +as an `'error'` event. After `bindSync()` returns, [`socket.address()`][] is +valid synchronously and the `'listening'` event is emitted on the next tick. + +`address` must be a numeric IP literal; `bindSync()` never performs DNS +resolution (asynchronous name resolution being the only genuinely blocking part +of binding). Incoming datagrams continue to be delivered asynchronously via the +[`'message'`][] event. `bindSync()` always binds the socket's own handle and +does not participate in [`cluster`][] handle sharing. + ### `socket.close([callback])`