diff options
-rw-r--r-- | doc/api/dgram.md | 38 | ||||
-rw-r--r-- | lib/dgram.js | 32 | ||||
-rw-r--r-- | test/parallel/test-dgram-custom-lookup.js | 47 |
3 files changed, 86 insertions, 31 deletions
diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 22fb2b5bbf..c3fcfb0528 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -455,27 +455,30 @@ s.bind(1234, () => { ### dgram.createSocket(options[, callback]) <!-- YAML added: v0.11.13 +changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/14560 + description: The `lookup` option is supported. --> -* `options` {Object} -* `callback` {Function} Attached as a listener to `'message'` events. +* `options` {Object} Available options are: + * `type` {string} The family of socket. Must be either `'udp4'` or `'udp6'`. + Required. + * `reuseAddr` {boolean} When `true` [`socket.bind()`][] will reuse the + address, even if another process has already bound a socket on it. Optional. + Defaults to `false`. + * `lookup` {Function} Custom lookup function. Defaults to [`dns.lookup()`][]. + Optional. +* `callback` {Function} Attached as a listener for `'message'` events. Optional. * Returns: {dgram.Socket} -Creates a `dgram.Socket` object. The `options` argument is an object that -should contain a `type` field of either `udp4` or `udp6` and an optional -boolean `reuseAddr` field. - -When `reuseAddr` is `true` [`socket.bind()`][] will reuse the address, even if -another process has already bound a socket on it. `reuseAddr` defaults to -`false`. The optional `callback` function is added as a listener for `'message'` -events. - -Once the socket is created, calling [`socket.bind()`][] will instruct the -socket to begin listening for datagram messages. When `address` and `port` are -not passed to [`socket.bind()`][] the method will bind the socket to the "all -interfaces" address on a random port (it does the right thing for both `udp4` -and `udp6` sockets). The bound address and port can be retrieved using -[`socket.address().address`][] and [`socket.address().port`][]. +Creates a `dgram.Socket` object. Once the socket is created, calling +[`socket.bind()`][] will instruct the socket to begin listening for datagram +messages. When `address` and `port` are not passed to [`socket.bind()`][] the +method will bind the socket to the "all interfaces" address on a random port +(it does the right thing for both `udp4` and `udp6` sockets). The bound address +and port can be retrieved using [`socket.address().address`][] and +[`socket.address().port`][]. ### dgram.createSocket(type[, callback]) <!-- YAML @@ -505,6 +508,7 @@ and `udp6` sockets). The bound address and port can be retrieved using [`cluster`]: cluster.html [`dgram.Socket#bind()`]: #dgram_socket_bind_options_callback [`dgram.createSocket()`]: #dgram_dgram_createsocket_options_callback +[`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback [`socket.address().address`]: #dgram_socket_address [`socket.address().port`]: #dgram_socket_address [`socket.bind()`]: #dgram_socket_bind_port_address_callback diff --git a/lib/dgram.js b/lib/dgram.js index 178ece8738..9e9806f5b0 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -46,31 +46,32 @@ var cluster = null; const errnoException = util._errnoException; const exceptionWithHostPort = util._exceptionWithHostPort; -function lookup(address, family, callback) { - return dns.lookup(address, family, callback); -} - -function lookup4(address, callback) { +function lookup4(lookup, address, callback) { return lookup(address || '127.0.0.1', 4, callback); } -function lookup6(address, callback) { +function lookup6(lookup, address, callback) { return lookup(address || '::1', 6, callback); } -function newHandle(type) { +function newHandle(type, lookup) { + if (lookup === undefined) + lookup = dns.lookup; + else if (typeof lookup !== 'function') + throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'lookup', 'function'); + if (type === 'udp4') { const handle = new UDP(); - handle.lookup = lookup4; + handle.lookup = lookup4.bind(handle, lookup); return handle; } if (type === 'udp6') { const handle = new UDP(); - handle.lookup = lookup6; + handle.lookup = lookup6.bind(handle, lookup); handle.bind = handle.bind6; handle.send = handle.send6; return handle; @@ -100,13 +101,15 @@ function _createSocketHandle(address, port, addressType, fd, flags) { function Socket(type, listener) { EventEmitter.call(this); + var lookup; if (type !== null && typeof type === 'object') { var options = type; type = options.type; + lookup = options.lookup; } - var handle = newHandle(type); + var handle = newHandle(type, lookup); handle.owner = this; this._handle = handle; @@ -186,10 +189,11 @@ Socket.prototype.bind = function(port_, address_ /*, callback*/) { } // defaulting address for bind to all interfaces - if (!address && this._handle.lookup === lookup4) { - address = '0.0.0.0'; - } else if (!address && this._handle.lookup === lookup6) { - address = '::'; + if (!address) { + if (this.type === 'udp4') + address = '0.0.0.0'; + else + address = '::'; } // resolve address first diff --git a/test/parallel/test-dgram-custom-lookup.js b/test/parallel/test-dgram-custom-lookup.js new file mode 100644 index 0000000000..ec6cef9e25 --- /dev/null +++ b/test/parallel/test-dgram-custom-lookup.js @@ -0,0 +1,47 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const dgram = require('dgram'); +const dns = require('dns'); + +{ + // Verify that the provided lookup function is called. + const lookup = common.mustCall((host, family, callback) => { + dns.lookup(host, family, callback); + }); + + const socket = dgram.createSocket({ type: 'udp4', lookup }); + + socket.bind(common.mustCall(() => { + socket.close(); + })); +} + +{ + // Verify that lookup defaults to dns.lookup(). + const originalLookup = dns.lookup; + + dns.lookup = common.mustCall((host, family, callback) => { + dns.lookup = originalLookup; + originalLookup(host, family, callback); + }); + + const socket = dgram.createSocket({ type: 'udp4' }); + + socket.bind(common.mustCall(() => { + socket.close(); + })); +} + +{ + // Verify that non-functions throw. + [null, true, false, 0, 1, NaN, '', 'foo', {}, Symbol()].forEach((value) => { + assert.throws(() => { + dgram.createSocket({ type: 'udp4', lookup: value }); + }, common.expectsError({ + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "lookup" argument must be of type function' + })); + }); +} |