Permalink
Browse files

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 <vieuxtech@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information...
boneskull authored and Trott committed Jan 13, 2017
1 parent b514bd2 commit 32679c73c11c618d027095d96b00f2a77b243d4d
@@ -225,7 +225,7 @@ never have reason to call this.
If `multicastInterface` is not specified, the operating system will attempt to
drop membership on all valid interfaces.
### socket.send(msg, [offset, length,] port, address[, callback])
### socket.send(msg, [offset, length,] port [, address] [, callback])
<!-- YAML
added: v0.1.99
-->
@@ -234,7 +234,7 @@ added: v0.1.99
* `offset` {Number} Integer. Optional. Offset in the buffer where the message starts.
* `length` {Number} Integer. Optional. Number of bytes in the message.
* `port` {Number} Integer. Destination port.
* `address` {String} Destination hostname or IP address.
* `address` {String} Destination hostname or IP address. Optional.
* `callback` {Function} Called when the message has been sent. Optional.
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.
If `msg` is an array, `offset` and `length` must not be specified.
The `address` argument is a string. If the value of `address` is a host name,
DNS will be used to resolve the address of the host. If the `address` is not
specified or is an empty string, `'127.0.0.1'` or `'::1'` will be used instead.
DNS will be used to resolve the address of the host. If `address` is not
provided or otherwise falsy, `'127.0.0.1'` (for `udp4` sockets) or `'::1'`
(for `udp6` sockets) will be used by default.
If the socket has not been previously bound with a call to `bind`, the socket
is assigned a random port number and is bound to the "all interfaces" address
@@ -283,14 +284,15 @@ client.send(message, 41234, 'localhost', (err) => {
});
```
Example of sending a UDP packet composed of multiple buffers to a random port on `localhost`;
Example of sending a UDP packet composed of multiple buffers to a random port
on `127.0.0.1`;
```js
const dgram = require('dgram');
const buf1 = Buffer.from('Some ');
const buf2 = Buffer.from('bytes');
const client = dgram.createSocket('udp4');
client.send([buf1, buf2], 41234, 'localhost', (err) => {
client.send([buf1, buf2], 41234, (err) => {
client.close();
});
```
@@ -314,9 +314,11 @@ function clearQueue() {
// valid combinations
// send(buffer, offset, length, port, address, callback)
// send(buffer, offset, length, port, address)
// send(buffer, offset, length, port, callback)
// send(buffer, offset, length, port)
// send(bufferOrList, port, address, callback)
// send(bufferOrList, port, address)
// send(bufferOrList, port, callback)
// send(bufferOrList, port)
Socket.prototype.send = function(buffer,
offset,
@@ -355,6 +357,14 @@ Socket.prototype.send = function(buffer,
if (typeof callback !== 'function')
callback = undefined;
if (typeof address === 'function') {
callback = address;
address = undefined;
} else if (address && typeof address !== 'string') {
throw new TypeError('Invalid arguments: address must be a nonempty ' +
'string or falsy');
}
this._healthCheck();
if (this._bindState === BIND_STATE_UNBOUND)
@@ -0,0 +1,51 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dgram = require('dgram');
const port = common.PORT;
const buf = Buffer.from('test');
const client = dgram.createSocket('udp4');
const onMessage = common.mustCall((err, bytes) => {
assert.ifError(err);
assert.strictEqual(bytes, buf.length);
}, 6);
// valid address: false
client.send(buf, port, false, onMessage);
// valid address: empty string
client.send(buf, port, '', onMessage);
// valid address: null
client.send(buf, port, null, onMessage);
// valid address: 0
client.send(buf, port, 0, onMessage);
// valid address: undefined
client.send(buf, port, undefined, onMessage);
// valid address: not provided
client.send(buf, port, onMessage);
const expectedError = new RegExp('^TypeError: Invalid arguments: address ' +
'must be a nonempty string or falsy$');
// invalid address: object
assert.throws(() => {
client.send(buf, port, []);
}, expectedError);
// invalid address: nonzero number
assert.throws(() => {
client.send(buf, port, 1);
}, expectedError);
// invalid address: true
assert.throws(() => {
client.send(buf, port, true);
}, expectedError);
client.unref();
@@ -0,0 +1,17 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const buf = Buffer.alloc(256, 'x');
const onMessage = common.mustCall(function(err, bytes) {
assert.ifError(err);
assert.strictEqual(bytes, buf.length);
client.close();
});
client.send(buf, common.PORT, onMessage);
@@ -0,0 +1,20 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const buf = Buffer.alloc(256, 'x');
const offset = 20;
const len = buf.length - offset;
const onMessage = common.mustCall(function messageSent(err, bytes) {
assert.ifError(err);
assert.notStrictEqual(bytes, buf.length);
assert.strictEqual(bytes, buf.length - offset);
client.close();
});
client.send(buf, offset, len, common.PORT, onMessage);
@@ -0,0 +1,28 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const messageSent = common.mustCall(function messageSent(err, bytes) {
assert.ifError(err);
assert.strictEqual(bytes, buf1.length + buf2.length);
});
const buf1 = Buffer.alloc(256, 'x');
const buf2 = Buffer.alloc(256, 'y');
client.on('listening', function() {
const port = this.address().port;
client.send([buf1, buf2], port, messageSent);
});
client.on('message', common.mustCall(function onMessage(buf) {
const expected = Buffer.concat([buf1, buf2]);
assert.ok(buf.equals(expected), 'message was received correctly');
client.close();
}));
client.bind(0);

0 comments on commit 32679c7

Please sign in to comment.