Skip to content

Commit 458f017

Browse files
santigimenoGaryGSC
authored andcommitted
dgram: add support for UDP connected sockets
Added the `dgram.connect()` and `dgram.disconnect()` methods that associate/disassociate a udp socket to/from a remote address. It optimizes for cases where lots of packets are sent to the same address. Also added the `dgram.remoteAddress()` method to retrieve the associated remote address. Backport-PR-URL: #30480 PR-URL: #26871 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Matteo Collina <[email protected]> (cherry picked from commit 9e96017)
1 parent 0621e25 commit 458f017

18 files changed

+731
-64
lines changed

doc/api/dgram.md

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ added: v0.1.99
4949
The `'close'` event is emitted after a socket is closed with [`close()`][].
5050
Once triggered, no new `'message'` events will be emitted on this socket.
5151

52+
### Event: 'connect'
53+
<!-- YAML
54+
added: REPLACEME
55+
-->
56+
57+
The `'connect'` event is emitted after a socket is associated to a remote
58+
address as a result of a successful [`connect()`][] call.
59+
5260
### Event: 'error'
5361
<!-- YAML
5462
added: v0.1.99
@@ -231,6 +239,34 @@ added: v0.1.99
231239
Close the underlying socket and stop listening for data on it. If a callback is
232240
provided, it is added as a listener for the [`'close'`][] event.
233241

242+
### socket.connect(port[, address][, callback])
243+
<!-- YAML
244+
added: REPLACEME
245+
-->
246+
247+
* `port` {integer}
248+
* `address` {string}
249+
* `callback` {Function} Called when the connection is completed or on error.
250+
251+
Associates the `dgram.Socket` to a remote address and port. Every
252+
message sent by this handle is automatically sent to that destination. Also,
253+
the socket will only receive messages from that remote peer.
254+
Trying to call `connect()` on an already connected socket will result
255+
in an [`ERR_SOCKET_DGRAM_IS_CONNECTED`][] exception. If `address` is not
256+
provided, `'127.0.0.1'` (for `udp4` sockets) or `'::1'` (for `udp6` sockets)
257+
will be used by default. Once the connection is complete, a `'connect'` event
258+
is emitted and the optional `callback` function is called. In case of failure,
259+
the `callback` is called or, failing this, an `'error'` event is emitted.
260+
261+
### socket.disconnect()
262+
<!-- YAML
263+
added: REPLACEME
264+
-->
265+
266+
A synchronous function that disassociates a connected `dgram.Socket` from
267+
its remote address. Trying to call `disconnect()` on an already disconnected
268+
socket will result in an [`ERR_SOCKET_DGRAM_NOT_CONNECTED`][] exception.
269+
234270
### socket.dropMembership(multicastAddress[, multicastInterface])
235271
<!-- YAML
236272
added: v0.6.9
@@ -277,7 +313,18 @@ Calling `socket.ref()` multiples times will have no additional effect.
277313
The `socket.ref()` method returns a reference to the socket so calls can be
278314
chained.
279315

280-
### socket.send(msg[, offset, length], port[, address][, callback])
316+
### socket.remoteAddress()
317+
<!-- YAML
318+
added: REPLACEME
319+
-->
320+
321+
* Returns: {Object}
322+
323+
Returns an object containing the `address`, `family`, and `port` of the remote
324+
endpoint. It throws an [`ERR_SOCKET_DGRAM_NOT_CONNECTED`][] exception if the
325+
socket is not connected.
326+
327+
### socket.send(msg[, offset, length][, port][, address][, callback])
281328
<!-- YAML
282329
added: v0.1.99
283330
changes:
@@ -295,6 +342,9 @@ changes:
295342
pr-url: https://github.com/nodejs/node/pull/4374
296343
description: The `msg` parameter can be an array now. Also, the `offset`
297344
and `length` parameters are optional now.
345+
- version: REPLACEME
346+
pr-url: https://github.com/nodejs/node/pull/26871
347+
description: Added support for sending data on connected sockets.
298348
-->
299349

300350
* `msg` {Buffer|Uint8Array|string|Array} Message to be sent.
@@ -304,8 +354,10 @@ changes:
304354
* `address` {string} Destination hostname or IP address.
305355
* `callback` {Function} Called when the message has been sent.
306356

307-
Broadcasts a datagram on the socket. The destination `port` and `address` must
308-
be specified.
357+
Broadcasts a datagram on the socket.
358+
For connectionless sockets, the destination `port` and `address` must be
359+
specified. Connected sockets, on the other hand, will use their associated
360+
remote endpoint, so the `port` and `address` arguments must not be set.
309361

310362
The `msg` argument contains the message to be sent.
311363
Depending on its type, different behavior can apply. If `msg` is a `Buffer`
@@ -369,6 +421,20 @@ application and operating system. It is important to run benchmarks to
369421
determine the optimal strategy on a case-by-case basis. Generally speaking,
370422
however, sending multiple buffers is faster.
371423

424+
Example of sending a UDP packet using a socket connected to a port on
425+
`localhost`:
426+
427+
```js
428+
const dgram = require('dgram');
429+
const message = Buffer.from('Some bytes');
430+
const client = dgram.createSocket('udp4');
431+
client.connect(41234, 'localhost', (err) => {
432+
client.send(message, (err) => {
433+
client.close();
434+
});
435+
});
436+
```
437+
372438
**A Note about UDP datagram size**
373439

374440
The maximum size of an `IPv4/v6` datagram depends on the `MTU`
@@ -639,10 +705,13 @@ and `udp6` sockets). The bound address and port can be retrieved using
639705

640706
[`'close'`]: #dgram_event_close
641707
[`Error`]: errors.html#errors_class_error
708+
[`ERR_SOCKET_DGRAM_IS_CONNECTED`]: errors.html#errors_err_socket_dgram_is_connected
709+
[`ERR_SOCKET_DGRAM_NOT_CONNECTED`]: errors.html#errors_err_socket_dgram_not_connected
642710
[`EventEmitter`]: events.html
643711
[`System Error`]: errors.html#errors_class_systemerror
644712
[`close()`]: #dgram_socket_close_callback
645713
[`cluster`]: cluster.html
714+
[`connect()`]: #dgram_socket_connect_port_address_callback
646715
[`dgram.Socket#bind()`]: #dgram_socket_bind_options_callback
647716
[`dgram.createSocket()`]: #dgram_dgram_createsocket_options_callback
648717
[`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback

doc/api/errors.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,17 @@ Data could be sent on a socket.
15711571

15721572
An attempt was made to operate on an already closed socket.
15731573

1574+
<a id="ERR_SOCKET_DGRAM_IS_CONNECTED"></a>
1575+
### ERR_SOCKET_DGRAM_IS_CONNECTED
1576+
1577+
A [`dgram.connect()`][] call was made on an already connected socket.
1578+
1579+
<a id="ERR_SOCKET_DGRAM_NOT_CONNECTED"></a>
1580+
### ERR_SOCKET_DGRAM_NOT_CONNECTED
1581+
1582+
A [`dgram.disconnect()`][] or [`dgram.remoteAddress()`][] call was made on a
1583+
disconnected socket.
1584+
15741585
<a id="ERR_SOCKET_DGRAM_NOT_RUNNING"></a>
15751586
### ERR_SOCKET_DGRAM_NOT_RUNNING
15761587

@@ -2140,7 +2151,10 @@ size.
21402151
[`crypto.scrypt()`]: crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback
21412152
[`crypto.scryptSync()`]: crypto.html#crypto_crypto_scryptsync_password_salt_keylen_options
21422153
[`crypto.timingSafeEqual()`]: crypto.html#crypto_crypto_timingsafeequal_a_b
2154+
[`dgram.connect()`]: dgram.html#dgram_socket_connect_port_address_callback
21432155
[`dgram.createSocket()`]: dgram.html#dgram_dgram_createsocket_options_callback
2156+
[`dgram.disconnect()`]: dgram.html#dgram_socket_disconnect
2157+
[`dgram.remoteAddress()`]: dgram.html#dgram_socket_remoteaddress
21442158
[`errno`(3) man page]: http://man7.org/linux/man-pages/man3/errno.3.html
21452159
[`fs.readFileSync`]: fs.html#fs_fs_readfilesync_path_options
21462160
[`fs.readdir`]: fs.html#fs_fs_readdir_path_options_callback

0 commit comments

Comments
 (0)