Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,26 @@
prefix internet
# To mark a test as flaky, list the test name in the appropriate section
# below, without ".js", followed by ": PASS,FLAKY". Example:
# sample-test : PASS,FLAKY
[true] # This section applies to all platforms
[$system==win32]
[$system==linux]
# https://github.com/nodejs/node/issues/32946
test-dgram-multicast-ssmv6-multi-process: PASS, FLAKY
[$system==macos]
[$system==solaris] # Also applies to SmartOS
[$system==freebsd]
[$system==aix]
[$system==ibmi]
[$arch==arm]

View File

@ -0,0 +1,64 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const path = require('path');
const exec = require('child_process').exec;
const assert = require('assert');
const fs = require('fs');
const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const npmSandbox = tmpdir.resolve('npm-sandbox');
fs.mkdirSync(npmSandbox);
const homeDir = tmpdir.resolve('home');
fs.mkdirSync(homeDir);
const installDir = tmpdir.resolve('install-dir');
fs.mkdirSync(installDir);
const corepackYarnPath = path.join(
__dirname,
'..',
'..',
'deps',
'corepack',
'dist',
'yarn.js',
);
const pkgContent = JSON.stringify({
dependencies: {
'package-name': fixtures.path('packages/main'),
},
});
const pkgPath = path.join(installDir, 'package.json');
fs.writeFileSync(pkgPath, pkgContent);
const env = { ...process.env,
PATH: path.dirname(process.execPath),
NPM_CONFIG_PREFIX: path.join(npmSandbox, 'npm-prefix'),
NPM_CONFIG_TMP: path.join(npmSandbox, 'npm-tmp'),
HOME: homeDir };
exec(`${process.execPath} ${corepackYarnPath} install`, {
cwd: installDir,
env: env,
}, common.mustCall(handleExit));
function handleExit(error, stdout, stderr) {
const code = error ? error.code : 0;
const signalCode = error ? error.signal : null;
if (code !== 0) {
process.stdout.write(stdout);
process.stderr.write(stderr);
}
assert.strictEqual(code, 0, `yarn install got error code ${code}`);
assert.strictEqual(signalCode, null, `unexpected signal: ${signalCode}`);
assert(fs.existsSync(`${installDir}/node_modules/package-name`));
}

View File

@ -0,0 +1,253 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
if (common.inFreeBSDJail)
common.skip('in a FreeBSD jail');
const assert = require('assert');
const dgram = require('dgram');
const util = require('util');
const networkInterfaces = require('os').networkInterfaces();
const { fork } = require('child_process');
const LOCAL_BROADCAST_HOST = '255.255.255.255';
const TIMEOUT = common.platformTimeout(5000);
const messages = [
Buffer.from('First message to send'),
Buffer.from('Second message to send'),
Buffer.from('Third message to send'),
Buffer.from('Fourth message to send'),
];
let bindAddress = null;
// Take the first non-internal interface as the address for binding.
// Ideally, this should check for whether or not an interface is set up for
// BROADCAST and favor internal/private interfaces.
get_bindAddress: for (const name in networkInterfaces) {
const interfaces = networkInterfaces[name];
for (let i = 0; i < interfaces.length; i++) {
const localInterface = interfaces[i];
if (!localInterface.internal && localInterface.family === 'IPv4') {
bindAddress = localInterface.address;
break get_bindAddress;
}
}
}
assert.ok(bindAddress);
if (process.argv[2] !== 'child') {
const workers = {};
const listeners = 3;
let listening = 0;
let dead = 0;
let i = 0;
let done = 0;
let timer = null;
// Exit the test if it doesn't succeed within TIMEOUT
timer = setTimeout(() => {
console.error('[PARENT] Responses were not received within %d ms.',
TIMEOUT);
console.error('[PARENT] Fail');
killSubprocesses(workers);
process.exit(1);
}, TIMEOUT);
// Launch child processes
for (let x = 0; x < listeners; x++) {
(function() {
const worker = fork(process.argv[1], ['child']);
workers[worker.pid] = worker;
worker.messagesReceived = [];
// Handle the death of workers
worker.on('exit', (code, signal) => {
// Don't consider this the true death if the worker
// has finished successfully
// or if the exit code is 0
if (worker.isDone || code === 0) {
return;
}
dead += 1;
console.error('[PARENT] Worker %d died. %d dead of %d',
worker.pid,
dead,
listeners);
assert.notStrictEqual(signal, null);
if (dead === listeners) {
console.error('[PARENT] All workers have died.');
console.error('[PARENT] Fail');
killSubprocesses(workers);
process.exit(1);
}
});
worker.on('message', (msg) => {
if (msg.listening) {
listening += 1;
if (listening === listeners) {
// All child process are listening, so start sending
sendSocket.sendNext();
}
} else if (msg.message) {
worker.messagesReceived.push(msg.message);
if (worker.messagesReceived.length === messages.length) {
done += 1;
worker.isDone = true;
console.error('[PARENT] %d received %d messages total.',
worker.pid,
worker.messagesReceived.length);
}
if (done === listeners) {
console.error('[PARENT] All workers have received the ' +
'required number of ' +
'messages. Will now compare.');
Object.keys(workers).forEach((pid) => {
const worker = workers[pid];
let count = 0;
worker.messagesReceived.forEach((buf) => {
for (let i = 0; i < messages.length; ++i) {
if (buf.toString() === messages[i].toString()) {
count++;
break;
}
}
});
console.error('[PARENT] %d received %d matching messages.',
worker.pid,
count);
assert.strictEqual(count, messages.length);
});
clearTimeout(timer);
console.error('[PARENT] Success');
killSubprocesses(workers);
}
}
});
})(x);
}
const sendSocket = dgram.createSocket({
type: 'udp4',
reuseAddr: true,
});
// Bind the address explicitly for sending
// INADDR_BROADCAST to only one interface
sendSocket.bind(common.PORT, bindAddress);
sendSocket.on('listening', () => {
sendSocket.setBroadcast(true);
});
sendSocket.on('close', () => {
console.error('[PARENT] sendSocket closed');
});
sendSocket.sendNext = function() {
const buf = messages[i++];
if (!buf) {
try { sendSocket.close(); } catch {
// Continue regardless of error.
}
return;
}
sendSocket.send(
buf,
0,
buf.length,
common.PORT,
LOCAL_BROADCAST_HOST,
(err) => {
assert.ifError(err);
console.error('[PARENT] sent %s to %s:%s',
util.inspect(buf.toString()),
LOCAL_BROADCAST_HOST, common.PORT);
process.nextTick(sendSocket.sendNext);
},
);
};
function killSubprocesses(subprocesses) {
Object.keys(subprocesses).forEach((key) => {
const subprocess = subprocesses[key];
subprocess.kill();
});
}
}
if (process.argv[2] === 'child') {
const receivedMessages = [];
const listenSocket = dgram.createSocket({
type: 'udp4',
reuseAddr: true,
});
listenSocket.on('message', (buf, rinfo) => {
// Receive udp messages only sent from parent
if (rinfo.address !== bindAddress) return;
console.error('[CHILD] %s received %s from %j',
process.pid,
util.inspect(buf.toString()),
rinfo);
receivedMessages.push(buf);
process.send({ message: buf.toString() });
if (receivedMessages.length === messages.length) {
process.nextTick(() => { listenSocket.close(); });
}
});
listenSocket.on('close', () => {
// HACK: Wait to exit the process to ensure that the parent
// process has had time to receive all messages via process.send()
// This may be indicative of some other issue.
setTimeout(() => { process.exit(); }, 1000);
});
listenSocket.on('listening', () => { process.send({ listening: true }); });
listenSocket.bind(common.PORT);
}

View File

@ -0,0 +1,19 @@
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
const assert = require('assert');
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
client.connect(common.PORT, addresses.INVALID_HOST, common.mustCall((err) => {
assert.ok(err.code === 'ENOTFOUND' || err.code === 'EAI_AGAIN');
client.once('error', common.mustCall((err) => {
assert.ok(err.code === 'ENOTFOUND' || err.code === 'EAI_AGAIN');
client.once('connect', common.mustCall(() => client.close()));
client.connect(common.PORT);
}));
client.connect(common.PORT, addresses.INVALID_HOST);
}));

View File

@ -0,0 +1,33 @@
'use strict';
require('../common');
const assert = require('assert');
const dgram = require('dgram');
const multicastAddress = '224.0.0.114';
const setup = dgram.createSocket.bind(dgram, { type: 'udp4', reuseAddr: true });
// addMembership() with valid socket and multicast address should not throw
{
const socket = setup();
socket.addMembership(multicastAddress);
socket.close();
}
// dropMembership() without previous addMembership should throw
{
const socket = setup();
assert.throws(
() => { socket.dropMembership(multicastAddress); },
/^Error: dropMembership EADDRNOTAVAIL$/,
);
socket.close();
}
// dropMembership() after addMembership() should not throw
{
const socket = setup();
socket.addMembership(multicastAddress);
socket.dropMembership(multicastAddress);
socket.close();
}

View File

@ -0,0 +1,235 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
// Skip test in FreeBSD jails.
if (common.inFreeBSDJail)
common.skip('In a FreeBSD jail');
const assert = require('assert');
const dgram = require('dgram');
const fork = require('child_process').fork;
const LOCAL_BROADCAST_HOST = '224.0.0.114';
const LOCAL_HOST_IFADDR = '0.0.0.0';
const TIMEOUT = common.platformTimeout(5000);
const messages = [
Buffer.from('First message to send'),
Buffer.from('Second message to send'),
Buffer.from('Third message to send'),
Buffer.from('Fourth message to send'),
];
const workers = {};
const listeners = 3;
let listening, sendSocket, done, timer, dead;
function launchChildProcess() {
const worker = fork(__filename, ['child']);
workers[worker.pid] = worker;
worker.messagesReceived = [];
// Handle the death of workers.
worker.on('exit', function(code) {
// Don't consider this the true death if the worker has finished
// successfully or if the exit code is 0.
if (worker.isDone || code === 0) {
return;
}
dead += 1;
console.error('[PARENT] Worker %d died. %d dead of %d',
worker.pid,
dead,
listeners);
if (dead === listeners) {
console.error('[PARENT] All workers have died.');
console.error('[PARENT] Fail');
process.exit(1);
}
});
worker.on('message', function(msg) {
if (msg.listening) {
listening += 1;
if (listening === listeners) {
// All child process are listening, so start sending.
sendSocket.sendNext();
}
return;
}
if (msg.message) {
worker.messagesReceived.push(msg.message);
if (worker.messagesReceived.length === messages.length) {
done += 1;
worker.isDone = true;
console.error('[PARENT] %d received %d messages total.',
worker.pid,
worker.messagesReceived.length);
}
if (done === listeners) {
console.error('[PARENT] All workers have received the ' +
'required number of messages. Will now compare.');
Object.keys(workers).forEach(function(pid) {
const worker = workers[pid];
let count = 0;
worker.messagesReceived.forEach(function(buf) {
for (let i = 0; i < messages.length; ++i) {
if (buf.toString() === messages[i].toString()) {
count++;
break;
}
}
});
console.error('[PARENT] %d received %d matching messages.',
worker.pid, count);
assert.strictEqual(count, messages.length);
});
clearTimeout(timer);
console.error('[PARENT] Success');
killSubprocesses(workers);
}
}
});
}
function killSubprocesses(subprocesses) {
Object.keys(subprocesses).forEach(function(key) {
const subprocess = subprocesses[key];
subprocess.kill();
});
}
if (process.argv[2] !== 'child') {
listening = 0;
dead = 0;
let i = 0;
done = 0;
// Exit the test if it doesn't succeed within TIMEOUT.
timer = setTimeout(function() {
console.error('[PARENT] Responses were not received within %d ms.',
TIMEOUT);
console.error('[PARENT] Fail');
killSubprocesses(workers);
process.exit(1);
}, TIMEOUT);
// Launch child processes.
for (let x = 0; x < listeners; x++) {
launchChildProcess(x);
}
sendSocket = dgram.createSocket('udp4');
// The socket is actually created async now.
sendSocket.on('listening', function() {
sendSocket.setTTL(1);
sendSocket.setBroadcast(true);
sendSocket.setMulticastTTL(1);
sendSocket.setMulticastLoopback(true);
sendSocket.setMulticastInterface(LOCAL_HOST_IFADDR);
});
sendSocket.on('close', function() {
console.error('[PARENT] sendSocket closed');
});
sendSocket.sendNext = function() {
const buf = messages[i++];
if (!buf) {
try { sendSocket.close(); } catch {
// Continue regardless of error.
}
return;
}
sendSocket.send(
buf,
0,
buf.length,
common.PORT,
LOCAL_BROADCAST_HOST,
function(err) {
assert.ifError(err);
console.error('[PARENT] sent "%s" to %s:%s',
buf.toString(),
LOCAL_BROADCAST_HOST, common.PORT);
process.nextTick(sendSocket.sendNext);
},
);
};
}
if (process.argv[2] === 'child') {
const receivedMessages = [];
const listenSocket = dgram.createSocket({
type: 'udp4',
reuseAddr: true,
});
listenSocket.on('listening', function() {
listenSocket.addMembership(LOCAL_BROADCAST_HOST, LOCAL_HOST_IFADDR);
listenSocket.on('message', function(buf, rinfo) {
console.error('[CHILD] %s received "%s" from %j', process.pid,
buf.toString(), rinfo);
receivedMessages.push(buf);
process.send({ message: buf.toString() });
if (receivedMessages.length === messages.length) {
// .dropMembership() not strictly needed but here as a sanity check.
listenSocket.dropMembership(LOCAL_BROADCAST_HOST);
process.nextTick(function() {
listenSocket.close();
});
}
});
listenSocket.on('close', function() {
// HACK: Wait to exit the process to ensure that the parent
// process has had time to receive all messages via process.send()
// This may be indicative of some other issue.
setTimeout(function() {
process.exit();
}, common.platformTimeout(1000));
});
process.send({ listening: true });
});
listenSocket.bind(common.PORT);
}

View File

@ -0,0 +1,293 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dgram = require('dgram');
const util = require('util');
if (common.inFreeBSDJail) {
common.skip('in a FreeBSD jail');
return;
}
// All SunOS systems must be able to pass this manual test before the
// following barrier can be removed:
// $ socat UDP-RECVFROM:12356,ip-add-membership=224.0.0.115:127.0.0.1,fork \
// EXEC:hostname &
// $ echo hi |socat STDIO \
// UDP4-DATAGRAM:224.0.0.115:12356,ip-multicast-if=127.0.0.1
if (common.isSunOS) {
common.skip('SunOs is not correctly delivering to loopback multicast.');
return;
}
const networkInterfaces = require('os').networkInterfaces();
const fork = require('child_process').fork;
const MULTICASTS = {
IPv4: ['224.0.0.115', '224.0.0.116', '224.0.0.117'],
IPv6: ['ff02::1:115', 'ff02::1:116', 'ff02::1:117'],
};
const LOOPBACK = { IPv4: '127.0.0.1', IPv6: '::1' };
const ANY = { IPv4: '0.0.0.0', IPv6: '::' };
const FAM = 'IPv4';
// Windows wont bind on multicasts so its filtering is by port.
const PORTS = {};
for (let i = 0; i < MULTICASTS[FAM].length; i++) {
PORTS[MULTICASTS[FAM][i]] = common.PORT + (common.isWindows ? i : 0);
}
const UDP = { IPv4: 'udp4', IPv6: 'udp6' };
const TIMEOUT = common.platformTimeout(5000);
const NOW = Date.now();
const TMPL = (tail) => `${NOW} - ${tail}`;
// Take the first non-internal interface as the other interface to isolate
// from loopback. Ideally, this should check for whether or not this interface
// and the loopback have the MULTICAST flag.
const interfaceAddress = ((networkInterfaces) => {
for (const name in networkInterfaces) {
for (const localInterface of networkInterfaces[name]) {
if (!localInterface.internal && localInterface.family === FAM) {
let interfaceAddress = localInterface.address;
// On Windows, IPv6 would need: `%${localInterface.scopeid}`
if (FAM === 'IPv6')
interfaceAddress += `${interfaceAddress}%${name}`;
return interfaceAddress;
}
}
}
})(networkInterfaces);
assert.ok(interfaceAddress);
const messages = [
{ tail: 'First message to send', mcast: MULTICASTS[FAM][0], rcv: true },
{ tail: 'Second message to send', mcast: MULTICASTS[FAM][0], rcv: true },
{ tail: 'Third message to send', mcast: MULTICASTS[FAM][1], rcv: true,
newAddr: interfaceAddress },
{ tail: 'Fourth message to send', mcast: MULTICASTS[FAM][2] },
{ tail: 'Fifth message to send', mcast: MULTICASTS[FAM][1], rcv: true },
{ tail: 'Sixth message to send', mcast: MULTICASTS[FAM][2], rcv: true,
newAddr: LOOPBACK[FAM] },
];
if (process.argv[2] !== 'child') {
const IFACES = [ANY[FAM], interfaceAddress, LOOPBACK[FAM]];
const workers = {};
const listeners = MULTICASTS[FAM].length * 2;
let listening = 0;
let dead = 0;
let i = 0;
let done = 0;
let timer = null;
const killSubprocesses = (subprocesses) => {
for (const i in subprocesses)
subprocesses[i].kill();
};
// Exit the test if it doesn't succeed within the TIMEOUT.
timer = setTimeout(() => {
console.error('[PARENT] Responses were not received within %d ms.',
TIMEOUT);
console.error('[PARENT] Skip');
killSubprocesses(workers);
common.skip('Check filter policy');
process.exit(1);
}, TIMEOUT);
// Launch the child processes.
for (let i = 0; i < listeners; i++) {
const IFACE = IFACES[i % IFACES.length];
const MULTICAST = MULTICASTS[FAM][i % MULTICASTS[FAM].length];
const messagesNeeded = messages.filter((m) => m.rcv &&
m.mcast === MULTICAST)
.map((m) => TMPL(m.tail));
const worker = fork(process.argv[1],
['child',
IFACE,
MULTICAST,
messagesNeeded.length,
NOW]);
workers[worker.pid] = worker;
worker.messagesReceived = [];
worker.messagesNeeded = messagesNeeded;
// Handle the death of workers.
worker.on('exit', (code) => {
// Don't consider this a true death if the worker has finished
// successfully or if the exit code is 0.
if (worker.isDone || code === 0) {
return;
}
dead += 1;
console.error('[PARENT] Worker %d died. %d dead of %d',
worker.pid,
dead,
listeners);
if (dead === listeners) {
console.error('[PARENT] All workers have died.');
console.error('[PARENT] Fail');
killSubprocesses(workers);
process.exit(1);
}
});
worker.on('message', (msg) => {
if (msg.listening) {
listening += 1;
if (listening === listeners) {
// All child process are listening, so start sending.
sendSocket.sendNext();
}
} else if (msg.message) {
worker.messagesReceived.push(msg.message);
if (worker.messagesReceived.length === worker.messagesNeeded.length) {
done += 1;
worker.isDone = true;
console.error('[PARENT] %d received %d messages total.',
worker.pid,
worker.messagesReceived.length);
}
if (done === listeners) {
console.error('[PARENT] All workers have received the ' +
'required number of ' +
'messages. Will now compare.');
Object.keys(workers).forEach((pid) => {
const worker = workers[pid];
let count = 0;
worker.messagesReceived.forEach((buf) => {
for (let i = 0; i < worker.messagesNeeded.length; ++i) {
if (buf.toString() === worker.messagesNeeded[i]) {
count++;
break;
}
}
});
console.error('[PARENT] %d received %d matching messages.',
worker.pid,
count);
assert.strictEqual(count, worker.messagesNeeded.length,
'A worker received ' +
'an invalid multicast message');
});
clearTimeout(timer);
console.error('[PARENT] Success');
killSubprocesses(workers);
}
}
});
}
const sendSocket = dgram.createSocket({
type: UDP[FAM],
reuseAddr: true,
});
// Don't bind the address explicitly when sending and start with
// the OSes default multicast interface selection.
sendSocket.bind(common.PORT, ANY[FAM]);
sendSocket.on('listening', () => {
console.error(`outgoing iface ${interfaceAddress}`);
});
sendSocket.on('close', () => {
console.error('[PARENT] sendSocket closed');
});
sendSocket.sendNext = () => {
const msg = messages[i++];
if (!msg) {
sendSocket.close();
return;
}
console.error(TMPL(NOW, msg.tail));
const buf = Buffer.from(TMPL(msg.tail));
if (msg.newAddr) {
console.error(`changing outgoing multicast ${msg.newAddr}`);
sendSocket.setMulticastInterface(msg.newAddr);
}
sendSocket.send(
buf,
0,
buf.length,
PORTS[msg.mcast],
msg.mcast,
(err) => {
assert.ifError(err);
console.error('[PARENT] sent %s to %s:%s',
util.inspect(buf.toString()),
msg.mcast, PORTS[msg.mcast]);
process.nextTick(sendSocket.sendNext);
},
);
};
}
if (process.argv[2] === 'child') {
const IFACE = process.argv[3];
const MULTICAST = process.argv[4];
const NEEDEDMSGS = Number(process.argv[5]);
const SESSION = Number(process.argv[6]);
const receivedMessages = [];
console.error(`pid ${process.pid} iface ${IFACE} MULTICAST ${MULTICAST}`);
const listenSocket = dgram.createSocket({
type: UDP[FAM],
reuseAddr: true,
});
listenSocket.on('message', (buf, rinfo) => {
// Examine udp messages only when they were sent by the parent.
if (!buf.toString().startsWith(SESSION)) return;
console.error('[CHILD] %s received %s from %j',
process.pid,
util.inspect(buf.toString()),
rinfo);
receivedMessages.push(buf);
let closecb;
if (receivedMessages.length === NEEDEDMSGS) {
listenSocket.close();
closecb = () => process.exit();
}
process.send({ message: buf.toString() }, closecb);
});
listenSocket.on('listening', () => {
listenSocket.addMembership(MULTICAST, IFACE);
process.send({ listening: true });
});
if (common.isWindows)
listenSocket.bind(PORTS[MULTICAST], ANY[FAM]);
else
listenSocket.bind(common.PORT, MULTICAST);
}

View File

@ -0,0 +1,231 @@
'use strict';
const common = require('../common');
// Skip test in FreeBSD jails.
if (common.inFreeBSDJail)
common.skip('In a FreeBSD jail');
const assert = require('assert');
const dgram = require('dgram');
const fork = require('child_process').fork;
const networkInterfaces = require('os').networkInterfaces();
const GROUP_ADDRESS = '232.1.1.1';
const TIMEOUT = common.platformTimeout(5000);
const messages = [
Buffer.from('First message to send'),
Buffer.from('Second message to send'),
Buffer.from('Third message to send'),
Buffer.from('Fourth message to send'),
];
const workers = {};
const listeners = 3;
let listening, sendSocket, done, timer, dead;
let sourceAddress = null;
// Take the first non-internal interface as the IPv4 address for binding.
// Ideally, this should favor internal/private interfaces.
get_sourceAddress: for (const name in networkInterfaces) {
const interfaces = networkInterfaces[name];
for (let i = 0; i < interfaces.length; i++) {
const localInterface = interfaces[i];
if (!localInterface.internal && localInterface.family === 'IPv4') {
sourceAddress = localInterface.address;
break get_sourceAddress;
}
}
}
assert.ok(sourceAddress);
function launchChildProcess() {
const worker = fork(__filename, ['child']);
workers[worker.pid] = worker;
worker.messagesReceived = [];
// Handle the death of workers.
worker.on('exit', function(code) {
// Don't consider this the true death if the worker has finished
// successfully or if the exit code is 0.
if (worker.isDone || code === 0) {
return;
}
dead += 1;
console.error('[PARENT] Worker %d died. %d dead of %d',
worker.pid,
dead,
listeners);
if (dead === listeners) {
console.error('[PARENT] All workers have died.');
console.error('[PARENT] Fail');
assert.fail();
}
});
worker.on('message', function(msg) {
if (msg.listening) {
listening += 1;
if (listening === listeners) {
// All child process are listening, so start sending.
sendSocket.sendNext();
}
return;
}
if (msg.message) {
worker.messagesReceived.push(msg.message);
if (worker.messagesReceived.length === messages.length) {
done += 1;
worker.isDone = true;
console.error('[PARENT] %d received %d messages total.',
worker.pid,
worker.messagesReceived.length);
}
if (done === listeners) {
console.error('[PARENT] All workers have received the ' +
'required number of messages. Will now compare.');
Object.keys(workers).forEach(function(pid) {
const worker = workers[pid];
let count = 0;
worker.messagesReceived.forEach(function(buf) {
for (let i = 0; i < messages.length; ++i) {
if (buf.toString() === messages[i].toString()) {
count++;
break;
}
}
});
console.error('[PARENT] %d received %d matching messages.',
worker.pid, count);
assert.strictEqual(count, messages.length);
});
clearTimeout(timer);
console.error('[PARENT] Success');
killChildren(workers);
}
}
});
}
function killChildren(children) {
Object.keys(children).forEach(function(key) {
const child = children[key];
child.kill();
});
}
if (process.argv[2] !== 'child') {
listening = 0;
dead = 0;
let i = 0;
done = 0;
// Exit the test if it doesn't succeed within TIMEOUT.
timer = setTimeout(function() {
console.error('[PARENT] Responses were not received within %d ms.',
TIMEOUT);
console.error('[PARENT] Fail');
killChildren(workers);
assert.fail();
}, TIMEOUT);
// Launch child processes.
for (let x = 0; x < listeners; x++) {
launchChildProcess(x);
}
sendSocket = dgram.createSocket('udp4');
// The socket is actually created async now.
sendSocket.on('listening', function() {
sendSocket.setTTL(1);
sendSocket.setBroadcast(true);
sendSocket.setMulticastTTL(1);
sendSocket.setMulticastLoopback(true);
sendSocket.addSourceSpecificMembership(sourceAddress, GROUP_ADDRESS);
});
sendSocket.on('close', function() {
console.error('[PARENT] sendSocket closed');
});
sendSocket.sendNext = function() {
const buf = messages[i++];
if (!buf) {
try { sendSocket.close(); } catch {
// Continue regardless of error.
}
return;
}
sendSocket.send(
buf,
0,
buf.length,
common.PORT,
GROUP_ADDRESS,
function(err) {
assert.ifError(err);
console.error('[PARENT] sent "%s" to %s:%s',
buf.toString(),
GROUP_ADDRESS, common.PORT);
process.nextTick(sendSocket.sendNext);
},
);
};
}
if (process.argv[2] === 'child') {
const receivedMessages = [];
const listenSocket = dgram.createSocket({
type: 'udp4',
reuseAddr: true,
});
listenSocket.on('listening', function() {
listenSocket.setMulticastLoopback(true);
listenSocket.addSourceSpecificMembership(sourceAddress, GROUP_ADDRESS);
listenSocket.on('message', function(buf, rinfo) {
console.error('[CHILD] %s received "%s" from %j', process.pid,
buf.toString(), rinfo);
receivedMessages.push(buf);
process.send({ message: buf.toString() });
if (receivedMessages.length === messages.length) {
// .dropSourceSpecificMembership() not strictly needed,
// it is here as a sanity check.
listenSocket.dropSourceSpecificMembership(sourceAddress, GROUP_ADDRESS);
process.nextTick(function() {
listenSocket.close();
});
}
});
listenSocket.on('close', function() {
// HACK: Wait to exit the process to ensure that the parent
// process has had time to receive all messages via process.send()
// This may be indicative of some other issue.
setTimeout(function() {
process.exit();
}, common.platformTimeout(1000));
});
process.send({ listening: true });
});
listenSocket.bind(common.PORT);
}

View File

@ -0,0 +1,231 @@
'use strict';
const common = require('../common');
// Skip test in FreeBSD jails.
if (common.inFreeBSDJail)
common.skip('In a FreeBSD jail');
const assert = require('assert');
const dgram = require('dgram');
const fork = require('child_process').fork;
const networkInterfaces = require('os').networkInterfaces();
const GROUP_ADDRESS = 'ff3e::1234';
const TIMEOUT = common.platformTimeout(5000);
const messages = [
Buffer.from('First message to send'),
Buffer.from('Second message to send'),
Buffer.from('Third message to send'),
Buffer.from('Fourth message to send'),
];
const workers = {};
const listeners = 3;
let listening, sendSocket, done, timer, dead;
let sourceAddress = null;
// Take the first non-internal interface as the IPv6 address for binding.
// Ideally, this should check favor internal/private interfaces.
get_sourceAddress: for (const name in networkInterfaces) {
const interfaces = networkInterfaces[name];
for (let i = 0; i < interfaces.length; i++) {
const localInterface = interfaces[i];
if (!localInterface.internal && localInterface.family === 'IPv6') {
sourceAddress = localInterface.address;
break get_sourceAddress;
}
}
}
assert.ok(sourceAddress);
function launchChildProcess() {
const worker = fork(__filename, ['child']);
workers[worker.pid] = worker;
worker.messagesReceived = [];
// Handle the death of workers.
worker.on('exit', function(code) {
// Don't consider this the true death if the worker has finished
// successfully or if the exit code is 0.
if (worker.isDone || code === 0) {
return;
}
dead += 1;
console.error('[PARENT] Worker %d died. %d dead of %d',
worker.pid,
dead,
listeners);
if (dead === listeners) {
console.error('[PARENT] All workers have died.');
console.error('[PARENT] Fail');
assert.fail();
}
});
worker.on('message', function(msg) {
if (msg.listening) {
listening += 1;
if (listening === listeners) {
// All child process are listening, so start sending.
sendSocket.sendNext();
}
return;
}
if (msg.message) {
worker.messagesReceived.push(msg.message);
if (worker.messagesReceived.length === messages.length) {
done += 1;
worker.isDone = true;
console.error('[PARENT] %d received %d messages total.',
worker.pid,
worker.messagesReceived.length);
}
if (done === listeners) {
console.error('[PARENT] All workers have received the ' +
'required number of messages. Will now compare.');
Object.keys(workers).forEach(function(pid) {
const worker = workers[pid];
let count = 0;
worker.messagesReceived.forEach(function(buf) {
for (let i = 0; i < messages.length; ++i) {
if (buf.toString() === messages[i].toString()) {
count++;
break;
}
}
});
console.error('[PARENT] %d received %d matching messages.',
worker.pid, count);
assert.strictEqual(count, messages.length);
});
clearTimeout(timer);
console.error('[PARENT] Success');
killChildren(workers);
}
}
});
}
function killChildren(children) {
Object.keys(children).forEach(function(key) {
const child = children[key];
child.kill();
});
}
if (process.argv[2] !== 'child') {
listening = 0;
dead = 0;
let i = 0;
done = 0;
// Exit the test if it doesn't succeed within TIMEOUT.
timer = setTimeout(function() {
console.error('[PARENT] Responses were not received within %d ms.',
TIMEOUT);
console.error('[PARENT] Fail');
killChildren(workers);
assert.fail();
}, TIMEOUT);
// Launch child processes.
for (let x = 0; x < listeners; x++) {
launchChildProcess(x);
}
sendSocket = dgram.createSocket('udp6');
// The socket is actually created async now.
sendSocket.on('listening', function() {
sendSocket.setTTL(1);
sendSocket.setBroadcast(true);
sendSocket.setMulticastTTL(1);
sendSocket.setMulticastLoopback(true);
sendSocket.addSourceSpecificMembership(sourceAddress, GROUP_ADDRESS);
});
sendSocket.on('close', function() {
console.error('[PARENT] sendSocket closed');
});
sendSocket.sendNext = function() {
const buf = messages[i++];
if (!buf) {
try { sendSocket.close(); } catch {
// Continue regardless of error.
}
return;
}
sendSocket.send(
buf,
0,
buf.length,
common.PORT,
GROUP_ADDRESS,
function(err) {
assert.ifError(err);
console.error('[PARENT] sent "%s" to %s:%s',
buf.toString(),
GROUP_ADDRESS, common.PORT);
process.nextTick(sendSocket.sendNext);
},
);
};
}
if (process.argv[2] === 'child') {
const receivedMessages = [];
const listenSocket = dgram.createSocket({
type: 'udp6',
reuseAddr: true,
});
listenSocket.on('listening', function() {
listenSocket.setMulticastLoopback(true);
listenSocket.addSourceSpecificMembership(sourceAddress, GROUP_ADDRESS);
listenSocket.on('message', function(buf, rinfo) {
console.error('[CHILD] %s received "%s" from %j', process.pid,
buf.toString(), rinfo);
receivedMessages.push(buf);
process.send({ message: buf.toString() });
if (receivedMessages.length === messages.length) {
// .dropSourceSpecificMembership() not strictly needed,
// it is here as a sanity check.
listenSocket.dropSourceSpecificMembership(sourceAddress, GROUP_ADDRESS);
process.nextTick(function() {
listenSocket.close();
});
}
});
listenSocket.on('close', function() {
// HACK: Wait to exit the process to ensure that the parent
// process has had time to receive all messages via process.send()
// This may be indicative of some other issue.
setTimeout(function() {
process.exit();
}, common.platformTimeout(1000));
});
process.send({ listening: true });
});
listenSocket.bind(common.PORT);
}

View File

@ -0,0 +1,174 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dns = require('dns');
const net = require('net');
let running = false;
const queue = [];
const dnsPromises = dns.promises;
const isIPv4 = net.isIPv4;
const isIPv6 = net.isIPv6;
dns.setServers([ '8.8.8.8', '8.8.4.4' ]);
function checkWrap(req) {
assert.ok(typeof req === 'object');
}
const checkers = {
checkA(r) {
assert.ok(isIPv4(r.address));
assert.strictEqual(typeof r.ttl, 'number');
assert.strictEqual(r.type, 'A');
},
checkAAAA(r) {
assert.ok(isIPv6(r.address));
assert.strictEqual(typeof r.ttl, 'number');
assert.strictEqual(r.type, 'AAAA');
},
checkCNAME(r) {
assert.ok(r.value);
assert.strictEqual(typeof r.value, 'string');
assert.strictEqual(r.type, 'CNAME');
},
checkMX(r) {
assert.strictEqual(typeof r.exchange, 'string');
assert.strictEqual(typeof r.priority, 'number');
assert.strictEqual(r.type, 'MX');
},
checkNAPTR(r) {
assert.strictEqual(typeof r.flags, 'string');
assert.strictEqual(typeof r.service, 'string');
assert.strictEqual(typeof r.regexp, 'string');
assert.strictEqual(typeof r.replacement, 'string');
assert.strictEqual(typeof r.order, 'number');
assert.strictEqual(typeof r.preference, 'number');
assert.strictEqual(r.type, 'NAPTR');
},
checkNS(r) {
assert.strictEqual(typeof r.value, 'string');
assert.strictEqual(r.type, 'NS');
},
checkPTR(r) {
assert.strictEqual(typeof r.value, 'string');
assert.strictEqual(r.type, 'PTR');
},
checkTXT(r) {
assert.ok(Array.isArray(r.entries));
assert.ok(r.entries.length > 0);
assert.strictEqual(r.type, 'TXT');
},
checkSOA(r) {
assert.strictEqual(typeof r.nsname, 'string');
assert.strictEqual(typeof r.hostmaster, 'string');
assert.strictEqual(typeof r.serial, 'number');
assert.strictEqual(typeof r.refresh, 'number');
assert.strictEqual(typeof r.retry, 'number');
assert.strictEqual(typeof r.expire, 'number');
assert.strictEqual(typeof r.minttl, 'number');
assert.strictEqual(r.type, 'SOA');
},
checkSRV(r) {
assert.strictEqual(typeof r.name, 'string');
assert.strictEqual(typeof r.port, 'number');
assert.strictEqual(typeof r.priority, 'number');
assert.strictEqual(typeof r.weight, 'number');
assert.strictEqual(r.type, 'SRV');
},
};
function TEST(f) {
function next() {
const f = queue.shift();
if (f) {
running = true;
f(done);
}
}
function done() {
running = false;
process.nextTick(next);
}
queue.push(f);
if (!running) {
next();
}
}
function processResult(res) {
assert.ok(Array.isArray(res));
assert.ok(res.length > 0);
const types = {};
res.forEach((obj) => {
types[obj.type] = true;
checkers[`check${obj.type}`](obj);
});
return types;
}
TEST(async function test_sip2sip_for_naptr(done) {
function validateResult(res) {
const types = processResult(res);
assert.ok(types.A && types.NS && types.NAPTR && types.SOA,
`Missing record type, found ${Object.keys(types)}`);
}
validateResult(await dnsPromises.resolve('sip2sip.info', 'ANY'));
const req = dns.resolve(
'sip2sip.info',
'ANY',
common.mustSucceed((ret) => {
validateResult(ret);
done();
}));
checkWrap(req);
});
TEST(async function test_google_for_cname_and_srv(done) {
function validateResult(res) {
const types = processResult(res);
assert.ok(types.SRV);
}
validateResult(await dnsPromises.resolve('_caldav._tcp.google.com', 'ANY'));
const req = dns.resolve(
'_caldav._tcp.google.com',
'ANY',
common.mustSucceed((ret) => {
validateResult(ret);
done();
}));
checkWrap(req);
});
TEST(async function test_ptr(done) {
function validateResult(res) {
const types = processResult(res);
assert.ok(types.PTR);
}
validateResult(await dnsPromises.resolve('8.8.8.8.in-addr.arpa', 'ANY'));
const req = dns.resolve(
'8.8.8.8.in-addr.arpa',
'ANY',
common.mustSucceed((ret) => {
validateResult(ret);
done();
}));
checkWrap(req);
});

View File

@ -0,0 +1,29 @@
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
const assert = require('assert');
const dns = require('dns');
const domain = require('domain');
const methods = [
'resolve4',
'resolve6',
'resolveCname',
'resolveMx',
'resolveNs',
'resolveTlsa',
'resolveTxt',
'resolveSrv',
'resolvePtr',
'resolveNaptr',
'resolveSoa',
];
methods.forEach(function(method) {
const d = domain.create();
d.run(function() {
dns[method](addresses.INET_HOST, common.mustCall(() => {
assert.strictEqual(process.domain, d, `${method} retains domain`);
}));
});
});

View File

@ -0,0 +1,43 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dns = require('dns');
dns.setDefaultResultOrder('ipv4first');
let dnsOrder = dns.getDefaultResultOrder();
assert.ok(dnsOrder === 'ipv4first');
dns.setDefaultResultOrder('ipv6first');
dnsOrder = dns.getDefaultResultOrder();
assert.ok(dnsOrder === 'ipv6first');
dns.setDefaultResultOrder('verbatim');
dnsOrder = dns.getDefaultResultOrder();
assert.ok(dnsOrder === 'verbatim');
{
(async function() {
const result = await dns.promises.lookup('localhost');
const result1 = await dns.promises.lookup('localhost', { order: 'verbatim' });
assert.ok(result !== undefined);
assert.ok(result1 !== undefined);
assert.ok(result.address === result1.address);
assert.ok(result.family === result1.family);
})().then(common.mustCall());
}
{
(async function() {
const result = await dns.promises.lookup('localhost', { order: 'ipv4first' });
assert.ok(result !== undefined);
assert.ok(result.family === 4);
})().then(common.mustCall());
}
if (common.hasIPv6) {
(async function() {
const result = await dns.promises.lookup('localhost', { order: 'ipv6first' });
assert.ok(result !== undefined);
assert.ok(result.family === 6);
})().then(common.mustCall());
}

View File

@ -0,0 +1,69 @@
'use strict';
// Verify that non-ASCII hostnames are handled correctly as IDNA 2008.
//
// * Tests will fail with NXDOMAIN when UTF-8 leaks through to a getaddrinfo()
// that doesn't support IDNA at all.
//
// * "straße.de" will resolve to the wrong address when the resolver supports
// only IDNA 2003 (e.g., glibc until 2.28) because it encodes it wrong.
const { mustCall } = require('../common');
const assert = require('assert');
const dns = require('dns');
const { addresses } = require('../common/internet');
const fixture = {
hostname: 'straße.de',
expectedAddress: '81.169.145.78',
dnsServer: addresses.DNS4_SERVER,
family: 4,
};
// Explicitly use well-behaved DNS servers that are known to be able to resolve
// the query (which is a.k.a xn--strae-oqa.de).
dns.setServers([fixture.dnsServer]);
dns.lookup(
fixture.hostname,
{ family: fixture.family },
mustCall((err, address) => {
if (err && err.errno === 'ESERVFAIL') {
assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
return;
}
assert.ifError(err);
assert.strictEqual(address, fixture.expectedAddress);
}),
);
dns.promises.lookup(fixture.hostname, { family: fixture.family })
.then(({ address }) => {
assert.strictEqual(address, fixture.expectedAddress);
}, (err) => {
if (err && err.errno === 'ESERVFAIL') {
assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
} else {
throw err;
}
}).finally(mustCall());
dns.resolve4(fixture.hostname, mustCall((err, addresses) => {
if (err && err.errno === 'ESERVFAIL') {
assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
return;
}
assert.ifError(err);
assert.deepStrictEqual(addresses, [fixture.expectedAddress]);
}));
const p = new dns.promises.Resolver().resolve4(fixture.hostname);
p.then((addresses) => {
assert.deepStrictEqual(addresses, [fixture.expectedAddress]);
}, (err) => {
if (err && err.errno === 'ESERVFAIL') {
assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
} else {
throw err;
}
}).finally(mustCall());

View File

@ -0,0 +1,249 @@
// Flags: --dns-result-order=ipv4first
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
const assert = require('assert');
const dns = require('dns');
const net = require('net');
const util = require('util');
const isIPv4 = net.isIPv4;
const dnsPromises = dns.promises;
let running = false;
const queue = [];
function TEST(f) {
function next() {
const f = queue.shift();
if (f) {
running = true;
console.log(f.name);
f(done);
}
}
function done() {
running = false;
process.nextTick(next);
}
queue.push(f);
if (!running) {
next();
}
}
function checkWrap(req) {
assert.ok(typeof req === 'object');
}
TEST(async function test_resolve4(done) {
function validateResult(res) {
assert.ok(res.length > 0);
for (let i = 0; i < res.length; i++) {
assert.ok(isIPv4(res[i]));
}
}
validateResult(await dnsPromises.resolve4(addresses.INET4_HOST));
const req = dns.resolve4(
addresses.INET4_HOST,
common.mustSucceed((ips) => {
validateResult(ips);
done();
}));
checkWrap(req);
});
TEST(async function test_reverse_ipv4(done) {
function validateResult(res) {
assert.ok(res.length > 0);
for (let i = 0; i < res.length; i++) {
assert.ok(res[i]);
assert.ok(typeof res[i] === 'string');
}
}
validateResult(await dnsPromises.reverse(addresses.INET4_IP));
const req = dns.reverse(
addresses.INET4_IP,
common.mustSucceed((domains) => {
validateResult(domains);
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_ipv4_explicit(done) {
function validateResult(res) {
assert.ok(net.isIPv4(res.address));
assert.strictEqual(res.family, 4);
}
validateResult(await dnsPromises.lookup(addresses.INET4_HOST, 4));
const req = dns.lookup(
addresses.INET4_HOST, 4,
common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_ipv4_implicit(done) {
function validateResult(res) {
assert.ok(net.isIPv4(res.address));
assert.strictEqual(res.family, 4);
}
validateResult(await dnsPromises.lookup(addresses.INET4_HOST));
const req = dns.lookup(
addresses.INET4_HOST,
common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_ipv4_explicit_object(done) {
function validateResult(res) {
assert.ok(net.isIPv4(res.address));
assert.strictEqual(res.family, 4);
}
validateResult(await dnsPromises.lookup(addresses.INET4_HOST, { family: 4 }));
const req = dns.lookup(addresses.INET4_HOST, {
family: 4,
}, common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_ipv4_hint_addrconfig(done) {
function validateResult(res) {
assert.ok(net.isIPv4(res.address));
assert.strictEqual(res.family, 4);
}
validateResult(await dnsPromises.lookup(addresses.INET4_HOST, {
hints: dns.ADDRCONFIG,
}));
const req = dns.lookup(addresses.INET4_HOST, {
hints: dns.ADDRCONFIG,
}, common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_ip_ipv4(done) {
function validateResult(res) {
assert.strictEqual(res.address, '127.0.0.1');
assert.strictEqual(res.family, 4);
}
validateResult(await dnsPromises.lookup('127.0.0.1'));
const req = dns.lookup('127.0.0.1',
common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_localhost_ipv4(done) {
function validateResult(res) {
assert.strictEqual(res.address, '127.0.0.1');
assert.strictEqual(res.family, 4);
}
validateResult(await dnsPromises.lookup('localhost', 4));
const req = dns.lookup('localhost', 4,
common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_all_ipv4(done) {
function validateResult(res) {
assert.ok(Array.isArray(res));
assert.ok(res.length > 0);
res.forEach((ip) => {
assert.ok(isIPv4(ip.address));
assert.strictEqual(ip.family, 4);
});
}
validateResult(await dnsPromises.lookup(addresses.INET4_HOST, {
all: true,
family: 4,
}));
const req = dns.lookup(
addresses.INET4_HOST,
{ all: true, family: 4 },
common.mustSucceed((ips) => {
validateResult(ips);
done();
}),
);
checkWrap(req);
});
TEST(async function test_lookupservice_ip_ipv4(done) {
function validateResult(res) {
assert.strictEqual(typeof res.hostname, 'string');
assert(res.hostname);
assert(['http', 'www', '80'].includes(res.service));
}
validateResult(await dnsPromises.lookupService('127.0.0.1', 80));
const req = dns.lookupService(
'127.0.0.1', 80,
common.mustSucceed((hostname, service) => {
validateResult({ hostname, service });
done();
}),
);
checkWrap(req);
});
TEST(function test_lookupservice_ip_ipv4_promise(done) {
util.promisify(dns.lookupService)('127.0.0.1', 80)
.then(common.mustCall(({ hostname, service }) => {
assert.strictEqual(typeof hostname, 'string');
assert(hostname.length > 0);
assert(['http', 'www', '80'].includes(service));
done();
}));
});

View File

@ -0,0 +1,240 @@
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
if (!common.hasIPv6)
common.skip('this test, no IPv6 support');
const assert = require('assert');
const dns = require('dns');
const net = require('net');
const dnsPromises = dns.promises;
const isIPv6 = net.isIPv6;
let running = false;
const queue = [];
function TEST(f) {
function next() {
const f = queue.shift();
if (f) {
running = true;
console.log(f.name);
f(done);
}
}
function done() {
running = false;
process.nextTick(next);
}
queue.push(f);
if (!running) {
next();
}
}
function checkWrap(req) {
assert.ok(typeof req === 'object');
}
TEST(async function test_resolve6(done) {
function validateResult(res) {
assert.ok(res.length > 0);
for (let i = 0; i < res.length; i++) {
assert.ok(isIPv6(res[i]));
}
}
validateResult(await dnsPromises.resolve6(addresses.INET6_HOST));
const req = dns.resolve6(
addresses.INET6_HOST,
common.mustSucceed((ips) => {
validateResult(ips);
done();
}));
checkWrap(req);
});
TEST(async function test_reverse_ipv6(done) {
function validateResult(res) {
assert.ok(res.length > 0);
for (let i = 0; i < res.length; i++) {
assert.ok(typeof res[i] === 'string');
}
}
validateResult(await dnsPromises.reverse(addresses.INET6_IP));
const req = dns.reverse(
addresses.INET6_IP,
common.mustSucceed((domains) => {
validateResult(domains);
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_ipv6_explicit(done) {
function validateResult(res) {
assert.ok(isIPv6(res.address));
assert.strictEqual(res.family, 6);
}
validateResult(await dnsPromises.lookup(addresses.INET6_HOST, 6));
const req = dns.lookup(
addresses.INET6_HOST,
6,
common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
// This ends up just being too problematic to test
// TEST(function test_lookup_ipv6_implicit(done) {
// var req = dns.lookup(addresses.INET6_HOST, function(err, ip, family) {
// assert.ifError(err);
// assert.ok(net.isIPv6(ip));
// assert.strictEqual(family, 6);
// done();
// });
// checkWrap(req);
// });
TEST(async function test_lookup_ipv6_explicit_object(done) {
function validateResult(res) {
assert.ok(isIPv6(res.address));
assert.strictEqual(res.family, 6);
}
validateResult(await dnsPromises.lookup(addresses.INET6_HOST, { family: 6 }));
const req = dns.lookup(addresses.INET6_HOST, {
family: 6,
}, common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(function test_lookup_ipv6_hint(done) {
const req = dns.lookup(addresses.INET6_HOST, {
family: 6,
hints: dns.V4MAPPED,
}, common.mustCall((err, ip, family) => {
if (err) {
// FreeBSD does not support V4MAPPED
if (common.isFreeBSD) {
assert(err instanceof Error);
assert.strictEqual(err.code, 'EAI_BADFLAGS');
assert.strictEqual(err.hostname, addresses.INET_HOST);
assert.match(err.message, /getaddrinfo EAI_BADFLAGS/);
done();
return;
}
assert.ifError(err);
}
assert.ok(isIPv6(ip));
assert.strictEqual(family, 6);
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_ip_ipv6(done) {
function validateResult(res) {
assert.ok(isIPv6(res.address));
assert.strictEqual(res.family, 6);
}
validateResult(await dnsPromises.lookup('::1'));
const req = dns.lookup(
'::1',
common.mustSucceed((ip, family) => {
validateResult({ address: ip, family });
done();
}));
checkWrap(req);
});
TEST(async function test_lookup_all_ipv6(done) {
function validateResult(res) {
assert.ok(Array.isArray(res));
assert.ok(res.length > 0);
res.forEach((ip) => {
assert.ok(isIPv6(ip.address),
`Invalid IPv6: ${ip.address.toString()}`);
assert.strictEqual(ip.family, 6);
});
}
validateResult(await dnsPromises.lookup(addresses.INET6_HOST, {
all: true,
family: 6,
}));
const req = dns.lookup(
addresses.INET6_HOST,
{ all: true, family: 6 },
common.mustSucceed((ips) => {
validateResult(ips);
done();
}),
);
checkWrap(req);
});
TEST(function test_lookupservice_ip_ipv6(done) {
const req = dns.lookupService(
'::1', 80,
common.mustCall((err, host, service) => {
if (err) {
// Not skipping the test, rather checking an alternative result,
// i.e. that ::1 may not be configured (e.g. in /etc/hosts)
assert.strictEqual(err.code, 'ENOTFOUND');
return done();
}
assert.strictEqual(typeof host, 'string');
assert(host);
assert(['http', 'www', '80'].includes(service));
done();
}),
);
checkWrap(req);
});
// Disabled because it appears to be not working on Linux.
// TEST(function test_lookup_localhost_ipv6(done) {
// var req = dns.lookup('localhost', 6, function(err, ip, family) {
// assert.ifError(err);
// assert.ok(net.isIPv6(ip));
// assert.strictEqual(family, 6);
//
// done();
// });
//
// checkWrap(req);
// });

View File

@ -0,0 +1,54 @@
'use strict';
require('../common');
const common = require('../common');
const dns = require('dns');
const dnsPromises = dns.promises;
const { addresses } = require('../common/internet');
const assert = require('assert');
assert.rejects(
dnsPromises.lookup(addresses.NOT_FOUND, {
hints: 0,
family: 0,
all: false,
}),
{
code: 'ENOTFOUND',
message: `getaddrinfo ENOTFOUND ${addresses.NOT_FOUND}`,
},
).then(common.mustCall());
assert.rejects(
dnsPromises.lookup(addresses.NOT_FOUND, {
hints: 0,
family: 0,
all: true,
}),
{
code: 'ENOTFOUND',
message: `getaddrinfo ENOTFOUND ${addresses.NOT_FOUND}`,
},
).then(common.mustCall());
dns.lookup(addresses.NOT_FOUND, {
hints: 0,
family: 0,
all: true,
}, common.mustCall((error) => {
assert.strictEqual(error.code, 'ENOTFOUND');
assert.strictEqual(
error.message,
`getaddrinfo ENOTFOUND ${addresses.NOT_FOUND}`,
);
assert.strictEqual(error.syscall, 'getaddrinfo');
assert.strictEqual(error.hostname, addresses.NOT_FOUND);
}));
assert.throws(
() => dnsPromises.lookup(addresses.NOT_FOUND, {
family: 'ipv4',
all: 'all',
}),
{ code: 'ERR_INVALID_ARG_VALUE' },
);

View File

@ -0,0 +1,42 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dnsPromises = require('dns').promises;
// Error when rrtype is invalid.
{
const rrtype = 'DUMMY';
assert.throws(
() => dnsPromises.resolve('example.org', rrtype),
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
message: `The argument 'rrtype' is invalid. Received '${rrtype}'`,
},
);
}
// Error when rrtype is a number.
{
const rrtype = 0;
assert.throws(
() => dnsPromises.resolve('example.org', rrtype),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "rrtype" argument must be of type string. ' +
`Received type ${typeof rrtype} (${rrtype})`,
},
);
}
// Setting rrtype to undefined should work like resolve4.
{
(async function() {
const rrtype = undefined;
const result = await dnsPromises.resolve('example.org', rrtype);
assert.ok(result !== undefined);
assert.ok(result.length > 0);
})().then(common.mustCall());
}

View File

@ -0,0 +1,28 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const dns = require('dns');
// Should not segfault.
// Ref: https://github.com/nodejs/node-v0.x-archive/issues/6244
dns.resolve4('127.0.0.1', common.mustCall());

View File

@ -0,0 +1,18 @@
'use strict';
// We don't care about `err` in the callback function of `dns.resolve4`. We just
// want to test whether `dns.setServers` that is run after `resolve4` will cause
// a crash or not. If it doesn't crash, the test succeeded.
const common = require('../common');
const { addresses } = require('../common/internet');
const dns = require('dns');
dns.resolve4(
addresses.INET4_HOST,
common.mustCall(function(/* err, nameServers */) {
dns.setServers([ addresses.DNS4_SERVER ]);
}));
// Test https://github.com/nodejs/node/issues/14734
dns.resolve4(addresses.INET4_HOST, common.mustCall());

View File

@ -0,0 +1,15 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dns = require('dns');
const dnsPromises = dns.promises;
(async function() {
const result = await dnsPromises.resolveTxt('www.microsoft.com');
assert.strictEqual(result.length, 0);
})().then(common.mustCall());
dns.resolveTxt('www.microsoft.com', function(err, records) {
assert.strictEqual(err, null);
assert.strictEqual(records.length, 0);
});

792
test/internet/test-dns.js Normal file
View File

@ -0,0 +1,792 @@
// Flags: --expose-internals
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
const { internalBinding } = require('internal/test/binding');
const { getSystemErrorName } = require('util');
const assert = require('assert');
const dns = require('dns');
const net = require('net');
const isIPv4 = net.isIPv4;
const isIPv6 = net.isIPv6;
const util = require('util');
const dnsPromises = dns.promises;
let expected = 0;
let completed = 0;
let running = false;
const queue = [];
function TEST(f) {
function next() {
const f = queue.shift();
if (f) {
running = true;
console.log(f.name);
f(done);
}
}
function done() {
running = false;
completed++;
process.nextTick(next);
}
expected++;
queue.push(f);
if (!running) {
next();
}
}
function checkWrap(req) {
assert.strictEqual(typeof req, 'object');
}
TEST(function test_reverse_bogus(done) {
dnsPromises.reverse('bogus ip')
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'EINVAL');
assert.strictEqual(getSystemErrorName(err.errno), 'EINVAL');
}));
assert.throws(() => {
dns.reverse('bogus ip', common.mustNotCall());
}, /^Error: getHostByAddr EINVAL bogus ip$/);
done();
});
TEST(async function test_resolve4_ttl(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.strictEqual(typeof item, 'object');
assert.strictEqual(typeof item.ttl, 'number');
assert.strictEqual(typeof item.address, 'string');
assert.ok(item.ttl >= 0);
assert.ok(isIPv4(item.address));
}
}
validateResult(await dnsPromises.resolve4(addresses.INET4_HOST, {
ttl: true,
}));
const req = dns.resolve4(addresses.INET4_HOST, {
ttl: true,
}, function(err, result) {
assert.ifError(err);
validateResult(result);
done();
});
checkWrap(req);
});
TEST(async function test_resolve6_ttl(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.strictEqual(typeof item, 'object');
assert.strictEqual(typeof item.ttl, 'number');
assert.strictEqual(typeof item.address, 'string');
assert.ok(item.ttl >= 0);
assert.ok(isIPv6(item.address));
}
}
validateResult(await dnsPromises.resolve6(addresses.INET6_HOST, {
ttl: true,
}));
const req = dns.resolve6(addresses.INET6_HOST, {
ttl: true,
}, function(err, result) {
assert.ifError(err);
validateResult(result);
done();
});
checkWrap(req);
});
TEST(async function test_resolveMx(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.strictEqual(typeof item, 'object');
assert.ok(item.exchange);
assert.strictEqual(typeof item.exchange, 'string');
assert.strictEqual(typeof item.priority, 'number');
}
}
validateResult(await dnsPromises.resolveMx(addresses.MX_HOST));
const req = dns.resolveMx(addresses.MX_HOST, function(err, result) {
assert.ifError(err);
validateResult(result);
done();
});
checkWrap(req);
});
TEST(function test_resolveMx_failure(done) {
dnsPromises.resolveMx(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveMx(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveNs(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.ok(item);
assert.strictEqual(typeof item, 'string');
}
}
validateResult(await dnsPromises.resolveNs(addresses.NS_HOST));
const req = dns.resolveNs(addresses.NS_HOST, function(err, names) {
assert.ifError(err);
validateResult(names);
done();
});
checkWrap(req);
});
TEST(function test_resolveNs_failure(done) {
dnsPromises.resolveNs(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveNs(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveSrv(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.strictEqual(typeof item, 'object');
assert.ok(item.name);
assert.strictEqual(typeof item.name, 'string');
assert.strictEqual(typeof item.port, 'number');
assert.strictEqual(typeof item.priority, 'number');
assert.strictEqual(typeof item.weight, 'number');
}
}
validateResult(await dnsPromises.resolveSrv(addresses.SRV_HOST));
const req = dns.resolveSrv(addresses.SRV_HOST, function(err, result) {
assert.ifError(err);
validateResult(result);
done();
});
checkWrap(req);
});
TEST(function test_resolveSrv_failure(done) {
dnsPromises.resolveSrv(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveSrv(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolvePtr(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.ok(item);
assert.strictEqual(typeof item, 'string');
}
}
validateResult(await dnsPromises.resolvePtr(addresses.PTR_HOST));
const req = dns.resolvePtr(addresses.PTR_HOST, function(err, result) {
assert.ifError(err);
validateResult(result);
done();
});
checkWrap(req);
});
TEST(function test_resolvePtr_failure(done) {
dnsPromises.resolvePtr(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolvePtr(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveNaptr(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.strictEqual(typeof item, 'object');
assert.strictEqual(typeof item.flags, 'string');
assert.strictEqual(typeof item.service, 'string');
assert.strictEqual(typeof item.regexp, 'string');
assert.strictEqual(typeof item.replacement, 'string');
assert.strictEqual(typeof item.order, 'number');
assert.strictEqual(typeof item.preference, 'number');
}
}
validateResult(await dnsPromises.resolveNaptr(addresses.NAPTR_HOST));
const req = dns.resolveNaptr(addresses.NAPTR_HOST, function(err, result) {
assert.ifError(err);
validateResult(result);
done();
});
checkWrap(req);
});
TEST(function test_resolveNaptr_failure(done) {
dnsPromises.resolveNaptr(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveNaptr(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveSoa(done) {
function validateResult(result) {
assert.strictEqual(typeof result, 'object');
assert.strictEqual(typeof result.nsname, 'string');
assert.ok(result.nsname.length > 0);
assert.strictEqual(typeof result.hostmaster, 'string');
assert.ok(result.hostmaster.length > 0);
assert.strictEqual(typeof result.serial, 'number');
assert.ok((result.serial > 0) && (result.serial < 4294967295));
assert.strictEqual(typeof result.refresh, 'number');
assert.ok((result.refresh > 0) && (result.refresh < 2147483647));
assert.strictEqual(typeof result.retry, 'number');
assert.ok((result.retry > 0) && (result.retry < 2147483647));
assert.strictEqual(typeof result.expire, 'number');
assert.ok((result.expire > 0) && (result.expire < 2147483647));
assert.strictEqual(typeof result.minttl, 'number');
assert.ok((result.minttl >= 0) && (result.minttl < 2147483647));
}
validateResult(await dnsPromises.resolveSoa(addresses.SOA_HOST));
const req = dns.resolveSoa(addresses.SOA_HOST, function(err, result) {
assert.ifError(err);
validateResult(result);
done();
});
checkWrap(req);
});
TEST(function test_resolveSoa_failure(done) {
dnsPromises.resolveSoa(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveSoa(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveCaa(done) {
function validateResult(result) {
assert.ok(Array.isArray(result),
`expected array, got ${util.inspect(result)}`);
assert.strictEqual(result.length, 1);
assert.strictEqual(typeof result[0].critical, 'number');
assert.strictEqual(result[0].critical, 0);
assert.strictEqual(result[0].issue, 'pki.goog');
}
validateResult(await dnsPromises.resolveCaa(addresses.CAA_HOST));
const req = dns.resolveCaa(addresses.CAA_HOST, function(err, records) {
assert.ifError(err);
validateResult(records);
done();
});
checkWrap(req);
});
TEST(function test_resolveCaa_failure(done) {
dnsPromises.resolveTxt(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveCaa(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveCname(done) {
function validateResult(result) {
assert.ok(result.length > 0);
for (const item of result) {
assert.ok(item);
assert.strictEqual(typeof item, 'string');
}
}
validateResult(await dnsPromises.resolveCname(addresses.CNAME_HOST));
const req = dns.resolveCname(addresses.CNAME_HOST, function(err, names) {
assert.ifError(err);
validateResult(names);
done();
});
checkWrap(req);
});
TEST(function test_resolveCname_failure(done) {
dnsPromises.resolveCname(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveCname(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveTlsa(done) {
function validateResult(result) {
assert.ok(Array.isArray(result));
assert.ok(result.length >= 1);
for (const record of result) {
assert.strictEqual(typeof record.certUsage, 'number');
assert.strictEqual(typeof record.selector, 'number');
assert.strictEqual(typeof record.match, 'number');
assert.ok(record.data instanceof ArrayBuffer);
}
}
validateResult(await dnsPromises.resolveTlsa(addresses.TLSA_HOST));
const req = dns.resolveTlsa(addresses.TLSA_HOST, function(err, records) {
assert.ifError(err);
validateResult(records);
done();
});
checkWrap(req);
});
TEST(function test_resolveTlsa_failure(done) {
dnsPromises.resolveTlsa(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveTlsa(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(async function test_resolveTxt(done) {
function validateResult(result) {
assert.ok(Array.isArray(result[0]));
assert.strictEqual(result.length, 1);
assert(result[0][0].startsWith('v=spf1'));
}
validateResult(await dnsPromises.resolveTxt(addresses.TXT_HOST));
const req = dns.resolveTxt(addresses.TXT_HOST, function(err, records) {
assert.ifError(err);
validateResult(records);
done();
});
checkWrap(req);
});
TEST(function test_resolveTxt_failure(done) {
dnsPromises.resolveTxt(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOTFOUND');
}));
const req = dns.resolveTxt(addresses.NOT_FOUND, function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.strictEqual(result, undefined);
done();
});
checkWrap(req);
});
TEST(function test_lookup_failure(done) {
dnsPromises.lookup(addresses.NOT_FOUND, 4)
.then(common.mustNotCall())
.catch(common.expectsError({ code: dns.NOTFOUND }));
const req = dns.lookup(addresses.NOT_FOUND, 4, (err) => {
assert.ok(err instanceof Error);
assert.strictEqual(err.code, dns.NOTFOUND);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.doesNotMatch(err.message, /ENOENT/);
assert.ok(err.message.includes(addresses.NOT_FOUND));
done();
});
checkWrap(req);
});
TEST(async function test_lookup_ip_all(done) {
function validateResult(result) {
assert.ok(Array.isArray(result));
assert.ok(result.length > 0);
assert.strictEqual(result[0].address, '127.0.0.1');
assert.strictEqual(result[0].family, 4);
}
validateResult(await dnsPromises.lookup('127.0.0.1', { all: true }));
const req = dns.lookup(
'127.0.0.1',
{ all: true },
function(err, ips, family) {
assert.ifError(err);
assert.strictEqual(family, undefined);
validateResult(ips);
done();
},
);
checkWrap(req);
});
TEST(function test_lookup_ip_all_promise(done) {
const req = util.promisify(dns.lookup)('127.0.0.1', { all: true })
.then(function(ips) {
assert.ok(Array.isArray(ips));
assert.ok(ips.length > 0);
assert.strictEqual(ips[0].address, '127.0.0.1');
assert.strictEqual(ips[0].family, 4);
done();
});
checkWrap(req);
});
TEST(function test_lookup_ip_promise(done) {
util.promisify(dns.lookup)('127.0.0.1')
.then(function({ address, family }) {
assert.strictEqual(address, '127.0.0.1');
assert.strictEqual(family, 4);
done();
});
});
TEST(async function test_lookup_null_all(done) {
assert.deepStrictEqual(await dnsPromises.lookup(null, { all: true }), []);
const req = dns.lookup(null, { all: true }, (err, ips) => {
assert.ifError(err);
assert.ok(Array.isArray(ips));
assert.strictEqual(ips.length, 0);
done();
});
checkWrap(req);
});
TEST(async function test_lookup_all_mixed(done) {
function validateResult(result) {
assert.ok(Array.isArray(result));
assert.ok(result.length > 0);
result.forEach(function(ip) {
if (isIPv4(ip.address))
assert.strictEqual(ip.family, 4);
else if (isIPv6(ip.address))
assert.strictEqual(ip.family, 6);
else
assert.fail('unexpected IP address');
});
}
validateResult(await dnsPromises.lookup(addresses.INET_HOST, { all: true }));
const req = dns.lookup(addresses.INET_HOST, {
all: true,
}, function(err, ips) {
assert.ifError(err);
validateResult(ips);
done();
});
checkWrap(req);
});
TEST(function test_lookupservice_invalid(done) {
dnsPromises.lookupService('1.2.3.4', 80)
.then(common.mustNotCall())
.catch(common.expectsError({ code: 'ENOTFOUND' }));
const req = dns.lookupService('1.2.3.4', 80, (err) => {
assert(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND');
assert.match(err.message, /1\.2\.3\.4/);
done();
});
checkWrap(req);
});
TEST(function test_reverse_failure(done) {
dnsPromises.reverse('203.0.113.0')
.then(common.mustNotCall())
.catch(common.expectsError({
code: 'ENOTFOUND',
hostname: '203.0.113.0',
}));
// 203.0.113.0/24 are addresses reserved for (RFC) documentation use only
const req = dns.reverse('203.0.113.0', function(err) {
assert(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code...
assert.strictEqual(err.hostname, '203.0.113.0');
assert.match(err.message, /203\.0\.113\.0/);
done();
});
checkWrap(req);
});
TEST(function test_lookup_failure(done) {
dnsPromises.lookup(addresses.NOT_FOUND)
.then(common.mustNotCall())
.catch(common.expectsError({
code: 'ENOTFOUND',
hostname: addresses.NOT_FOUND,
}));
const req = dns.lookup(addresses.NOT_FOUND, (err) => {
assert(err instanceof Error);
assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code...
assert.strictEqual(err.hostname, addresses.NOT_FOUND);
assert.ok(err.message.includes(addresses.NOT_FOUND));
done();
});
checkWrap(req);
});
TEST(function test_resolve_failure(done) {
const req = dns.resolve4(addresses.NOT_FOUND, (err) => {
assert(err instanceof Error);
switch (err.code) {
case 'ENOTFOUND':
case 'ESERVFAIL':
break;
default:
assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code...
break;
}
assert.strictEqual(err.hostname, addresses.NOT_FOUND);
assert.ok(err.message.includes(addresses.NOT_FOUND));
done();
});
checkWrap(req);
});
let getaddrinfoCallbackCalled = false;
console.log(`looking up ${addresses.INET4_HOST}..`);
const cares = internalBinding('cares_wrap');
const req = new cares.GetAddrInfoReqWrap();
cares.getaddrinfo(req, addresses.INET4_HOST, 4,
/* hints */ 0, /* order */ cares.DNS_ORDER_VERBATIM);
req.oncomplete = function(err, domains) {
assert.strictEqual(err, 0);
console.log(`${addresses.INET4_HOST} = ${domains}`);
assert.ok(Array.isArray(domains));
assert.ok(domains.length >= 1);
assert.strictEqual(typeof domains[0], 'string');
getaddrinfoCallbackCalled = true;
};
process.on('exit', function() {
console.log(`${completed} tests completed`);
assert.strictEqual(running, false);
assert.strictEqual(completed, expected);
assert.ok(getaddrinfoCallbackCalled);
});
// Should not throw.
dns.lookup(addresses.INET6_HOST, 6, common.mustCall());
dns.lookup(addresses.INET_HOST, {}, common.mustCall());
dns.lookupService('0.0.0.0', '0', common.mustCall());
dns.lookupService('0.0.0.0', 0, common.mustCall());
(async function() {
await dnsPromises.lookup(addresses.INET6_HOST, 6);
await dnsPromises.lookup(addresses.INET_HOST, {});
})().then(common.mustCall());

View File

@ -0,0 +1,49 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
// Repeated requests for a domain that fails to resolve
// should trigger the error event after each attempt.
const common = require('../common');
const assert = require('assert');
const http = require('http');
function httpreq(count) {
if (count > 1) return;
const req = http.request({
host: 'not-a-real-domain-name.nobody-would-register-this-as-a-tld',
port: 80,
path: '/',
method: 'GET',
}, common.mustNotCall());
req.on('error', common.mustCall((e) => {
assert.strictEqual(e.code, 'ENOTFOUND');
httpreq(count + 1);
}));
req.end();
}
httpreq(0);

View File

@ -0,0 +1,39 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
if (!common.hasCrypto)
common.skip('missing crypto');
const https = require('https');
const http = require('http');
https.get(`https://${addresses.INET_HOST}/`, common.mustCall((res) => {
res.resume();
}));
http.get(`http://${addresses.INET_HOST}/`, common.mustCall((res) => {
res.resume();
}));

View File

@ -0,0 +1,73 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const http2 = require('http2');
const net = require('net');
const {
HTTP2_HEADER_PATH,
} = http2.constants;
// Create a normal session, as a control case
function normalSession(cb) {
http2.connect('https://google.com', (clientSession) => {
let error = null;
const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' });
req.on('error', (err) => {
error = err;
});
req.on('response', (_headers) => {
req.on('data', (_chunk) => { });
req.on('end', () => {
clientSession.close();
return cb(error);
});
});
});
}
normalSession(common.mustSucceed());
// Create a session using a socket that has not yet finished connecting
function socketNotFinished(done) {
const socket2 = net.connect(443, 'google.com');
http2.connect('https://google.com', { socket2 }, (clientSession) => {
let error = null;
const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' });
req.on('error', (err) => {
error = err;
});
req.on('response', (_headers) => {
req.on('data', (_chunk) => { });
req.on('end', () => {
clientSession.close();
socket2.destroy();
return done(error);
});
});
});
}
socketNotFinished(common.mustSucceed());
// Create a session using a socket that has finished connecting
function socketFinished(done) {
const socket = net.connect(443, 'google.com', () => {
http2.connect('https://google.com', { socket }, (clientSession) => {
let error = null;
const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' });
req.on('error', (err) => {
error = err;
});
req.on('response', (_headers) => {
req.on('data', (_chunk) => { });
req.on('end', () => {
clientSession.close();
return done(error);
});
});
});
});
}
socketFinished(common.mustSucceed());

View File

@ -0,0 +1,20 @@
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const { request } = require('https');
request(
`https://${addresses.INET_HOST}/en`,
// Purposely set this to a low value because we want all connection but the last to fail
{ autoSelectFamily: true, autoSelectFamilyAttemptTimeout: 10 },
(res) => {
assert.strictEqual(res.statusCode, 200);
res.resume();
},
).end();

View File

@ -0,0 +1,31 @@
'use strict';
const common = require('../common');
const https = require('node:https');
const assert = require('node:assert');
const server = https.createServer();
server.on(
'tlsClientError',
common.mustCall((exception, tlsSocket) => {
assert.strictEqual(exception !== undefined, true);
assert.strictEqual(Object.keys(tlsSocket.address()).length !== 0, true);
assert.strictEqual(tlsSocket.localAddress !== undefined, true);
assert.strictEqual(tlsSocket.localPort !== undefined, true);
assert.strictEqual(tlsSocket.remoteAddress !== undefined, true);
assert.strictEqual(tlsSocket.remoteFamily !== undefined, true);
assert.strictEqual(tlsSocket.remotePort !== undefined, true);
}),
);
server.listen(0, () => {
const req = https.request({
hostname: '127.0.0.1',
port: server.address().port,
});
req.on(
'error',
common.mustCall(() => server.close()),
);
req.end();
});

View File

@ -0,0 +1,37 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const https = require('https');
const { spawnSync } = require('child_process');
const child = spawnSync(process.execPath, ['--inspect', '-e', '""']);
const stderr = child.stderr.toString();
const helpUrl = stderr.match(/For help, see: (.+)/)[1];
function check(url, cb) {
https.get(url, { agent: new https.Agent() }, common.mustCall((res) => {
assert(res.statusCode >= 200 && res.statusCode < 400);
if (res.statusCode >= 300)
return check(new URL(res.headers.location, url), cb);
let result = '';
res.setEncoding('utf8');
res.on('data', (data) => {
result += data;
});
res.on('end', common.mustCall(() => {
assert.match(result, />Debugging Node\.js</);
cb();
}));
})).on('error', common.mustNotCall);
}
check(helpUrl, common.mustCall());

View File

@ -0,0 +1,128 @@
'use strict';
const common = require('../common');
const { addresses: { INET6_IP, INET4_IP } } = require('../common/internet');
const { createMockedLookup } = require('../common/dns');
const assert = require('assert');
const { createConnection } = require('net');
//
// When testing this is MacOS, remember that the last connection will have no timeout at Node.js
// level but only at operating system one.
//
// The default for MacOS is 75 seconds. It can be changed by doing:
//
// sudo sysctl net.inet.tcp.keepinit=VALUE_IN_MS
//
// Test that all failure events are emitted when trying a single IP (which means autoselectfamily is bypassed)
{
const pass = common.mustCallAtLeast(1);
const connection = createConnection({
host: 'example.org',
port: 10,
lookup: createMockedLookup(INET4_IP),
autoSelectFamily: true,
autoSelectFamilyAttemptTimeout: 10,
});
connection.on('connectionAttempt', (address, port, family) => {
assert.strictEqual(address, INET4_IP);
assert.strictEqual(port, 10);
assert.strictEqual(family, 4);
pass();
});
connection.on('connectionAttemptFailed', (address, port, family, error) => {
assert.strictEqual(address, INET4_IP);
assert.strictEqual(port, 10);
assert.strictEqual(family, 4);
assert.ok(
error.code.match(/ECONNREFUSED|ENETUNREACH|EHOSTUNREACH|ETIMEDOUT/),
`Received unexpected error code ${error.code}`,
);
pass();
});
connection.on('ready', () => {
pass();
connection.destroy();
});
connection.on('error', () => {
pass();
connection.destroy();
});
setTimeout(() => {
pass();
process.exit(0);
}, 5000).unref();
}
// Test that all events are emitted when trying multiple IPs
{
const pass = common.mustCallAtLeast(1);
const connection = createConnection({
host: 'example.org',
port: 10,
lookup: createMockedLookup(INET6_IP, INET4_IP),
autoSelectFamily: true,
autoSelectFamilyAttemptTimeout: 10,
});
const addresses = [
{ address: INET6_IP, port: 10, family: 6 },
{ address: INET6_IP, port: 10, family: 6 },
{ address: INET4_IP, port: 10, family: 4 },
{ address: INET4_IP, port: 10, family: 4 },
];
connection.on('connectionAttempt', (address, port, family) => {
const expected = addresses.shift();
assert.strictEqual(address, expected.address);
assert.strictEqual(port, expected.port);
assert.strictEqual(family, expected.family);
pass();
});
connection.on('connectionAttemptFailed', (address, port, family, error) => {
const expected = addresses.shift();
assert.strictEqual(address, expected.address);
assert.strictEqual(port, expected.port);
assert.strictEqual(family, expected.family);
assert.ok(
error.code.match(/ECONNREFUSED|ENETUNREACH|EHOSTUNREACH|ETIMEDOUT/),
`Received unexpected error code ${error.code}`,
);
pass();
});
connection.on('ready', () => {
pass();
connection.destroy();
});
connection.on('error', () => {
pass();
connection.destroy();
});
setTimeout(() => {
pass();
process.exit(0);
}, 5000).unref();
}

View File

@ -0,0 +1,54 @@
'use strict';
const common = require('../common');
const { addresses: { INET6_IP, INET4_IP } } = require('../common/internet');
const { createMockedLookup } = require('../common/dns');
const assert = require('assert');
const { createConnection } = require('net');
//
// When testing this is MacOS, remember that the last connection will have no timeout at Node.js
// level but only at operating system one.
//
// The default for MacOS is 75 seconds. It can be changed by doing:
//
// sudo sysctl net.inet.tcp.keepinit=VALUE_IN_MS
//
// Depending on the network, it might be impossible to obtain a timeout in 10ms,
// which is the minimum value allowed by network family autoselection.
// At the time of writing (Dec 2023), the network times out on local machine and in the Node CI,
// but it does not on GitHub actions runner.
// Therefore, after five seconds we just consider this test as passed.
// Test that if a connection attempt times out and the socket is destroyed before the
// next attempt starts then the process does not crash
{
const connection = createConnection({
host: 'example.org',
port: 443,
lookup: createMockedLookup(INET4_IP, INET6_IP),
autoSelectFamily: true,
autoSelectFamilyAttemptTimeout: 10,
});
const pass = common.mustCall();
connection.on('connectionAttemptTimeout', (address, port, family) => {
assert.strictEqual(address, INET4_IP);
assert.strictEqual(port, 443);
assert.strictEqual(family, 4);
connection.destroy();
pass();
});
connection.on('ready', () => {
pass();
connection.destroy();
});
setTimeout(() => {
pass();
process.exit(0);
}, 5000).unref();
}

View File

@ -0,0 +1,36 @@
'use strict';
const common = require('../common');
const { addresses } = require('../common/internet');
const assert = require('assert');
const { connect } = require('net');
//
// When testing this is MacOS, remember that the last connection will have no timeout at Node.js
// level but only at operating system one.
//
// The default for MacOS is 75 seconds. It can be changed by doing:
//
// sudo sysctl net.inet.tcp.keepinit=VALUE_IN_MS
//
// Test that when all errors are returned when no connections succeeded and that the close event is emitted
{
const connection = connect({
host: addresses.INET_HOST,
port: 10,
autoSelectFamily: true,
// Purposely set this to a low value because we want all non last connection to fail due to early timeout
autoSelectFamilyAttemptTimeout: 10,
});
connection.on('close', common.mustCall());
connection.on('ready', common.mustNotCall());
connection.on('error', common.mustCall((error) => {
assert.ok(connection.autoSelectFamilyAttemptedAddresses.length > 0);
assert.strictEqual(error.constructor.name, 'AggregateError');
assert.ok(error.errors.length > 0);
}));
}

View File

@ -0,0 +1,50 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
// This example attempts to time out before the connection is established
// https://groups.google.com/forum/#!topic/nodejs/UE0ZbfLt6t8
// https://groups.google.com/forum/#!topic/nodejs-dev/jR7-5UDqXkw
const common = require('../common');
const net = require('net');
const assert = require('assert');
const start = new Date();
const T = 100;
// 192.0.2.1 is part of subnet assigned as "TEST-NET" in RFC 5737.
// For use solely in documentation and example source code.
// In short, it should be unreachable.
// In practice, it's a network black hole.
const socket = net.createConnection(9999, '192.0.2.1');
socket.setTimeout(T);
socket.on('timeout', common.mustCall(function() {
console.error('timeout');
const now = new Date();
assert.ok(now - start < T + 500);
socket.destroy();
}));
socket.on('connect', common.mustNotCall());

View File

@ -0,0 +1,30 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const net = require('net');
const client = net.createConnection(53, '8.8.8.8', function() {
client.unref();
});
client.on('close', common.mustNotCall());

View File

@ -0,0 +1,34 @@
'use strict';
// This tests support for the dns module in snapshot.
require('../common');
const assert = require('assert');
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
const {
addresses: { INET4_HOST },
} = require('../common/internet');
const entry = fixtures.path('snapshot', 'dns-lookup.js');
const env = {
NODE_TEST_HOST: INET4_HOST,
NODE_TEST_PROMISE: 'false',
};
tmpdir.refresh();
function checkOutput(stderr, stdout) {
assert.match(stdout, /address: "\d+\.\d+\.\d+\.\d+"/);
assert.match(stdout, /family: 4/);
assert.strictEqual(stdout.trim().split('\n').length, 2);
}
{
const { stderr, stdout } = buildSnapshot(entry, env);
checkOutput(stderr, stdout);
}
{
const { stderr, stdout } = runWithSnapshot(entry, env);
checkOutput(stderr, stdout);
}

View File

@ -0,0 +1,36 @@
'use strict';
// This tests support for the dns module in snapshot.
require('../common');
const assert = require('assert');
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
const {
addresses: { DNS4_SERVER, INET4_IP, INET4_HOST },
} = require('../common/internet');
const entry = fixtures.path('snapshot', 'dns-resolve.js');
const env = {
NODE_TEST_IP: INET4_IP,
NODE_TEST_HOST: INET4_HOST,
NODE_TEST_DNS: DNS4_SERVER,
NODE_TEST_PROMISE: 'false',
};
tmpdir.refresh();
function checkOutput(stderr, stdout) {
assert(stdout.includes('hostnames: ['));
assert(stdout.includes('addresses: ['));
assert.strictEqual(stdout.trim().split('\n').length, 2);
}
{
const { stderr, stdout } = buildSnapshot(entry, env);
checkOutput(stderr, stdout);
}
{
const { stderr, stdout } = runWithSnapshot(entry, env);
checkOutput(stderr, stdout);
}

View File

@ -0,0 +1,54 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
// Test interaction of compiled-in CAs with user-provided CAs.
const assert = require('assert');
const fs = require('fs');
const fixtures = require('../common/fixtures');
const tls = require('tls');
function filenamePEM(n) {
return fixtures.path('keys', `${n}.pem`);
}
function loadPEM(n) {
return fs.readFileSync(filenamePEM(n));
}
const caCert = loadPEM('ca1-cert');
const opts = {
host: 'www.nodejs.org',
port: 443,
rejectUnauthorized: true,
};
// Success relies on the compiled in well-known root CAs
tls.connect(opts, common.mustCall(end));
// The .ca option replaces the well-known roots, so connection fails.
opts.ca = caCert;
tls.connect(opts, fail).on('error', common.mustCall((err) => {
assert.strictEqual(err.message, 'unable to get local issuer certificate');
}));
function fail() {
assert.fail('should fail to connect');
}
// New secure contexts have the well-known root CAs.
opts.secureContext = tls.createSecureContext();
tls.connect(opts, common.mustCall(end));
// Explicit calls to addCACert() add to the default well-known roots, instead
// of replacing, so connection still succeeds.
opts.secureContext.context.addCACert(caCert);
tls.connect(opts, common.mustCall(end));
function end() {
this.end();
}

View File

@ -0,0 +1,22 @@
'use strict';
const common = require('../common');
const { addresses: { INET_HOST } } = require('../common/internet');
if (!common.hasCrypto) {
common.skip('missing crypto');
}
const { Socket } = require('net');
const { TLSSocket } = require('tls');
// Test that TLS connecting works with autoSelectFamily when using a backing socket
{
const socket = new Socket();
const secureSocket = new TLSSocket(socket);
secureSocket.on('connect', common.mustCall(() => secureSocket.end()));
socket.connect({ host: INET_HOST, port: 443, servername: INET_HOST });
secureSocket.connect({ host: INET_HOST, port: 443, servername: INET_HOST });
}

View File

@ -0,0 +1,34 @@
'use strict';
const common = require('../common');
const { addresses: { INET_HOST } } = require('../common/internet');
if (!common.hasCrypto) {
common.skip('missing crypto');
}
const { connect } = require('tls');
// Test that TLS connecting works without autoSelectFamily
{
const socket = connect({
host: INET_HOST,
port: 443,
servername: INET_HOST,
autoSelectFamily: false,
});
socket.on('secureConnect', common.mustCall(() => socket.end()));
}
// Test that TLS connecting works with autoSelectFamily
{
const socket = connect({
host: INET_HOST,
port: 443,
servername: INET_HOST,
autoSelectFamily: true,
});
socket.on('secureConnect', common.mustCall(() => socket.end()));
}

View File

@ -0,0 +1,74 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const cp = require('child_process');
const tmpdir = require('../common/tmpdir');
const fs = require('fs');
const util = require('util');
const { isMainThread } = require('worker_threads');
if (!isMainThread) {
common.skip('process.chdir is not available in Workers');
}
const traceFile = 'node_trace.1.log';
tmpdir.refresh();
process.chdir(tmpdir.path);
const test_str = 'const dns = require("dns");' +
'const options = {' +
' family: 4,' +
' hints: dns.ADDRCONFIG | dns.V4MAPPED,' +
'};';
const tests = {
'lookup': 'dns.lookup("example.com", options, (err, address, family) => {});',
'lookupService': 'dns.lookupService("127.0.0.1", 22, ' +
'(err, hostname, service) => {});',
'reverse': 'dns.reverse("8.8.8.8", (err, hostnames) => {});',
'resolveAny': 'dns.resolveAny("example.com", (err, res) => {});',
'resolve4': 'dns.resolve4("example.com", (err, res) => {});',
'resolve6': 'dns.resolve6("example.com", (err, res) => {});',
'resolveCaa': 'dns.resolveCaa("example.com", (err, res) => {});',
'resolveCname': 'dns.resolveCname("example.com", (err, res) => {});',
'resolveMx': 'dns.resolveMx("example.com", (err, res) => {});',
'resolveNs': 'dns.resolveNs("example.com", (err, res) => {});',
'resolveTlsa': 'dns.resolveTlsa("example.com", (err, res) => {});',
'resolveTxt': 'dns.resolveTxt("example.com", (err, res) => {});',
'resolveSrv': 'dns.resolveSrv("example.com", (err, res) => {});',
'resolvePtr': 'dns.resolvePtr("example.com", (err, res) => {});',
'resolveNaptr': 'dns.resolveNaptr("example.com", (err, res) => {});',
'resolveSoa': 'dns.resolveSoa("example.com", (err, res) => {});',
};
for (const tr in tests) {
const proc = cp.spawnSync(process.execPath,
[ '--trace-event-categories',
'node.dns.native',
'-e',
test_str + tests[tr],
],
{ encoding: 'utf8' });
// Make sure the operation is successful.
// Don't use assert with a custom message here. Otherwise the
// inspection in the message is done eagerly and wastes a lot of CPU
// time.
if (proc.status !== 0) {
throw new Error(`${tr}:\n${util.inspect(proc)}`);
}
const file = tmpdir.resolve(traceFile);
const data = fs.readFileSync(file);
const traces = JSON.parse(data.toString()).traceEvents
.filter((trace) => trace.cat !== '__metadata');
assert(traces.length > 0);
// DNS native trace events should be generated.
assert(traces.some((trace) => {
return (trace.name === tr && trace.pid === proc.pid);
}));
}

View File

@ -0,0 +1,65 @@
'use strict';
// Test to validate massive dns lookups do not block filesystem I/O
// (or any fast I/O). Prior to https://github.com/libuv/libuv/pull/1845
// few back-to-back dns lookups were sufficient to engage libuv
// threadpool workers in a blocking manner, throttling other work items
// that need pool resources. Start slow and fast I/Os together, make sure
// fast I/O can complete in at least in 1/100th of time for slow I/O.
// TEST TIME TO COMPLETION: ~5 seconds.
const common = require('../common');
const dns = require('dns');
const fs = require('fs');
const assert = require('assert');
const start = Date.now();
const slowIOmax = 100;
let slowIOcount = 0;
let fastIOdone = false;
let slowIOend, fastIOend;
function onResolve() {
slowIOcount++;
if (slowIOcount === slowIOmax) {
slowIOend = Date.now();
// Conservative expectation: finish disc I/O
// at least by when the net I/O completes.
assert.ok(fastIOdone,
'fast I/O was throttled due to threadpool congestion.');
// More realistic expectation: finish disc I/O at least within
// a time duration that is half of net I/O.
// Ideally the slow I/O should not affect the fast I/O as those
// have two different thread-pool buckets. However, this could be
// highly load / platform dependent, so don't be very greedy.
const fastIOtime = fastIOend - start;
const slowIOtime = slowIOend - start;
const expectedMax = slowIOtime / 2;
assert.ok(fastIOtime < expectedMax,
'fast I/O took longer to complete, ' +
`actual: ${fastIOtime}, expected: ${expectedMax}`);
}
}
for (let i = 0; i < slowIOmax; i++) {
// We need to refresh the domain string everytime,
// otherwise the TCP stack that cache the previous lookup
// returns result from memory, breaking all our Math.
dns.lookup(`${randomDomain()}.com`, {}, common.mustCall(onResolve));
}
fs.readFile(__filename, common.mustCall(() => {
fastIOend = Date.now();
fastIOdone = true;
}));
function randomDomain() {
const d = Buffer.alloc(10);
for (let i = 0; i < 10; i++)
d[i] = 97 + (Math.round(Math.random() * 13247)) % 26;
return d.toString();
}

6
test/internet/testcfg.py Normal file
View File

@ -0,0 +1,6 @@
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import testpy
def GetConfiguration(context, root):
return testpy.SimpleTestConfiguration(context, root, 'internet')