Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dgram: add custom lookup function in sockets #14560

Merged
merged 1 commit into from
Aug 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions doc/api/dgram.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()`][].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to provide the function signature

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied that directly from the net docs for the same feature.

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
Expand Down Expand Up @@ -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
Expand Down
32 changes: 18 additions & 14 deletions lib/dgram.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
47 changes: 47 additions & 0 deletions test/parallel/test-dgram-custom-lookup.js
Original file line number Diff line number Diff line change
@@ -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'
}));
});
}