Skip to content

Commit 32679c7

Browse files
boneskullTrott
authored andcommitted
dgram: improve signature of Socket.prototype.send
- Do not require presence of `address` parameter to use `callback` parameter; `address` is *always* optional - Improve exception messaging if `address` is invalid type - If `address` is an invalid type, guarantee a synchronously thrown exception - Update documentation to reflect signature changes - Add coverage around valid, undocumented types for `address` parameter. - Add coverage around known invalid, but uncovered, types for `address` parameter. PR-URL: #10473 Reviewed-By: Sam Roberts <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent b514bd2 commit 32679c7

6 files changed

+134
-6
lines changed

doc/api/dgram.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ never have reason to call this.
225225
If `multicastInterface` is not specified, the operating system will attempt to
226226
drop membership on all valid interfaces.
227227

228-
### socket.send(msg, [offset, length,] port, address[, callback])
228+
### socket.send(msg, [offset, length,] port [, address] [, callback])
229229
<!-- YAML
230230
added: v0.1.99
231231
-->
@@ -234,7 +234,7 @@ added: v0.1.99
234234
* `offset` {Number} Integer. Optional. Offset in the buffer where the message starts.
235235
* `length` {Number} Integer. Optional. Number of bytes in the message.
236236
* `port` {Number} Integer. Destination port.
237-
* `address` {String} Destination hostname or IP address.
237+
* `address` {String} Destination hostname or IP address. Optional.
238238
* `callback` {Function} Called when the message has been sent. Optional.
239239

240240
Broadcasts a datagram on the socket. The destination `port` and `address` must
@@ -251,8 +251,9 @@ respect to [byte length][] and not the character position.
251251
If `msg` is an array, `offset` and `length` must not be specified.
252252

253253
The `address` argument is a string. If the value of `address` is a host name,
254-
DNS will be used to resolve the address of the host. If the `address` is not
255-
specified or is an empty string, `'127.0.0.1'` or `'::1'` will be used instead.
254+
DNS will be used to resolve the address of the host. If `address` is not
255+
provided or otherwise falsy, `'127.0.0.1'` (for `udp4` sockets) or `'::1'`
256+
(for `udp6` sockets) will be used by default.
256257

257258
If the socket has not been previously bound with a call to `bind`, the socket
258259
is assigned a random port number and is bound to the "all interfaces" address
@@ -283,14 +284,15 @@ client.send(message, 41234, 'localhost', (err) => {
283284
});
284285
```
285286

286-
Example of sending a UDP packet composed of multiple buffers to a random port on `localhost`;
287+
Example of sending a UDP packet composed of multiple buffers to a random port
288+
on `127.0.0.1`;
287289

288290
```js
289291
const dgram = require('dgram');
290292
const buf1 = Buffer.from('Some ');
291293
const buf2 = Buffer.from('bytes');
292294
const client = dgram.createSocket('udp4');
293-
client.send([buf1, buf2], 41234, 'localhost', (err) => {
295+
client.send([buf1, buf2], 41234, (err) => {
294296
client.close();
295297
});
296298
```

lib/dgram.js

+10
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,11 @@ function clearQueue() {
314314
// valid combinations
315315
// send(buffer, offset, length, port, address, callback)
316316
// send(buffer, offset, length, port, address)
317+
// send(buffer, offset, length, port, callback)
317318
// send(buffer, offset, length, port)
318319
// send(bufferOrList, port, address, callback)
319320
// send(bufferOrList, port, address)
321+
// send(bufferOrList, port, callback)
320322
// send(bufferOrList, port)
321323
Socket.prototype.send = function(buffer,
322324
offset,
@@ -355,6 +357,14 @@ Socket.prototype.send = function(buffer,
355357
if (typeof callback !== 'function')
356358
callback = undefined;
357359

360+
if (typeof address === 'function') {
361+
callback = address;
362+
address = undefined;
363+
} else if (address && typeof address !== 'string') {
364+
throw new TypeError('Invalid arguments: address must be a nonempty ' +
365+
'string or falsy');
366+
}
367+
358368
this._healthCheck();
359369

360370
if (this._bindState === BIND_STATE_UNBOUND)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const dgram = require('dgram');
5+
6+
const port = common.PORT;
7+
const buf = Buffer.from('test');
8+
const client = dgram.createSocket('udp4');
9+
10+
const onMessage = common.mustCall((err, bytes) => {
11+
assert.ifError(err);
12+
assert.strictEqual(bytes, buf.length);
13+
}, 6);
14+
15+
// valid address: false
16+
client.send(buf, port, false, onMessage);
17+
18+
// valid address: empty string
19+
client.send(buf, port, '', onMessage);
20+
21+
// valid address: null
22+
client.send(buf, port, null, onMessage);
23+
24+
// valid address: 0
25+
client.send(buf, port, 0, onMessage);
26+
27+
// valid address: undefined
28+
client.send(buf, port, undefined, onMessage);
29+
30+
// valid address: not provided
31+
client.send(buf, port, onMessage);
32+
33+
const expectedError = new RegExp('^TypeError: Invalid arguments: address ' +
34+
'must be a nonempty string or falsy$');
35+
36+
// invalid address: object
37+
assert.throws(() => {
38+
client.send(buf, port, []);
39+
}, expectedError);
40+
41+
// invalid address: nonzero number
42+
assert.throws(() => {
43+
client.send(buf, port, 1);
44+
}, expectedError);
45+
46+
// invalid address: true
47+
assert.throws(() => {
48+
client.send(buf, port, true);
49+
}, expectedError);
50+
51+
client.unref();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const dgram = require('dgram');
6+
7+
const client = dgram.createSocket('udp4');
8+
9+
const buf = Buffer.alloc(256, 'x');
10+
11+
const onMessage = common.mustCall(function(err, bytes) {
12+
assert.ifError(err);
13+
assert.strictEqual(bytes, buf.length);
14+
client.close();
15+
});
16+
17+
client.send(buf, common.PORT, onMessage);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
6+
const dgram = require('dgram');
7+
const client = dgram.createSocket('udp4');
8+
9+
const buf = Buffer.alloc(256, 'x');
10+
const offset = 20;
11+
const len = buf.length - offset;
12+
13+
const onMessage = common.mustCall(function messageSent(err, bytes) {
14+
assert.ifError(err);
15+
assert.notStrictEqual(bytes, buf.length);
16+
assert.strictEqual(bytes, buf.length - offset);
17+
client.close();
18+
});
19+
20+
client.send(buf, offset, len, common.PORT, onMessage);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const dgram = require('dgram');
6+
7+
const client = dgram.createSocket('udp4');
8+
9+
const messageSent = common.mustCall(function messageSent(err, bytes) {
10+
assert.ifError(err);
11+
assert.strictEqual(bytes, buf1.length + buf2.length);
12+
});
13+
14+
const buf1 = Buffer.alloc(256, 'x');
15+
const buf2 = Buffer.alloc(256, 'y');
16+
17+
client.on('listening', function() {
18+
const port = this.address().port;
19+
client.send([buf1, buf2], port, messageSent);
20+
});
21+
22+
client.on('message', common.mustCall(function onMessage(buf) {
23+
const expected = Buffer.concat([buf1, buf2]);
24+
assert.ok(buf.equals(expected), 'message was received correctly');
25+
client.close();
26+
}));
27+
28+
client.bind(0);

0 commit comments

Comments
 (0)