Skip to content

Commit 2944ea6

Browse files
cjihrigjasnell
authored andcommitted
dgram: add custom lookup function in sockets
This commit adds support for custom DNS lookup functions in dgram sockets. This is similar to the existing feature in net sockets. Refs: #6189 PR-URL: #14560 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Wyatt Preul <wpreul@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
1 parent b122714 commit 2944ea6

File tree

3 files changed

+86
-31
lines changed

3 files changed

+86
-31
lines changed

doc/api/dgram.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -535,27 +535,30 @@ s.bind(1234, () => {
535535
### dgram.createSocket(options[, callback])
536536
<!-- YAML
537537
added: v0.11.13
538+
changes:
539+
- version: REPLACEME
540+
pr-url: https://github.com/nodejs/node/pull/14560
541+
description: The `lookup` option is supported.
538542
-->
539543

540-
* `options` {Object}
541-
* `callback` {Function} Attached as a listener to `'message'` events.
544+
* `options` {Object} Available options are:
545+
* `type` {string} The family of socket. Must be either `'udp4'` or `'udp6'`.
546+
Required.
547+
* `reuseAddr` {boolean} When `true` [`socket.bind()`][] will reuse the
548+
address, even if another process has already bound a socket on it. Optional.
549+
Defaults to `false`.
550+
* `lookup` {Function} Custom lookup function. Defaults to [`dns.lookup()`][].
551+
Optional.
552+
* `callback` {Function} Attached as a listener for `'message'` events. Optional.
542553
* Returns: {dgram.Socket}
543554

544-
Creates a `dgram.Socket` object. The `options` argument is an object that
545-
should contain a `type` field of either `udp4` or `udp6` and an optional
546-
boolean `reuseAddr` field.
547-
548-
When `reuseAddr` is `true` [`socket.bind()`][] will reuse the address, even if
549-
another process has already bound a socket on it. `reuseAddr` defaults to
550-
`false`. The optional `callback` function is added as a listener for `'message'`
551-
events.
552-
553-
Once the socket is created, calling [`socket.bind()`][] will instruct the
554-
socket to begin listening for datagram messages. When `address` and `port` are
555-
not passed to [`socket.bind()`][] the method will bind the socket to the "all
556-
interfaces" address on a random port (it does the right thing for both `udp4`
557-
and `udp6` sockets). The bound address and port can be retrieved using
558-
[`socket.address().address`][] and [`socket.address().port`][].
555+
Creates a `dgram.Socket` object. Once the socket is created, calling
556+
[`socket.bind()`][] will instruct the socket to begin listening for datagram
557+
messages. When `address` and `port` are not passed to [`socket.bind()`][] the
558+
method will bind the socket to the "all interfaces" address on a random port
559+
(it does the right thing for both `udp4` and `udp6` sockets). The bound address
560+
and port can be retrieved using [`socket.address().address`][] and
561+
[`socket.address().port`][].
559562

560563
### dgram.createSocket(type[, callback])
561564
<!-- YAML
@@ -585,6 +588,7 @@ and `udp6` sockets). The bound address and port can be retrieved using
585588
[`cluster`]: cluster.html
586589
[`dgram.Socket#bind()`]: #dgram_socket_bind_options_callback
587590
[`dgram.createSocket()`]: #dgram_dgram_createsocket_options_callback
591+
[`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback
588592
[`socket.address().address`]: #dgram_socket_address
589593
[`socket.address().port`]: #dgram_socket_address
590594
[`socket.bind()`]: #dgram_socket_bind_port_address_callback

lib/dgram.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,32 @@ var cluster = null;
4646
const errnoException = util._errnoException;
4747
const exceptionWithHostPort = util._exceptionWithHostPort;
4848

49-
function lookup(address, family, callback) {
50-
return dns.lookup(address, family, callback);
51-
}
52-
5349

54-
function lookup4(address, callback) {
50+
function lookup4(lookup, address, callback) {
5551
return lookup(address || '127.0.0.1', 4, callback);
5652
}
5753

5854

59-
function lookup6(address, callback) {
55+
function lookup6(lookup, address, callback) {
6056
return lookup(address || '::1', 6, callback);
6157
}
6258

6359

64-
function newHandle(type) {
60+
function newHandle(type, lookup) {
61+
if (lookup === undefined)
62+
lookup = dns.lookup;
63+
else if (typeof lookup !== 'function')
64+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'lookup', 'function');
65+
6566
if (type === 'udp4') {
6667
const handle = new UDP();
67-
handle.lookup = lookup4;
68+
handle.lookup = lookup4.bind(handle, lookup);
6869
return handle;
6970
}
7071

7172
if (type === 'udp6') {
7273
const handle = new UDP();
73-
handle.lookup = lookup6;
74+
handle.lookup = lookup6.bind(handle, lookup);
7475
handle.bind = handle.bind6;
7576
handle.send = handle.send6;
7677
return handle;
@@ -100,13 +101,15 @@ function _createSocketHandle(address, port, addressType, fd, flags) {
100101

101102
function Socket(type, listener) {
102103
EventEmitter.call(this);
104+
var lookup;
103105

104106
if (type !== null && typeof type === 'object') {
105107
var options = type;
106108
type = options.type;
109+
lookup = options.lookup;
107110
}
108111

109-
var handle = newHandle(type);
112+
var handle = newHandle(type, lookup);
110113
handle.owner = this;
111114

112115
this._handle = handle;
@@ -186,10 +189,11 @@ Socket.prototype.bind = function(port_, address_ /*, callback*/) {
186189
}
187190

188191
// defaulting address for bind to all interfaces
189-
if (!address && this._handle.lookup === lookup4) {
190-
address = '0.0.0.0';
191-
} else if (!address && this._handle.lookup === lookup6) {
192-
address = '::';
192+
if (!address) {
193+
if (this.type === 'udp4')
194+
address = '0.0.0.0';
195+
else
196+
address = '::';
193197
}
194198

195199
// resolve address first
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const dgram = require('dgram');
5+
const dns = require('dns');
6+
7+
{
8+
// Verify that the provided lookup function is called.
9+
const lookup = common.mustCall((host, family, callback) => {
10+
dns.lookup(host, family, callback);
11+
});
12+
13+
const socket = dgram.createSocket({ type: 'udp4', lookup });
14+
15+
socket.bind(common.mustCall(() => {
16+
socket.close();
17+
}));
18+
}
19+
20+
{
21+
// Verify that lookup defaults to dns.lookup().
22+
const originalLookup = dns.lookup;
23+
24+
dns.lookup = common.mustCall((host, family, callback) => {
25+
dns.lookup = originalLookup;
26+
originalLookup(host, family, callback);
27+
});
28+
29+
const socket = dgram.createSocket({ type: 'udp4' });
30+
31+
socket.bind(common.mustCall(() => {
32+
socket.close();
33+
}));
34+
}
35+
36+
{
37+
// Verify that non-functions throw.
38+
[null, true, false, 0, 1, NaN, '', 'foo', {}, Symbol()].forEach((value) => {
39+
assert.throws(() => {
40+
dgram.createSocket({ type: 'udp4', lookup: value });
41+
}, common.expectsError({
42+
code: 'ERR_INVALID_ARG_TYPE',
43+
type: TypeError,
44+
message: 'The "lookup" argument must be of type function'
45+
}));
46+
});
47+
}

0 commit comments

Comments
 (0)