From 0c8219c83903e2fbf0a239aabf2700f3074a7e73 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sat, 23 Apr 2022 16:56:41 +0100 Subject: [PATCH 01/35] feat: first pass support of node pipe compat --- node/internal_binding/_listen.ts | 15 ++ node/internal_binding/pipe_wrap.ts | 262 ++++++++++++++++++++++++++--- node/internal_binding/tcp_wrap.ts | 78 ++++----- node/net.ts | 2 +- 4 files changed, 288 insertions(+), 69 deletions(-) create mode 100644 node/internal_binding/_listen.ts diff --git a/node/internal_binding/_listen.ts b/node/internal_binding/_listen.ts new file mode 100644 index 000000000000..2aa93585e02c --- /dev/null +++ b/node/internal_binding/_listen.ts @@ -0,0 +1,15 @@ +/** + * @param n Number to act on. + * @return The number rounded up to the nearest power of 2. + */ +export function ceilPowOf2(n: number) { + const roundPowOf2 = 1 << (31 - Math.clz32(n)); + + return roundPowOf2 < n ? roundPowOf2 * 2 : roundPowOf2; +} + +/** Initial backoff delay of 5ms following a temporary accept failure. */ +export const INITIAL_ACCEPT_BACKOFF_DELAY = 5; + +/** Max backoff delay of 1s following a temporary accept failure. */ +export const MAX_ACCEPT_BACKOFF_DELAY = 1000; diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index bb526590cffb..f47e1bf51c46 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -28,6 +28,15 @@ import { notImplemented } from "../_utils.ts"; import { unreachable } from "../../testing/asserts.ts"; import { ConnectionWrap } from "./connection_wrap.ts"; import { AsyncWrap, providerType } from "./async_wrap.ts"; +import { LibuvStreamWrap } from "./stream_wrap.ts"; +import { codeMap } from "./uv.ts"; +import { delay } from "../../async/mod.ts"; +import { + ceilPowOf2, + INITIAL_ACCEPT_BACKOFF_DELAY, + MAX_ACCEPT_BACKOFF_DELAY, +} from "./_listen.ts"; +import { isWindows } from "../../_util/os.ts"; export enum socketType { SOCKET, @@ -39,7 +48,19 @@ export class Pipe extends ConnectionWrap { override reading = false; ipc: boolean; - constructor(type: number) { + // REF: https://github.com/nodejs/node/blob/master/deps/uv/src/win/pipe.c#L48 + #pendingInstances = 4; + + #address?: string; + + #backlog?: number; + #listener!: Deno.Listener; + #connections = 0; + + #closed = false; + #acceptBackoffDelay?: number; + + constructor(type: number, conn?: Deno.UnixConn) { let provider: providerType; let ipc: boolean; @@ -67,44 +88,233 @@ export class Pipe extends ConnectionWrap { } } - super(provider); + super(provider, conn); this.ipc = ipc; } - bind() { - notImplemented("Pipe.prototype.bind"); + open(_fd: number): number { + // REF: https://github.com/denoland/deno/issues/6529 + notImplemented("Pipe.prototype.open"); } - listen() { - notImplemented("Pipe.prototype.listen"); + /** + * Bind to a Unix domain or Windows named pipe. + * @param name Unix domain or Windows named pipe the server should listen to. + * @return An error status code. + */ + bind(name: string) { + // Deno doesn't currently separate bind from connect. For now we noop under + // the assumption we will connect shortly. + // REF: https://doc.deno.land/deno/unstable/~/Deno.connect + + this.#address = name; + + return 0; } - connect( - _req: PipeConnectWrap, - _address: string, - _afterConnect: ( - status: number, - handle: Pipe, - req: PipeConnectWrap, - readable: boolean, - writable: boolean, - ) => void, - ) { - notImplemented("Pipe.prototype.connect"); + /** + * Connect to an IPv4 address. + * @param req A PipeConnectWrap instance. + * @param address Unix domain or Windows named pipe the server should connect to. + * @return An error status code. + */ + connect(req: PipeConnectWrap, address: string) { + Deno.connect({ + path: address, + transport: "unix", + }).then( + (_conn: Deno.UnixConn) => { + try { + this.afterConnect(req, 0); + } catch { + // swallow callback errors. + } + }, + () => { + try { + // TODO(cmorten): correct mapping of connection error to status code. + this.afterConnect(req, codeMap.get("ECONNREFUSED")!); + } catch { + // swallow callback errors. + } + }, + ); + + return 0; } - open(_fd: number): number { - // REF: https://github.com/denoland/deno/issues/6529 - notImplemented("Pipe.prototype.open"); + /** + * Listen for new connections. + * @param backlog The maximum length of the queue of pending connections. + * @return An error status code. + */ + listen(backlog: number): number { + this.#backlog = isWindows + ? this.#pendingInstances + : ceilPowOf2(backlog + 1); + + const listenOptions = { + path: this.#address!, + transport: "unix" as const, + }; + + let listener; + + try { + listener = Deno.listen(listenOptions); + } catch (e) { + if (e instanceof Deno.errors.AddrInUse) { + return codeMap.get("EADDRINUSE")!; + } else if (e instanceof Deno.errors.AddrNotAvailable) { + return codeMap.get("EADDRNOTAVAIL")!; + } + + // TODO(cmorten): map errors to appropriate error codes. + return codeMap.get("UNKNOWN")!; + } + + this.#listener = listener; + this.#accept(); + + return 0; + } + + override ref() { + this.#listener?.ref(); + } + + override unref() { + this.#listener?.unref(); + } + + /** + * Set the number of pending pipe instance handles when the pipe server is + * waiting for connections. This setting applies to Windows only. + * @param instances Number of pending pipe instances. + */ + setPendingInstances(instances: number) { + this.#pendingInstances = instances; } - // Windows only - setPendingInstances(_instances: number) { - notImplemented("Pipe.prototype.setPendingInstances"); + /** + * Alters pipe permissions, allowing it to be accessed from processes run by + * different users. Makes the pipe writable or readable by all users. Mode + * can be `UV_WRITABLE`, `UV_READABLE` or `UV_WRITABLE | UV_READABLE`. This + * function is blocking. + * @param mode Pipe permissions mode. + * @return An error status code. + */ + fchmod(mode: number) { + if ( + mode != constants.UV_READABLE && + mode != constants.UV_WRITABLE && + mode != (constants.UV_WRITABLE | constants.UV_READABLE) + ) { + return codeMap.get("EINVAL"); + } + + // TODO(cmorten): this will incorrectly throw on Windows + // REF: https://github.com/denoland/deno/issues/4357 + try { + Deno.chmodSync(this.#address!, mode); + } catch { + // TODO(cmorten): map errors to appropriate error codes. + return codeMap.get("UNKNOWN")!; + } + + return 0; } - fchmod() { - notImplemented("Pipe.prototype.fchmod"); + /** Handle backoff delays following an unsuccessful accept. */ + async #acceptBackoff(): Promise { + // Backoff after transient errors to allow time for the system to + // recover, and avoid blocking up the event loop with a continuously + // running loop. + if (!this.#acceptBackoffDelay) { + this.#acceptBackoffDelay = INITIAL_ACCEPT_BACKOFF_DELAY; + } else { + this.#acceptBackoffDelay *= 2; + } + + if (this.#acceptBackoffDelay >= MAX_ACCEPT_BACKOFF_DELAY) { + this.#acceptBackoffDelay = MAX_ACCEPT_BACKOFF_DELAY; + } + + await delay(this.#acceptBackoffDelay); + + this.#accept(); + } + + /** Accept new connections. */ + async #accept(): Promise { + if (this.#closed) { + return; + } + + if (this.#connections > this.#backlog!) { + this.#acceptBackoff(); + + return; + } + + let connection: Deno.Conn; + + try { + connection = await this.#listener.accept(); + } catch (e) { + if (e instanceof Deno.errors.BadResource && this.#closed) { + // Listener and server has closed. + return; + } + + try { + // TODO(cmorten): map errors to appropriate error codes. + this.onconnection!(codeMap.get("UNKNOWN")!, undefined); + } catch { + // swallow callback errors. + } + + this.#acceptBackoff(); + + return; + } + + // Reset the backoff delay upon successful accept. + this.#acceptBackoffDelay = undefined; + + const connectionHandle = new Pipe(socketType.SOCKET, connection); + this.#connections++; + + try { + this.onconnection!(0, connectionHandle); + } catch { + // swallow callback errors. + } + + return this.#accept(); + } + + /** Handle server closure. */ + override async _onClose(): Promise { + // TODO(cmorten): this isn't great + this.#closed = true; + this.reading = false; + + this.#address = undefined; + + this.#backlog = undefined; + this.#connections = 0; + this.#acceptBackoffDelay = undefined; + + if (this.provider === providerType.PIPESERVERWRAP) { + try { + this.#listener.close(); + } catch { + // listener already closed + } + } + + return await LibuvStreamWrap.prototype._onClose.call(this); } } diff --git a/node/internal_binding/tcp_wrap.ts b/node/internal_binding/tcp_wrap.ts index 629c7faf7ac2..e1ac75fd4fe4 100644 --- a/node/internal_binding/tcp_wrap.ts +++ b/node/internal_binding/tcp_wrap.ts @@ -34,6 +34,11 @@ import { codeMap } from "./uv.ts"; import { delay } from "../../async/mod.ts"; import { kStreamBaseField } from "./stream_wrap.ts"; import { isIP } from "../internal/net.ts"; +import { + ceilPowOf2, + INITIAL_ACCEPT_BACKOFF_DELAY, + MAX_ACCEPT_BACKOFF_DELAY, +} from "./_listen.ts"; /** The type of TCP socket. */ enum socketType { @@ -47,22 +52,6 @@ interface AddressInfo { port: number; } -/** Initial backoff delay of 5ms following a temporary accept failure. */ -const INITIAL_ACCEPT_BACKOFF_DELAY = 5; - -/** Max backoff delay of 1s following a temporary accept failure. */ -const MAX_ACCEPT_BACKOFF_DELAY = 1000; - -/** - * @param n Number to act on. - * @return The number rounded up to the nearest power of 2. - */ -function _ceilPowOf2(n: number) { - const roundPowOf2 = 1 << 31 - Math.clz32(n); - - return roundPowOf2 < n ? roundPowOf2 * 2 : roundPowOf2; -} - export class TCPConnectWrap extends AsyncWrap { oncomplete!: ( status: number, @@ -199,11 +188,11 @@ export class TCP extends ConnectionWrap { /** * Listen for new connections. - * @param backlog + * @param backlog The maximum length of the queue of pending connections. * @return An error status code. */ listen(backlog: number): number { - this.#backlog = _ceilPowOf2(backlog + 1); + this.#backlog = ceilPowOf2(backlog + 1); const listenOptions = { hostname: this.#address!, @@ -239,6 +228,7 @@ export class TCP extends ConnectionWrap { override ref() { this.#listener?.ref(); } + override unref() { this.#listener?.unref(); } @@ -250,7 +240,8 @@ export class TCP extends ConnectionWrap { */ getsockname(sockname: Record | AddressInfo): number { if ( - typeof this.#address === "undefined" || typeof this.#port === "undefined" + typeof this.#address === "undefined" || + typeof this.#port === "undefined" ) { return codeMap.get("EADDRNOTAVAIL")!; } @@ -326,11 +317,11 @@ export class TCP extends ConnectionWrap { #bind(address: string, port: number, _flags: number): number { // Deno doesn't currently separate bind from connect. For now we noop under // the assumption we will connect shortly. - // REF: https://doc.deno.land/builtin/stable#Deno.connect + // REF: https://doc.deno.land/deno/stable/~/Deno.connect // // This also means we won't be connecting from the specified local address // and port as providing these is not an option in Deno. - // REF: https://doc.deno.land/builtin/stable#Deno.ConnectOptions + // REF: https://doc.deno.land/deno/stable/~/Deno.ConnectOptions this.#address = address; this.#port = port; @@ -355,27 +346,30 @@ export class TCP extends ConnectionWrap { transport: "tcp", }; - Deno.connect(connectOptions).then((conn: Deno.Conn) => { - // Incorrect / backwards, but correcting the local address and port with - // what was actually used given we can't actually specify these in Deno. - const localAddr = conn.localAddr as Deno.NetAddr; - this.#address = req.localAddress = localAddr.hostname; - this.#port = req.localPort = localAddr.port; - this[kStreamBaseField] = conn; - - try { - this.afterConnect(req, 0); - } catch { - // swallow callback errors. - } - }, () => { - try { - // TODO(cmorten): correct mapping of connection error to status code. - this.afterConnect(req, codeMap.get("ECONNREFUSED")!); - } catch { - // swallow callback errors. - } - }); + Deno.connect(connectOptions).then( + (conn: Deno.Conn) => { + // Incorrect / backwards, but correcting the local address and port with + // what was actually used given we can't actually specify these in Deno. + const localAddr = conn.localAddr as Deno.NetAddr; + this.#address = req.localAddress = localAddr.hostname; + this.#port = req.localPort = localAddr.port; + this[kStreamBaseField] = conn; + + try { + this.afterConnect(req, 0); + } catch { + // swallow callback errors. + } + }, + () => { + try { + // TODO(cmorten): correct mapping of connection error to status code. + this.afterConnect(req, codeMap.get("ECONNREFUSED")!); + } catch { + // swallow callback errors. + } + }, + ); return 0; } diff --git a/node/net.ts b/node/net.ts index a1e1730b8e14..1c3cd4725573 100644 --- a/node/net.ts +++ b/node/net.ts @@ -467,7 +467,7 @@ function _internalConnect( req.oncomplete = _afterConnect; req.address = address; - err = (socket._handle as Pipe).connect(req, address, _afterConnect); + err = (socket._handle as Pipe).connect(req, address); } if (err) { From 46ce57be81a63b27e9e6d365fa26d01ba6f5b3a9 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sat, 23 Apr 2022 23:40:44 +0100 Subject: [PATCH 02/35] test: `test-net-server-listen-path.js` --- node/README.md | 2 +- node/_tools/config.json | 2 + node/_tools/test/common/index.js | 10 ++ .../parallel/test-net-server-listen-path.js | 100 ++++++++++++++++++ node/internal_binding/pipe_wrap.ts | 22 ++-- 5 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 node/_tools/test/parallel/test-net-server-listen-path.js diff --git a/node/README.md b/node/README.md index 8b5c26b695ff..931d3f5823cf 100644 --- a/node/README.md +++ b/node/README.md @@ -112,7 +112,7 @@ workflow. $ deno task node:setup ``` -You can aditionally pass the `-y`/`-n` flag to use test cache or generating +You can additionally pass the `-y`/`-n` flag to use test cache or generating tests from scratch instead of being prompted at the moment of running it. ```zsh diff --git a/node/_tools/config.json b/node/_tools/config.json index 223bb077de1b..5f4dd2dea287 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -32,6 +32,7 @@ "test-fs-rmdir-recursive.js", "test-fs-write-file.js", "test-fs-write.js", + "test-net-server-listen-path.js", "test-os.js", "test-path-resolve.js", "test-path.js", @@ -225,6 +226,7 @@ "test-http-url.parse-path.js", "test-http-url.parse-post.js", "test-http-url.parse-search.js", + "test-net-server-listen-path.js", "test-net-server-unref-persistent.js", "test-next-tick-doesnt-hang.js", "test-next-tick-fixed-queue-regression.js", diff --git a/node/_tools/test/common/index.js b/node/_tools/test/common/index.js index 8eb429e3875f..71f944382f03 100644 --- a/node/_tools/test/common/index.js +++ b/node/_tools/test/common/index.js @@ -11,7 +11,9 @@ */ 'use strict'; const assert = require("assert"); +const path = require("path"); const util = require("util"); +const tmpdir = require("./tmpdir"); function platformTimeout(ms) { return ms; @@ -345,6 +347,13 @@ function skip(msg) { process.exit(0); } +const PIPE = (() => { + const localRelative = path.relative(process.cwd(), `${tmpdir.path}/`); + const pipePrefix = isWindows ? "\\\\.\\pipe\\" : localRelative; + const pipeName = `node-test.${process.pid}.sock`; + return path.join(pipePrefix, pipeName); +})(); + function getArrayBufferViews(buf) { const { buffer, byteOffset, byteLength } = buf; @@ -387,6 +396,7 @@ module.exports = { mustCallAtLeast, mustNotCall, mustSucceed, + PIPE, platformTimeout, printSkipMessage, skipIfDumbTerminal, diff --git a/node/_tools/test/parallel/test-net-server-listen-path.js b/node/_tools/test/parallel/test-net-server-listen-path.js new file mode 100644 index 000000000000..a86ba9c025c7 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-listen-path.js @@ -0,0 +1,100 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const net = require('net'); +const assert = require('assert'); +const fs = require('fs'); + +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +function closeServer() { + return common.mustCall(function() { + this.close(); + }); +} + +let counter = 0; + +// Avoid conflict with listen-handle +function randomPipePath() { + return `${common.PIPE}-listen-path-${counter++}`; +} + +// // Test listen(path) +// { +// const handlePath = randomPipePath(); +// net.createServer() +// .listen(handlePath) +// .on('listening', closeServer()); +// } + +// // Test listen({path}) +// { +// const handlePath = randomPipePath(); +// net.createServer() +// .listen({ path: handlePath }) +// .on('listening', closeServer()); +// } + +// // Test listen(path, cb) +// { +// const handlePath = randomPipePath(); +// net.createServer() +// .listen(handlePath, closeServer()); +// } + +// // Test listen(path, cb) +// { +// const handlePath = randomPipePath(); +// net.createServer() +// .listen({ path: handlePath }, closeServer()); +// } + +// // Test pipe chmod +// { +// const handlePath = randomPipePath(); + +// const server = net.createServer() +// .listen({ +// path: handlePath, +// readableAll: true, +// writableAll: true +// }, common.mustCall(() => { +// if (process.platform !== 'win32') { +// const mode = fs.statSync(handlePath).mode; +// assert.notStrictEqual(mode & fs.constants.S_IROTH, 0); +// assert.notStrictEqual(mode & fs.constants.S_IWOTH, 0); +// } +// server.close(); +// })); +// } + +// TODO(cmorten): seems Deno.listen() for Unix domains isn't throwing +// Deno.errors.AddrInUse errors as would expect...? +// Test should emit "error" events when listening fails. +// { +// const handlePath = randomPipePath(); +// const server1 = net.createServer().listen({ path: handlePath }, () => { +// // As the handlePath is in use, binding to the same address again should +// // make the server emit an 'EADDRINUSE' error. +// const server2 = net.createServer() +// .listen({ +// path: handlePath, +// writableAll: true, +// }, common.mustNotCall()); + +// server2.on('error', common.mustCall((err) => { +// server1.close(); +// assert.strictEqual(err.code, 'EADDRINUSE'); +// assert.match(err.message, /^listen EADDRINUSE: address already in use/); +// })); +// }); +// } diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index f47e1bf51c46..e7031400bbe2 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -37,6 +37,7 @@ import { MAX_ACCEPT_BACKOFF_DELAY, } from "./_listen.ts"; import { isWindows } from "../../_util/os.ts"; +import { fs } from "./constants.ts"; export enum socketType { SOCKET, @@ -113,7 +114,7 @@ export class Pipe extends ConnectionWrap { } /** - * Connect to an IPv4 address. + * Connect to a Unix domain or Windows named pipe. * @param req A PipeConnectWrap instance. * @param address Unix domain or Windows named pipe the server should connect to. * @return An error status code. @@ -137,7 +138,7 @@ export class Pipe extends ConnectionWrap { } catch { // swallow callback errors. } - }, + } ); return 0; @@ -213,10 +214,19 @@ export class Pipe extends ConnectionWrap { return codeMap.get("EINVAL"); } + let desired_mode = 0; + + if (mode & constants.UV_READABLE) { + desired_mode |= fs.S_IRUSR | fs.S_IRGRP | fs.S_IROTH; + } + if (mode & constants.UV_WRITABLE) { + desired_mode |= fs.S_IWUSR | fs.S_IWGRP | fs.S_IWOTH; + } + // TODO(cmorten): this will incorrectly throw on Windows // REF: https://github.com/denoland/deno/issues/4357 try { - Deno.chmodSync(this.#address!, mode); + Deno.chmodSync(this.#address!, desired_mode); } catch { // TODO(cmorten): map errors to appropriate error codes. return codeMap.get("UNKNOWN")!; @@ -324,7 +334,7 @@ export class PipeConnectWrap extends AsyncWrap { handle: ConnectionWrap, req: PipeConnectWrap, readable: boolean, - writeable: boolean, + writeable: boolean ) => void; address!: string; @@ -337,6 +347,6 @@ export enum constants { SOCKET = socketType.SOCKET, SERVER = socketType.SERVER, IPC = socketType.IPC, - UV_READABLE, - UV_WRITABLE, + UV_READABLE = 1, + UV_WRITABLE = 2, } From 107d6f5af8b50de79eb6312c88224a4b0bdfa764 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 00:44:53 +0100 Subject: [PATCH 03/35] test: add net coverage --- node/_events.mjs | 1 + node/_tools/config.json | 10 ++ node/_tools/setup.ts | 2 +- .../parallel/test-net-access-byteswritten.js | 28 ++++++ .../test/parallel/test-net-after-close.js | 58 +++++++++++ .../test/parallel/test-net-allow-half-open.js | 54 ++++++++++ ...t-net-better-error-messages-listen-path.js | 17 ++++ .../test-net-better-error-messages-listen.js | 19 ++++ .../test-net-better-error-messages-path.js | 29 ++++++ ...net-better-error-messages-port-hostname.js | 44 +++++++++ .../test/parallel/test-net-bind-twice.js | 43 ++++++++ .../parallel/test-net-can-reset-timeout.js | 64 ++++++++++++ .../test-net-connect-after-destroy.js | 16 +++ node/internal_binding/pipe_wrap.ts | 18 +++- node/net.ts | 99 +++++++++---------- 15 files changed, 443 insertions(+), 59 deletions(-) create mode 100644 node/_tools/test/parallel/test-net-access-byteswritten.js create mode 100644 node/_tools/test/parallel/test-net-after-close.js create mode 100644 node/_tools/test/parallel/test-net-allow-half-open.js create mode 100644 node/_tools/test/parallel/test-net-better-error-messages-listen-path.js create mode 100644 node/_tools/test/parallel/test-net-better-error-messages-listen.js create mode 100644 node/_tools/test/parallel/test-net-better-error-messages-path.js create mode 100644 node/_tools/test/parallel/test-net-better-error-messages-port-hostname.js create mode 100644 node/_tools/test/parallel/test-net-bind-twice.js create mode 100644 node/_tools/test/parallel/test-net-can-reset-timeout.js create mode 100644 node/_tools/test/parallel/test-net-connect-after-destroy.js diff --git a/node/_events.mjs b/node/_events.mjs index 12552d3be148..9fdb08b6ea40 100644 --- a/node/_events.mjs +++ b/node/_events.mjs @@ -789,6 +789,7 @@ export function getEventListeners(emitterOrTarget, type) { return emitterOrTarget.listeners(type); } if (emitterOrTarget instanceof EventTarget) { + // TODO: kEvents is not defined const root = emitterOrTarget[kEvents].get(type); const listeners = []; let handler = root?.next; diff --git a/node/_tools/config.json b/node/_tools/config.json index 5f4dd2dea287..3a56b4dc0506 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -226,6 +226,16 @@ "test-http-url.parse-path.js", "test-http-url.parse-post.js", "test-http-url.parse-search.js", + "test-net-access-byteswritten.js", + "test-net-after-close.js", + "test-net-allow-half-open.js", + "test-net-better-error-messages-listen-path.js", + "test-net-better-error-messages-listen.js", + "test-net-better-error-messages-path.js", + "test-net-better-error-messages-port-hostname.js", + "test-net-bind-twice.js", + "test-net-can-reset-timeout.js", + "test-net-connect-after-destroy.js", "test-net-server-listen-path.js", "test-net-server-unref-persistent.js", "test-next-tick-doesnt-hang.js", diff --git a/node/_tools/setup.ts b/node/_tools/setup.ts index 0ea90fe905bc..f7f3a5722fe2 100755 --- a/node/_tools/setup.ts +++ b/node/_tools/setup.ts @@ -26,7 +26,7 @@ import { downloadFile } from "../../_util/download_file.ts"; * * Usage: `deno run --allow-read --allow-net --allow-write setup.ts` * - * You can aditionally pass a flag to indicate if cache should be used for generating + * You can additionally pass a flag to indicate if cache should be used for generating * the tests, or to generate the tests from scratch (-y/-n) */ diff --git a/node/_tools/test/parallel/test-net-access-byteswritten.js b/node/_tools/test/parallel/test-net-access-byteswritten.js new file mode 100644 index 000000000000..572626305d99 --- /dev/null +++ b/node/_tools/test/parallel/test-net-access-byteswritten.js @@ -0,0 +1,28 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const net = require('net'); +const tls = require('tls'); +const tty = require('tty'); + +// Check that the bytesWritten getter doesn't crash if object isn't +// constructed. +assert.strictEqual(net.Socket.prototype.bytesWritten, undefined); +assert.strictEqual(Object.getPrototypeOf(tls.TLSSocket).prototype.bytesWritten, + undefined); +assert.strictEqual(tls.TLSSocket.prototype.bytesWritten, undefined); +assert.strictEqual(Object.getPrototypeOf(tty.ReadStream).prototype.bytesWritten, + undefined); +assert.strictEqual(tty.ReadStream.prototype.bytesWritten, undefined); +assert.strictEqual(tty.WriteStream.prototype.bytesWritten, undefined); diff --git a/node/_tools/test/parallel/test-net-after-close.js b/node/_tools/test/parallel/test-net-after-close.js new file mode 100644 index 000000000000..fc8a9e405f86 --- /dev/null +++ b/node/_tools/test/parallel/test-net-after-close.js @@ -0,0 +1,58 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +const server = net.createServer(common.mustCall((s) => { + console.error('SERVER: got connection'); + s.end(); +})); + +server.listen(0, common.mustCall(() => { + const c = net.createConnection(server.address().port); + c.on('close', common.mustCall(() => { + /* eslint-disable no-unused-expressions */ + console.error('connection closed'); + assert.strictEqual(c._handle, null); + // Calling functions / accessing properties of a closed socket should not + // throw. + c.setNoDelay(); + c.setKeepAlive(); + c.bufferSize; + c.pause(); + c.resume(); + c.address(); + c.remoteAddress; + c.remotePort; + server.close(); + /* eslint-enable no-unused-expressions */ + })); +})); diff --git a/node/_tools/test/parallel/test-net-allow-half-open.js b/node/_tools/test/parallel/test-net-allow-half-open.js new file mode 100644 index 000000000000..b05ac4cab160 --- /dev/null +++ b/node/_tools/test/parallel/test-net-allow-half-open.js @@ -0,0 +1,54 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +{ + const server = net.createServer(common.mustCall((socket) => { + socket.end(Buffer.alloc(1024)); + })).listen(0, common.mustCall(() => { + const socket = net.connect(server.address().port); + assert.strictEqual(socket.allowHalfOpen, false); + socket.resume(); + socket.on('end', common.mustCall(() => { + process.nextTick(() => { + // Ensure socket is not destroyed straight away + // without proper shutdown. + assert(!socket.destroyed); + server.close(); + }); + })); + socket.on('finish', common.mustCall(() => { + assert(!socket.destroyed); + })); + socket.on('close', common.mustCall()); + })); +} + +{ + const server = net.createServer(common.mustCall((socket) => { + socket.end(Buffer.alloc(1024)); + })).listen(0, common.mustCall(() => { + const socket = net.connect(server.address().port); + assert.strictEqual(socket.allowHalfOpen, false); + socket.resume(); + socket.on('end', common.mustCall(() => { + assert(!socket.destroyed); + })); + socket.end('asd'); + socket.on('finish', common.mustCall(() => { + assert(!socket.destroyed); + })); + socket.on('close', common.mustCall(() => { + server.close(); + })); + })); +} diff --git a/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js new file mode 100644 index 000000000000..147d102e577e --- /dev/null +++ b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js @@ -0,0 +1,17 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); +const fp = '/blah/fadfa'; +const server = net.createServer(common.mustNotCall()); +server.listen(fp, common.mustNotCall()); +server.on('error', common.mustCall(function(e) { + assert.strictEqual(e.address, fp); +})); diff --git a/node/_tools/test/parallel/test-net-better-error-messages-listen.js b/node/_tools/test/parallel/test-net-better-error-messages-listen.js new file mode 100644 index 000000000000..03047d971e5a --- /dev/null +++ b/node/_tools/test/parallel/test-net-better-error-messages-listen.js @@ -0,0 +1,19 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const server = net.createServer(common.mustNotCall()); +server.listen(1, '1.1.1.1', common.mustNotCall()); +server.on('error', common.mustCall(function(e) { + assert.strictEqual(e.address, '1.1.1.1'); + assert.strictEqual(e.port, 1); + assert.strictEqual(e.syscall, 'listen'); +})); diff --git a/node/_tools/test/parallel/test-net-better-error-messages-path.js b/node/_tools/test/parallel/test-net-better-error-messages-path.js new file mode 100644 index 000000000000..d1bada362dd7 --- /dev/null +++ b/node/_tools/test/parallel/test-net-better-error-messages-path.js @@ -0,0 +1,29 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +{ + const fp = '/tmp/fadagagsdfgsdf'; + const c = net.connect(fp); + + c.on('connect', common.mustNotCall()); + c.on('error', common.expectsError({ + code: 'ENOENT', + message: `connect ENOENT ${fp}` + })); +} + +{ + assert.throws( + () => net.createConnection({ path: {} }), + { code: 'ERR_INVALID_ARG_TYPE' } + ); +} diff --git a/node/_tools/test/parallel/test-net-better-error-messages-port-hostname.js b/node/_tools/test/parallel/test-net-better-error-messages-port-hostname.js new file mode 100644 index 000000000000..c492df0bc17d --- /dev/null +++ b/node/_tools/test/parallel/test-net-better-error-messages-port-hostname.js @@ -0,0 +1,44 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +// This tests that the error thrown from net.createConnection +// comes with host and port properties. +// See https://github.com/nodejs/node-v0.x-archive/issues/7005 + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const { addresses } = require('../common/internet'); +const { + errorLookupMock, + mockedErrorCode +} = require('../common/dns'); + +// Using port 0 as hostname used is already invalid. +const c = net.createConnection({ + port: 0, + host: addresses.INVALID_HOST, + lookup: common.mustCall(errorLookupMock()) +}); + +c.on('connect', common.mustNotCall()); + +c.on('error', common.mustCall((error) => { + assert.ok(!('port' in error)); + assert.ok(!('host' in error)); + assert.throws(() => { throw error; }, { + errno: mockedErrorCode, + code: mockedErrorCode, + name: 'Error', + message: 'getaddrinfo ENOTFOUND something.invalid', + hostname: addresses.INVALID_HOST, + syscall: 'getaddrinfo' + }); +})); diff --git a/node/_tools/test/parallel/test-net-bind-twice.js b/node/_tools/test/parallel/test-net-bind-twice.js new file mode 100644 index 000000000000..dc5120504031 --- /dev/null +++ b/node/_tools/test/parallel/test-net-bind-twice.js @@ -0,0 +1,43 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +const server1 = net.createServer(common.mustNotCall()); +server1.listen(0, '127.0.0.1', common.mustCall(function() { + const server2 = net.createServer(common.mustNotCall()); + server2.listen(this.address().port, '127.0.0.1', common.mustNotCall()); + + server2.on('error', common.mustCall(function(e) { + assert.strictEqual(e.code, 'EADDRINUSE'); + server1.close(); + })); +})); diff --git a/node/_tools/test/parallel/test-net-can-reset-timeout.js b/node/_tools/test/parallel/test-net-can-reset-timeout.js new file mode 100644 index 000000000000..04f3eb3dd9e6 --- /dev/null +++ b/node/_tools/test/parallel/test-net-can-reset-timeout.js @@ -0,0 +1,64 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'); + +// Ref: https://github.com/nodejs/node-v0.x-archive/issues/481 + +const net = require('net'); + +const server = net.createServer(common.mustCall(function(stream) { + stream.setTimeout(100); + + stream.resume(); + + stream.once('timeout', common.mustCall(function() { + console.log('timeout'); + // Try to reset the timeout. + stream.write('WHAT.'); + })); + + stream.on('end', common.mustCall(function() { + console.log('server side end'); + stream.end(); + })); +})); + +server.listen(0, common.mustCall(function() { + const c = net.createConnection(this.address().port); + + c.on('data', function() { + c.end(); + }); + + c.on('end', function() { + console.log('client side end'); + server.close(); + }); +})); diff --git a/node/_tools/test/parallel/test-net-connect-after-destroy.js b/node/_tools/test/parallel/test-net-connect-after-destroy.js new file mode 100644 index 000000000000..5c35a9851d14 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-after-destroy.js @@ -0,0 +1,16 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +// Regression test for https://github.com/nodejs/node-v0.x-archive/issues/819. + +require('../common'); +const net = require('net'); + +// Connect to something that we need to DNS resolve +const c = net.createConnection(80, 'google.com'); +c.destroy(); diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index e7031400bbe2..64ce87b09026 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -131,14 +131,22 @@ export class Pipe extends ConnectionWrap { // swallow callback errors. } }, - () => { + (e) => { + // TODO(cmorten): correct mapping of connection error to status code. + let code: number; + + if (e instanceof Deno.errors.NotFound) { + code = codeMap.get("ENOENT")!; + } else { + code = codeMap.get("ECONNREFUSED")!; + } + try { - // TODO(cmorten): correct mapping of connection error to status code. - this.afterConnect(req, codeMap.get("ECONNREFUSED")!); + this.afterConnect(req, code); } catch { // swallow callback errors. } - } + }, ); return 0; @@ -334,7 +342,7 @@ export class PipeConnectWrap extends AsyncWrap { handle: ConnectionWrap, req: PipeConnectWrap, readable: boolean, - writeable: boolean + writeable: boolean, ) => void; address!: string; diff --git a/node/net.ts b/node/net.ts index 1c3cd4725573..037103a15288 100644 --- a/node/net.ts +++ b/node/net.ts @@ -211,7 +211,7 @@ interface IpcSocketConnectOptions extends ConnectOptions { type SocketConnectOptions = TcpSocketConnectOptions | IpcSocketConnectOptions; function _getNewAsyncId(handle?: Handle): number { - return (!handle || typeof handle.getAsyncId !== "function") + return !handle || typeof handle.getAsyncId !== "function" ? newAsyncId() : handle.getAsyncId(); } @@ -227,7 +227,7 @@ const _noop = (_arrayBuffer: Uint8Array, _nread: number): undefined => { }; function _toNumber(x: unknown): number | false { - return (x = Number(x)) >= 0 ? x as number : false; + return (x = Number(x)) >= 0 ? (x as number) : false; } function _isPipeName(s: unknown): s is string { @@ -240,15 +240,11 @@ function _createHandle(fd: number, isServer: boolean): Handle { const type = guessHandleType(fd); if (type === "PIPE") { - return new Pipe( - isServer ? PipeConstants.SERVER : PipeConstants.SOCKET, - ); + return new Pipe(isServer ? PipeConstants.SERVER : PipeConstants.SOCKET); } if (type === "TCP") { - return new TCP( - isServer ? TCPConstants.SERVER : TCPConstants.SOCKET, - ); + return new TCP(isServer ? TCPConstants.SERVER : TCPConstants.SOCKET); } throw new ERR_INVALID_FD_TYPE(type); @@ -495,7 +491,7 @@ function _writeAfterFIN( | BufferEncoding | null | ((error: Error | null | undefined) => void), - cb?: ((error: Error | null | undefined) => void), + cb?: (error: Error | null | undefined) => void, ): boolean { if (!this.writableEnded) { return Duplex.prototype.write.call( @@ -518,12 +514,7 @@ function _writeAfterFIN( ); if (typeof cb === "function") { - defaultTriggerAsyncIdScope( - this[asyncIdSymbol], - nextTick, - cb, - err, - ); + defaultTriggerAsyncIdScope(this[asyncIdSymbol], nextTick, cb, err); } this.destroy(err); @@ -614,24 +605,20 @@ function _lookupAndConnect( // If host is an IP, skip performing a lookup const addressType = isIP(host); if (addressType) { - defaultTriggerAsyncIdScope( - self[asyncIdSymbol], - nextTick, - () => { - if (self.connecting) { - defaultTriggerAsyncIdScope( - self[asyncIdSymbol], - _internalConnect, - self, - host, - port, - addressType, - localAddress, - localPort, - ); - } - }, - ); + defaultTriggerAsyncIdScope(self[asyncIdSymbol], nextTick, () => { + if (self.connecting) { + defaultTriggerAsyncIdScope( + self[asyncIdSymbol], + _internalConnect, + self, + host, + port, + addressType, + localAddress, + localPort, + ); + } + }); return; } @@ -801,7 +788,8 @@ export class Socket extends Duplex { const onread = options.onread; if ( - onread !== null && typeof onread === "object" && + onread !== null && + typeof onread === "object" && (isUint8Array(onread.buffer) || typeof onread.buffer === "function") && typeof onread.callback === "function" ) { @@ -944,7 +932,9 @@ export class Socket extends Duplex { */ override pause(): this { if ( - this[kBuffer] && !this.connecting && this._handle && + this[kBuffer] && + !this.connecting && + this._handle && this._handle.reading ) { this._handle.reading = false; @@ -968,7 +958,9 @@ export class Socket extends Duplex { */ override resume(): this { if ( - this[kBuffer] && !this.connecting && this._handle && + this[kBuffer] && + !this.connecting && + this._handle && !this._handle.reading ) { _tryReadStart(this); @@ -1034,7 +1026,8 @@ export class Socket extends Duplex { const newValue = noDelay === undefined ? true : !!noDelay; if ( - "setNoDelay" in this._handle && this._handle.setNoDelay && + "setNoDelay" in this._handle && + this._handle.setNoDelay && newValue !== this[kSetNoDelay] ) { this[kSetNoDelay] = newValue; @@ -1298,7 +1291,9 @@ export class Socket extends Duplex { size?: number, ): string | Uint8Array | Buffer | null | undefined { if ( - this[kBuffer] && !this.connecting && this._handle && + this[kBuffer] && + !this.connecting && + this._handle && !this._handle.reading ) { _tryReadStart(this); @@ -1389,10 +1384,7 @@ export class Socket extends Duplex { } } - override _destroy( - exception: Error | null, - cb: (err: Error | null) => void, - ) { + override _destroy(exception: Error | null, cb: (err: Error | null) => void) { debug("destroy"); this.connecting = false; @@ -1628,8 +1620,11 @@ interface ServerOptions { function _isServerSocketOptions( options: unknown, ): options is null | undefined | ServerOptions { - return options === null || typeof options === "undefined" || - typeof options === "object"; + return ( + options === null || + typeof options === "undefined" || + typeof options === "object" + ); } function _isConnectionListener( @@ -1774,11 +1769,7 @@ export function _createServerHandle( if (!address) { // Try binding to ipv6 first - err = (handle as TCP).bind6( - DEFAULT_IPV6_ADDR, - port ?? 0, - flags ?? 0, - ); + err = (handle as TCP).bind6(DEFAULT_IPV6_ADDR, port ?? 0, flags ?? 0); if (err) { handle.close(); @@ -2067,6 +2058,7 @@ export class Server extends EventEmitter { const cb = normalized[1]; if (this._handle) { + console.log("asdjhasgdjh"); throw new ERR_SERVER_ALREADY_LISTEN(); } @@ -2077,7 +2069,7 @@ export class Server extends EventEmitter { const backlogFromArgs: number = // (handle, backlog) or (path, backlog) or (port, backlog) _toNumber(args.length > 1 && args[1]) || - _toNumber(args.length > 2 && args[2]) as number; // (port, host, backlog) + (_toNumber(args.length > 2 && args[2]) as number); // (port, host, backlog) // deno-lint-ignore no-explicit-any options = (options as any)._handle || (options as any).handle || options; @@ -2107,7 +2099,8 @@ export class Server extends EventEmitter { // or (options[, cb]) where options.port is explicitly set as undefined or // null, bind to an arbitrary unused port if ( - args.length === 0 || typeof args[0] === "function" || + args.length === 0 || + typeof args[0] === "function" || (typeof options.port === "undefined" && "port" in options) || options.port === null ) { @@ -2153,7 +2146,7 @@ export class Server extends EventEmitter { // (path[, backlog][, cb]) or (options[, cb]) // where path or options.path is a UNIX domain socket or Windows pipe if (options.path && _isPipeName(options.path)) { - const pipeName = this._pipeName = options.path; + const pipeName = (this._pipeName = options.path); backlog = options.backlog || backlogFromArgs; _listenInCluster( @@ -2196,7 +2189,7 @@ export class Server extends EventEmitter { return this; } - if (!(("port" in options) || ("path" in options))) { + if (!("port" in options || "path" in options)) { throw new ERR_INVALID_ARG_VALUE( "options", options, From ecab3c046d6cc3c62b01c51911fe368357fcfa22 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 00:50:13 +0100 Subject: [PATCH 04/35] test: reinstate most of `test-net-server-listen-path` --- .../parallel/test-net-server-listen-path.js | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/node/_tools/test/parallel/test-net-server-listen-path.js b/node/_tools/test/parallel/test-net-server-listen-path.js index a86ba9c025c7..559e9c7eb4a8 100644 --- a/node/_tools/test/parallel/test-net-server-listen-path.js +++ b/node/_tools/test/parallel/test-net-server-listen-path.js @@ -28,54 +28,54 @@ function randomPipePath() { return `${common.PIPE}-listen-path-${counter++}`; } -// // Test listen(path) -// { -// const handlePath = randomPipePath(); -// net.createServer() -// .listen(handlePath) -// .on('listening', closeServer()); -// } +// Test listen(path) +{ + const handlePath = randomPipePath(); + net.createServer() + .listen(handlePath) + .on('listening', closeServer()); +} -// // Test listen({path}) -// { -// const handlePath = randomPipePath(); -// net.createServer() -// .listen({ path: handlePath }) -// .on('listening', closeServer()); -// } +// Test listen({path}) +{ + const handlePath = randomPipePath(); + net.createServer() + .listen({ path: handlePath }) + .on('listening', closeServer()); +} -// // Test listen(path, cb) -// { -// const handlePath = randomPipePath(); -// net.createServer() -// .listen(handlePath, closeServer()); -// } +// Test listen(path, cb) +{ + const handlePath = randomPipePath(); + net.createServer() + .listen(handlePath, closeServer()); +} -// // Test listen(path, cb) -// { -// const handlePath = randomPipePath(); -// net.createServer() -// .listen({ path: handlePath }, closeServer()); -// } +// Test listen(path, cb) +{ + const handlePath = randomPipePath(); + net.createServer() + .listen({ path: handlePath }, closeServer()); +} -// // Test pipe chmod -// { -// const handlePath = randomPipePath(); +// Test pipe chmod +{ + const handlePath = randomPipePath(); -// const server = net.createServer() -// .listen({ -// path: handlePath, -// readableAll: true, -// writableAll: true -// }, common.mustCall(() => { -// if (process.platform !== 'win32') { -// const mode = fs.statSync(handlePath).mode; -// assert.notStrictEqual(mode & fs.constants.S_IROTH, 0); -// assert.notStrictEqual(mode & fs.constants.S_IWOTH, 0); -// } -// server.close(); -// })); -// } + const server = net.createServer() + .listen({ + path: handlePath, + readableAll: true, + writableAll: true + }, common.mustCall(() => { + if (process.platform !== 'win32') { + const mode = fs.statSync(handlePath).mode; + assert.notStrictEqual(mode & fs.constants.S_IROTH, 0); + assert.notStrictEqual(mode & fs.constants.S_IWOTH, 0); + } + server.close(); + })); +} // TODO(cmorten): seems Deno.listen() for Unix domains isn't throwing // Deno.errors.AddrInUse errors as would expect...? From 7c83511bf8ce682f1407bf1334b560be16891e22 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 00:52:16 +0100 Subject: [PATCH 05/35] refactor: remove log statement --- node/net.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/node/net.ts b/node/net.ts index 037103a15288..6ac482183b95 100644 --- a/node/net.ts +++ b/node/net.ts @@ -2058,7 +2058,6 @@ export class Server extends EventEmitter { const cb = normalized[1]; if (this._handle) { - console.log("asdjhasgdjh"); throw new ERR_SERVER_ALREADY_LISTEN(); } From 492f5cc36a260e01e42a4c95125cbdcbbc5a3022 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 10:17:18 +0100 Subject: [PATCH 06/35] refactor: windows named pipes aren't supported yet --- .../test/parallel/test-net-server-listen-path.js | 6 ++++++ node/internal_binding/pipe_wrap.ts | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/node/_tools/test/parallel/test-net-server-listen-path.js b/node/_tools/test/parallel/test-net-server-listen-path.js index 559e9c7eb4a8..bf15b063194c 100644 --- a/node/_tools/test/parallel/test-net-server-listen-path.js +++ b/node/_tools/test/parallel/test-net-server-listen-path.js @@ -12,6 +12,12 @@ const net = require('net'); const assert = require('assert'); const fs = require('fs'); +// TODO(cmorten): reenable for windows once named pipes are supported +// REF: https://github.com/denoland/deno/issues/10244 +if (!common.isWindows) { + return; +} + const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index 64ce87b09026..89f088ea14ff 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -120,6 +120,11 @@ export class Pipe extends ConnectionWrap { * @return An error status code. */ connect(req: PipeConnectWrap, address: string) { + if (isWindows) { + // REF: https://github.com/denoland/deno/issues/10244 + notImplemented("Pipe.prototype.connect - Windows"); + } + Deno.connect({ path: address, transport: "unix", @@ -158,6 +163,11 @@ export class Pipe extends ConnectionWrap { * @return An error status code. */ listen(backlog: number): number { + if (isWindows) { + // REF: https://github.com/denoland/deno/issues/10244 + notImplemented("Pipe.prototype.listen - Windows"); + } + this.#backlog = isWindows ? this.#pendingInstances : ceilPowOf2(backlog + 1); From e561e4f6719045d5b79713eb68f2cf90555aa6fe Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 10:19:40 +0100 Subject: [PATCH 07/35] test: windows names pipes not yet supported --- node/_tools/config.json | 2 ++ .../parallel/test-net-better-error-messages-listen-path.js | 7 +++++++ .../test/parallel/test-net-better-error-messages-path.js | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/node/_tools/config.json b/node/_tools/config.json index 3a56b4dc0506..0c3782afe83a 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -32,6 +32,8 @@ "test-fs-rmdir-recursive.js", "test-fs-write-file.js", "test-fs-write.js", + "test-net-better-error-messages-listen-path.js", + "test-net-better-error-messages-path.js", "test-net-server-listen-path.js", "test-os.js", "test-path-resolve.js", diff --git a/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js index 147d102e577e..20003d2f867f 100644 --- a/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js +++ b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js @@ -7,6 +7,13 @@ 'use strict'; const common = require('../common'); + +// TODO(cmorten): reenable for windows once named pipes are supported +// REF: https://github.com/denoland/deno/issues/10244 +if (!common.isWindows) { + return; +} + const assert = require('assert'); const net = require('net'); const fp = '/blah/fadfa'; diff --git a/node/_tools/test/parallel/test-net-better-error-messages-path.js b/node/_tools/test/parallel/test-net-better-error-messages-path.js index d1bada362dd7..9389c2d91c4c 100644 --- a/node/_tools/test/parallel/test-net-better-error-messages-path.js +++ b/node/_tools/test/parallel/test-net-better-error-messages-path.js @@ -10,6 +10,12 @@ const common = require('../common'); const assert = require('assert'); const net = require('net'); +// TODO(cmorten): reenable for windows once named pipes are supported +// REF: https://github.com/denoland/deno/issues/10244 +if (!common.isWindows) { + return; +} + { const fp = '/tmp/fadagagsdfgsdf'; const c = net.connect(fp); From 5c8a96fee0a08bbe8a9536a7311555b009a03290 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 22:01:45 +0100 Subject: [PATCH 08/35] fix: ignore windows not other way around :facepalm: --- .../test/parallel/test-net-better-error-messages-listen-path.js | 2 +- .../_tools/test/parallel/test-net-better-error-messages-path.js | 2 +- node/_tools/test/parallel/test-net-server-listen-path.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js index 20003d2f867f..f64385aa24c0 100644 --- a/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js +++ b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js @@ -10,7 +10,7 @@ const common = require('../common'); // TODO(cmorten): reenable for windows once named pipes are supported // REF: https://github.com/denoland/deno/issues/10244 -if (!common.isWindows) { +if (common.isWindows) { return; } diff --git a/node/_tools/test/parallel/test-net-better-error-messages-path.js b/node/_tools/test/parallel/test-net-better-error-messages-path.js index 9389c2d91c4c..78a24ffd7cf7 100644 --- a/node/_tools/test/parallel/test-net-better-error-messages-path.js +++ b/node/_tools/test/parallel/test-net-better-error-messages-path.js @@ -12,7 +12,7 @@ const net = require('net'); // TODO(cmorten): reenable for windows once named pipes are supported // REF: https://github.com/denoland/deno/issues/10244 -if (!common.isWindows) { +if (common.isWindows) { return; } diff --git a/node/_tools/test/parallel/test-net-server-listen-path.js b/node/_tools/test/parallel/test-net-server-listen-path.js index bf15b063194c..f7c818cf465b 100644 --- a/node/_tools/test/parallel/test-net-server-listen-path.js +++ b/node/_tools/test/parallel/test-net-server-listen-path.js @@ -14,7 +14,7 @@ const fs = require('fs'); // TODO(cmorten): reenable for windows once named pipes are supported // REF: https://github.com/denoland/deno/issues/10244 -if (!common.isWindows) { +if (common.isWindows) { return; } From 6953b9356ec819595a082c13b7c1251a53ec77c0 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 22:57:44 +0100 Subject: [PATCH 09/35] feat: support `LibuvStreamWrap.prototype.writev` --- node/internal_binding/stream_wrap.ts | 31 ++++++++++++++++++++++------ node/net.ts | 2 +- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index 9d562e092b5a..76c7f6505309 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -185,13 +185,32 @@ export class LibuvStreamWrap extends HandleWrap { * @return An error status code. */ writev( - _req: WriteWrap, - // deno-lint-ignore no-explicit-any - _chunks: any, - _allBuffers: boolean, + req: WriteWrap, + chunks: Buffer[] | (string | Buffer)[], + allBuffers: boolean, ): number { - // TODO(cmorten) - notImplemented("LibuvStreamWrap.prototype.writev"); + const count = allBuffers ? chunks.length : chunks.length >> 1; + const buffers: Buffer[] = new Array(count); + + if (!allBuffers) { + for (let i = 0; i < count; i++) { + const chunk = chunks[i * 2]; + + if (Buffer.isBuffer(chunk)) { + buffers[i] = chunk; + } + + // String chunk + const encoding: string = chunks[i * 2 + 1] as string; + buffers[i] = Buffer.from(chunk as string, encoding); + } + } else { + for (let i = 0; i < count; i++) { + buffers[i] = chunks[i] as Buffer; + } + } + + return this.writeBuffer(req, Buffer.concat(buffers)); } /** diff --git a/node/net.ts b/node/net.ts index 6ac482183b95..63279b8fc8cb 100644 --- a/node/net.ts +++ b/node/net.ts @@ -1326,7 +1326,7 @@ export class Socket extends Duplex { // The user has called .end(), and all the bytes have been // sent out to the other side. // deno-lint-ignore no-explicit-any - override _final = (cb: any): any => { + override _final(cb: any): any { // If still connecting - defer handling `_final` until 'connect' will happen if (this.pending) { debug("_final: not yet connected"); From af695578078e1f2ad2fd775e4d2163f4002862ec Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 22:57:57 +0100 Subject: [PATCH 10/35] test: `test-net-buffersize.js` --- node/_tools/config.json | 1 + .../test/parallel/test-net-buffersize.js | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 node/_tools/test/parallel/test-net-buffersize.js diff --git a/node/_tools/config.json b/node/_tools/config.json index 0c3782afe83a..d5feb8058cb9 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -236,6 +236,7 @@ "test-net-better-error-messages-path.js", "test-net-better-error-messages-port-hostname.js", "test-net-bind-twice.js", + "test-net-buffersize.js", "test-net-can-reset-timeout.js", "test-net-connect-after-destroy.js", "test-net-server-listen-path.js", diff --git a/node/_tools/test/parallel/test-net-buffersize.js b/node/_tools/test/parallel/test-net-buffersize.js new file mode 100644 index 000000000000..b3203e599730 --- /dev/null +++ b/node/_tools/test/parallel/test-net-buffersize.js @@ -0,0 +1,59 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +const iter = 10; + +const server = net.createServer(function(socket) { + socket.on('readable', function() { + socket.read(); + }); + + socket.on('end', function() { + server.close(); + }); +}); + +server.listen(0, common.mustCall(function() { + const client = net.connect(this.address().port); + + client.on('finish', common.mustCall(() => { + assert.strictEqual(client.bufferSize, 0); + })); + + for (let i = 1; i < iter; i++) { + client.write('a'); + assert.strictEqual(client.bufferSize, i); + } + + client.end(); +})); From b7ee3ce1f73ebad6a0f4da36d24c11419fcaabb9 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 24 Apr 2022 22:58:48 +0100 Subject: [PATCH 11/35] fmt: net.ts --- node/net.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/net.ts b/node/net.ts index 63279b8fc8cb..5f5bf094b67d 100644 --- a/node/net.ts +++ b/node/net.ts @@ -1351,7 +1351,7 @@ export class Socket extends Duplex { } else if (err !== 0) { return cb(errnoException(err, "shutdown")); } - }; + } _onTimeout() { const handle = this._handle; From 7257a56d3167ff33bc8f2ee54693b7832d811395 Mon Sep 17 00:00:00 2001 From: Craig Morten Date: Mon, 25 Apr 2022 09:18:17 +0100 Subject: [PATCH 12/35] fix: windows listening on ::1 but trying to connect to 127.0.0.1 --- node/internal_binding/cares_wrap.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/node/internal_binding/cares_wrap.ts b/node/internal_binding/cares_wrap.ts index cb27b2528fe0..47ff8fe3893e 100644 --- a/node/internal_binding/cares_wrap.ts +++ b/node/internal_binding/cares_wrap.ts @@ -75,12 +75,12 @@ export function getaddrinfo( const recordTypes: ("A" | "AAAA")[] = []; - if (family === 0 || family === 4) { - recordTypes.push("A"); - } if (family === 0 || family === 6) { recordTypes.push("AAAA"); } + if (family === 0 || family === 4) { + recordTypes.push("A"); + } await Promise.allSettled( recordTypes.map((recordType) => @@ -92,12 +92,14 @@ export function getaddrinfo( const error = addresses.length ? null : codeMap.get("EAI_NODATA")!; + // TODO(cmorten): needs work + // REF: https://github.com/nodejs/node/blob/master/src/cares_wrap.cc#L1444 if (!verbatim) { addresses.sort((a: string, b: string): number => { if (isIPv4(a)) { - return -1; - } else if (isIPv4(b)) { return 1; + } else if (isIPv4(b)) { + return -1; } return 0; From f7a4f5b20dfdea7c88a7c00a1de4ce88ea79625d Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 25 Apr 2022 22:43:55 +0100 Subject: [PATCH 13/35] revert: dns record reordering --- node/internal_binding/tcp_wrap.ts | 14 +++++++++----- node/net.ts | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/node/internal_binding/tcp_wrap.ts b/node/internal_binding/tcp_wrap.ts index e1ac75fd4fe4..c877e801b815 100644 --- a/node/internal_binding/tcp_wrap.ts +++ b/node/internal_binding/tcp_wrap.ts @@ -311,17 +311,21 @@ export class TCP extends ConnectionWrap { * Bind to an IPv4 or IPv6 address. * @param address The hostname to bind to. * @param port The port to bind to - * @param flags + * @param _flags * @return An error status code. */ #bind(address: string, port: number, _flags: number): number { - // Deno doesn't currently separate bind from connect. For now we noop under - // the assumption we will connect shortly. - // REF: https://doc.deno.land/deno/stable/~/Deno.connect + // Deno doesn't currently separate bind from connect etc. + // REF: + // - https://doc.deno.land/deno/stable/~/Deno.connect + // - https://doc.deno.land/deno/stable/~/Deno.listen // // This also means we won't be connecting from the specified local address // and port as providing these is not an option in Deno. - // REF: https://doc.deno.land/deno/stable/~/Deno.ConnectOptions + // REF: + // - https://doc.deno.land/deno/stable/~/Deno.ConnectOptions + // - https://doc.deno.land/deno/stable/~/Deno.ListenOptions + this.#address = address; this.#port = port; diff --git a/node/net.ts b/node/net.ts index 5f5bf094b67d..0caa90a7149f 100644 --- a/node/net.ts +++ b/node/net.ts @@ -106,7 +106,7 @@ const kBytesRead = Symbol("kBytesRead"); const kBytesWritten = Symbol("kBytesWritten"); const DEFAULT_IPV4_ADDR = "0.0.0.0"; -const DEFAULT_IPV6_ADDR = "::"; +const DEFAULT_IPV6_ADDR = "::1"; type Handle = TCP | Pipe; From 85dcfed03e62f8ca2b29a08efd61164c8a4e840b Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 25 Apr 2022 23:34:29 +0100 Subject: [PATCH 14/35] revert: default ipv6 --- node/net.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/net.ts b/node/net.ts index 0caa90a7149f..5f5bf094b67d 100644 --- a/node/net.ts +++ b/node/net.ts @@ -106,7 +106,7 @@ const kBytesRead = Symbol("kBytesRead"); const kBytesWritten = Symbol("kBytesWritten"); const DEFAULT_IPV4_ADDR = "0.0.0.0"; -const DEFAULT_IPV6_ADDR = "::1"; +const DEFAULT_IPV6_ADDR = "::"; type Handle = TCP | Pipe; From 1c8d33245fcaf5049fa70e7d22290bb59264cb1c Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 25 Apr 2022 23:34:33 +0100 Subject: [PATCH 15/35] test: coverage --- node/_tools/config.json | 12 + .../parallel/test-net-bytes-written-large.js | 74 ++++++ .../test/parallel/test-net-connect-buffer.js | 86 +++++++ .../test/parallel/test-net-connect-buffer2.js | 63 +++++ .../test-net-connect-call-socket-connect.js | 46 ++++ .../test/parallel/test-net-connect-destroy.js | 14 ++ .../test-net-connect-immediate-destroy.js | 18 ++ .../test-net-connect-immediate-finish.js | 66 +++++ .../test/parallel/test-net-connect-memleak.js | 65 +++++ .../test/parallel/test-net-connect-no-arg.js | 42 ++++ .../test-net-connect-options-allowhalfopen.js | 125 ++++++++++ .../parallel/test-net-connect-options-ipv6.js | 74 ++++++ .../parallel/test-net-connect-options-port.js | 225 ++++++++++++++++++ node/internal_binding/pipe_wrap.ts | 19 +- node/internal_binding/stream_wrap.ts | 1 + 15 files changed, 926 insertions(+), 4 deletions(-) create mode 100644 node/_tools/test/parallel/test-net-bytes-written-large.js create mode 100644 node/_tools/test/parallel/test-net-connect-buffer.js create mode 100644 node/_tools/test/parallel/test-net-connect-buffer2.js create mode 100644 node/_tools/test/parallel/test-net-connect-call-socket-connect.js create mode 100644 node/_tools/test/parallel/test-net-connect-destroy.js create mode 100644 node/_tools/test/parallel/test-net-connect-immediate-destroy.js create mode 100644 node/_tools/test/parallel/test-net-connect-immediate-finish.js create mode 100644 node/_tools/test/parallel/test-net-connect-memleak.js create mode 100644 node/_tools/test/parallel/test-net-connect-no-arg.js create mode 100644 node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js create mode 100644 node/_tools/test/parallel/test-net-connect-options-ipv6.js create mode 100644 node/_tools/test/parallel/test-net-connect-options-port.js diff --git a/node/_tools/config.json b/node/_tools/config.json index d5feb8058cb9..4845f095a7b5 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -34,6 +34,8 @@ "test-fs-write.js", "test-net-better-error-messages-listen-path.js", "test-net-better-error-messages-path.js", + "test-net-connect-buffer.js", + "test-net-connect-buffer2.js", "test-net-server-listen-path.js", "test-os.js", "test-path-resolve.js", @@ -237,8 +239,18 @@ "test-net-better-error-messages-port-hostname.js", "test-net-bind-twice.js", "test-net-buffersize.js", + "test-net-bytes-written-large.js", "test-net-can-reset-timeout.js", "test-net-connect-after-destroy.js", + "test-net-connect-buffer.js", + "test-net-connect-buffer2.js", + "test-net-connect-call-socket-connect.js", + "test-net-connect-destroy.js", + "test-net-connect-immediate-destroy.js", + "test-net-connect-immediate-finish.js", + "test-net-connect-no-arg.js", + "test-net-connect-options-ipv6.js", + "test-net-connect-options-port.js", "test-net-server-listen-path.js", "test-net-server-unref-persistent.js", "test-next-tick-doesnt-hang.js", diff --git a/node/_tools/test/parallel/test-net-bytes-written-large.js b/node/_tools/test/parallel/test-net-bytes-written-large.js new file mode 100644 index 000000000000..a112c0c41a3d --- /dev/null +++ b/node/_tools/test/parallel/test-net-bytes-written-large.js @@ -0,0 +1,74 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +// Regression test for https://github.com/nodejs/node/issues/19562: +// Writing to a socket first tries to push through as much data as possible +// without blocking synchronously, and, if that is not enough, queues more +// data up for asynchronous writing. +// Check that `bytesWritten` accounts for both parts of a write. + +const N = 10000000; +{ + // Variant 1: Write a Buffer. + const server = net.createServer(common.mustCall((socket) => { + socket.end(Buffer.alloc(N), common.mustCall(() => { + assert.strictEqual(socket.bytesWritten, N); + })); + assert.strictEqual(socket.bytesWritten, N); + })).listen(0, common.mustCall(() => { + const client = net.connect(server.address().port); + client.resume(); + client.on('close', common.mustCall(() => { + assert.strictEqual(client.bytesRead, N); + server.close(); + })); + })); +} + +{ + // Variant 2: Write a string. + const server = net.createServer(common.mustCall((socket) => { + socket.end('a'.repeat(N), common.mustCall(() => { + assert.strictEqual(socket.bytesWritten, N); + })); + assert.strictEqual(socket.bytesWritten, N); + })).listen(0, common.mustCall(() => { + const client = net.connect(server.address().port); + client.resume(); + client.on('close', common.mustCall(() => { + assert.strictEqual(client.bytesRead, N); + server.close(); + })); + })); +} + +{ + // Variant 2: writev() with mixed data. + const server = net.createServer(common.mustCall((socket) => { + socket.cork(); + socket.write('a'.repeat(N)); + assert.strictEqual(socket.bytesWritten, N); + socket.write(Buffer.alloc(N)); + assert.strictEqual(socket.bytesWritten, 2 * N); + socket.end('', common.mustCall(() => { + assert.strictEqual(socket.bytesWritten, 2 * N); + })); + socket.uncork(); + })).listen(0, common.mustCall(() => { + const client = net.connect(server.address().port); + client.resume(); + client.on('close', common.mustCall(() => { + assert.strictEqual(client.bytesRead, 2 * N); + server.close(); + })); + })); +} diff --git a/node/_tools/test/parallel/test-net-connect-buffer.js b/node/_tools/test/parallel/test-net-connect-buffer.js new file mode 100644 index 000000000000..04e71247e425 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-buffer.js @@ -0,0 +1,86 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +// TODO: support not using "new" +const tcp = new net.Server(common.mustCall((s) => { + tcp.close(); + + let buf = ''; + s.setEncoding('utf8'); + s.on('data', function(d) { + buf += d; + }); + + s.on('end', common.mustCall(function() { + console.error('SERVER: end', buf); + assert.strictEqual(buf, "L'État, c'est moi"); + s.end(); + })); +})); + +tcp.listen(0, common.mustCall(function() { + // TODO: support not using "new" + const socket = new net.Stream({ highWaterMark: 0 }); + + let connected = false; + assert.strictEqual(socket.pending, true); + socket.connect(this.address().port, common.mustCall(() => connected = true)); + + assert.strictEqual(socket.pending, true); + assert.strictEqual(socket.connecting, true); + assert.strictEqual(socket.readyState, 'opening'); + + // Write a string that contains a multi-byte character sequence to test that + // `bytesWritten` is incremented with the # of bytes, not # of characters. + const a = "L'État, c'est "; + const b = 'moi'; + + // We're still connecting at this point so the datagram is first pushed onto + // the connect queue. Make sure that it's not added to `bytesWritten` again + // when the actual write happens. + const r = socket.write(a, common.mustCall((er) => { + console.error('write cb'); + assert.ok(connected); + assert.strictEqual(socket.bytesWritten, Buffer.from(a + b).length); + assert.strictEqual(socket.pending, false); + })); + socket.on('close', common.mustCall(() => { + assert.strictEqual(socket.pending, true); + })); + + assert.strictEqual(socket.bytesWritten, Buffer.from(a).length); + assert.strictEqual(r, false); + socket.end(b); + + assert.strictEqual(socket.readyState, 'opening'); +})); diff --git a/node/_tools/test/parallel/test-net-connect-buffer2.js b/node/_tools/test/parallel/test-net-connect-buffer2.js new file mode 100644 index 000000000000..499f3849f287 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-buffer2.js @@ -0,0 +1,63 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const tcp = new net.Server(common.mustCall((s) => { + tcp.close(); + + let buf = ''; + s.setEncoding('utf8'); + s.on('data', function(d) { + buf += d; + }); + + s.on('end', common.mustCall(function() { + console.error('SERVER: end', buf); + assert.strictEqual(buf, "L'État, c'est moi"); + s.end(); + })); +})); + +tcp.listen(0, common.mustCall(function() { + const socket = new net.Stream({ highWaterMark: 0 }); + + let connected = false; + assert.strictEqual(socket.pending, true); + socket.connect(this.address().port, common.mustCall(() => connected = true)); + + assert.strictEqual(socket.pending, true); + assert.strictEqual(socket.connecting, true); + assert.strictEqual(socket.readyState, 'opening'); + + // Write a string that contains a multi-byte character sequence to test that + // `bytesWritten` is incremented with the # of bytes, not # of characters. + const a = "L'État, c'est "; + const b = 'moi'; + + // We're still connecting at this point so the datagram is first pushed onto + // the connect queue. Make sure that it's not added to `bytesWritten` again + // when the actual write happens. + const r = socket.write(a, common.mustCall((er) => { + console.error('write cb'); + assert.ok(connected); + assert.strictEqual(socket.bytesWritten, Buffer.from(a + b).length); + assert.strictEqual(socket.pending, false); + })); + socket.on('close', common.mustCall(() => { + assert.strictEqual(socket.pending, true); + })); + + assert.strictEqual(socket.bytesWritten, Buffer.from(a).length); + assert.strictEqual(r, false); + socket.end(b); + + assert.strictEqual(socket.readyState, 'opening'); +})); diff --git a/node/_tools/test/parallel/test-net-connect-call-socket-connect.js b/node/_tools/test/parallel/test-net-connect-call-socket-connect.js new file mode 100644 index 000000000000..1de1ae4519ad --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-call-socket-connect.js @@ -0,0 +1,46 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); + +// This test checks that calling `net.connect` internally calls +// `Socket.prototype.connect`. +// +// This is important for people who monkey-patch `Socket.prototype.connect` +// since it's not possible to monkey-patch `net.connect` directly (as the core +// `connect` function is called internally in Node instead of calling the +// `exports.connect` function). +// +// Monkey-patching of `Socket.prototype.connect` is done by - among others - +// most APM vendors, the async-listener module and the +// continuation-local-storage module. +// +// Related: +// - https://github.com/nodejs/node/pull/12342 +// - https://github.com/nodejs/node/pull/12852 + +const net = require('net'); +const Socket = net.Socket; + +// Monkey patch Socket.prototype.connect to check that it's called. +const orig = Socket.prototype.connect; +Socket.prototype.connect = common.mustCall(function() { + return orig.apply(this, arguments); +}); + +const server = net.createServer(); + +server.listen(common.mustCall(function() { + const port = server.address().port; + const client = net.connect({ port }, common.mustCall(function() { + client.end(); + })); + client.on('end', common.mustCall(function() { + server.close(); + })); +})); diff --git a/node/_tools/test/parallel/test-net-connect-destroy.js b/node/_tools/test/parallel/test-net-connect-destroy.js new file mode 100644 index 000000000000..a024a032d7ab --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-destroy.js @@ -0,0 +1,14 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const net = require('net'); + +const socket = new net.Socket(); +socket.on('close', common.mustCall()); +socket.destroy(); diff --git a/node/_tools/test/parallel/test-net-connect-immediate-destroy.js b/node/_tools/test/parallel/test-net-connect-immediate-destroy.js new file mode 100644 index 000000000000..7cc28d6b3ae3 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-immediate-destroy.js @@ -0,0 +1,18 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const net = require('net'); + +const server = net.createServer(); +server.listen(0); +const port = server.address().port; +const socket = net.connect(port, common.localhostIPv4, common.mustNotCall()); +socket.on('error', common.mustNotCall()); +server.close(); +socket.destroy(); diff --git a/node/_tools/test/parallel/test-net-connect-immediate-finish.js b/node/_tools/test/parallel/test-net-connect-immediate-finish.js new file mode 100644 index 000000000000..6e5b63ab2889 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-immediate-finish.js @@ -0,0 +1,66 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 tests that if the socket is still in the 'connecting' state +// when the user calls socket.end() ('finish'), the socket would emit +// 'connect' and defer the handling until the 'connect' event is handled. + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const { addresses } = require('../common/internet'); +const { + errorLookupMock, + mockedErrorCode, + mockedSysCall +} = require('../common/dns'); + +const client = net.connect({ + host: addresses.INVALID_HOST, + port: 80, // Port number doesn't matter because host name is invalid + lookup: common.mustCall(errorLookupMock()) +}, common.mustNotCall()); + +client.once('error', common.mustCall((error) => { + // TODO(BridgeAR): Add a better way to handle not defined properties using + // `assert.throws(fn, object)`. + assert.ok(!('port' in error)); + assert.ok(!('host' in error)); + assert.throws(() => { throw error; }, { + code: mockedErrorCode, + errno: mockedErrorCode, + syscall: mockedSysCall, + hostname: addresses.INVALID_HOST, + message: 'getaddrinfo ENOTFOUND something.invalid' + }); +})); + +client.end(); diff --git a/node/_tools/test/parallel/test-net-connect-memleak.js b/node/_tools/test/parallel/test-net-connect-memleak.js new file mode 100644 index 000000000000..36b2db498c12 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-memleak.js @@ -0,0 +1,65 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; +// Flags: --expose-gc + +const common = require('../common'); +const onGC = require('../common/ongc'); +const assert = require('assert'); +const net = require('net'); + +// Test that the implicit listener for an 'connect' event on net.Sockets is +// added using `once()`, i.e. can be gc'ed once that event has occurred. + +const server = net.createServer(common.mustCall()).listen(0); + +let collected = false; +const gcListener = { ongc() { collected = true; } }; + +{ + const gcObject = {}; + onGC(gcObject, gcListener); + + const sock = net.createConnection( + server.address().port, + common.mustCall(() => { + assert.strictEqual(gcObject, gcObject); // Keep reference alive + assert.strictEqual(collected, false); + setImmediate(done, sock); + })); +} + +function done(sock) { + global.gc(); + setImmediate(() => { + assert.strictEqual(collected, true); + sock.end(); + server.close(); + }); +} diff --git a/node/_tools/test/parallel/test-net-connect-no-arg.js b/node/_tools/test/parallel/test-net-connect-no-arg.js new file mode 100644 index 000000000000..35b5250d049a --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-no-arg.js @@ -0,0 +1,42 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +require('../common'); +const assert = require('assert'); +const net = require('net'); + +// Tests that net.connect() called without arguments throws ERR_MISSING_ARGS. + +assert.throws(() => { + net.connect(); +}, { + code: 'ERR_MISSING_ARGS', + message: 'The "options" or "port" or "path" argument must be specified', +}); + +assert.throws(() => { + new net.Socket().connect(); +}, { + code: 'ERR_MISSING_ARGS', + message: 'The "options" or "port" or "path" argument must be specified', +}); + +assert.throws(() => { + net.connect({}); +}, { + code: 'ERR_MISSING_ARGS', + message: 'The "options" or "port" or "path" argument must be specified', +}); + +assert.throws(() => { + new net.Socket().connect({}); +}, { + code: 'ERR_MISSING_ARGS', + message: 'The "options" or "port" or "path" argument must be specified', +}); diff --git a/node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js b/node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js new file mode 100644 index 000000000000..0f703de00185 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js @@ -0,0 +1,125 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +// Test allowHalfOpen +{ + let clientReceivedFIN = 0; + let serverConnections = 0; + let clientSentFIN = 0; + let serverReceivedFIN = 0; + const host = common.localhostIPv4; + + function serverOnConnection(socket) { + console.log(`'connection' ${++serverConnections} emitted on server`); + const srvConn = serverConnections; + socket.resume(); + socket.on('data', common.mustCall(function socketOnData(data) { + this.clientId = data.toString(); + console.log( + `server connection ${srvConn} is started by client ${this.clientId}`); + })); + // 'end' on each socket must not be emitted twice + socket.on('end', common.mustCall(function socketOnEnd() { + console.log(`Server received FIN sent by client ${this.clientId}`); + if (++serverReceivedFIN < CLIENT_VARIANTS) return; + setTimeout(() => { + server.close(); + console.log(`connection ${this.clientId} is closing the server: + FIN ${serverReceivedFIN} received by server, + FIN ${clientReceivedFIN} received by client + FIN ${clientSentFIN} sent by client, + FIN ${serverConnections} sent by server`.replace(/ {3,}/g, '')); + }, 50); + }, 1)); + socket.end(); + console.log(`Server has sent ${serverConnections} FIN`); + } + + // These two levels of functions (and not arrows) are necessary in order to + // bind the `index`, and the calling socket (`this`) + function clientOnConnect(index) { + return common.mustCall(function clientOnConnectInner() { + const client = this; + console.log(`'connect' emitted on Client ${index}`); + client.resume(); + client.on('end', common.mustCall(function clientOnEnd() { + setTimeout(function closeServer() { + // When allowHalfOpen is true, client must still be writable + // after the server closes the connections, but not readable + console.log(`client ${index} received FIN`); + assert(!client.readable); + assert(client.writable); + assert(client.write(String(index))); + client.end(); + clientSentFIN++; + console.log( + `client ${index} sent FIN, ${clientSentFIN} have been sent`); + }, 50); + })); + client.on('close', common.mustCall(function clientOnClose() { + clientReceivedFIN++; + console.log(`connection ${index} has been closed by both sides,` + + ` ${clientReceivedFIN} clients have closed`); + })); + }); + } + + function serverOnClose() { + console.log(`Server has been closed: + FIN ${serverReceivedFIN} received by server + FIN ${clientReceivedFIN} received by client + FIN ${clientSentFIN} sent by client + FIN ${serverConnections} sent by server`.replace(/ {3,}/g, '')); + } + + function serverOnListen() { + const port = server.address().port; + console.log(`Server started listening at ${host}:${port}`); + const opts = { allowHalfOpen: true, host, port }; + // 6 variations === CLIENT_VARIANTS + net.connect(opts, clientOnConnect(1)); + net.connect(opts).on('connect', clientOnConnect(2)); + net.createConnection(opts, clientOnConnect(3)); + net.createConnection(opts).on('connect', clientOnConnect(4)); + new net.Socket(opts).connect(opts, clientOnConnect(5)); + new net.Socket(opts).connect(opts).on('connect', clientOnConnect(6)); + } + + const CLIENT_VARIANTS = 6; + + // The trigger + const server = net.createServer({ allowHalfOpen: true }) + .on('connection', common.mustCall(serverOnConnection, CLIENT_VARIANTS)) + .on('close', common.mustCall(serverOnClose)) + .listen(0, host, common.mustCall(serverOnListen)); +} diff --git a/node/_tools/test/parallel/test-net-connect-options-ipv6.js b/node/_tools/test/parallel/test-net-connect-options-ipv6.js new file mode 100644 index 000000000000..e222d4822649 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-options-ipv6.js @@ -0,0 +1,74 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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. + +// Test that the family option of net.connect is honored. + +'use strict'; +const common = require('../common'); +if (!common.hasIPv6) + common.skip('no IPv6 support'); + +const assert = require('assert'); +const net = require('net'); + +const hostAddrIPv6 = '::1'; +const HOSTNAME = 'dummy'; + +const server = net.createServer({ allowHalfOpen: true }, (socket) => { + socket.resume(); + socket.on('end', common.mustCall()); + socket.end(); +}); + +function tryConnect() { + const connectOpt = { + host: HOSTNAME, + port: server.address().port, + family: 6, + allowHalfOpen: true, + lookup: common.mustCall((addr, opt, cb) => { + assert.strictEqual(addr, HOSTNAME); + assert.strictEqual(opt.family, 6); + cb(null, hostAddrIPv6, opt.family); + }) + }; + // No `mustCall`, since test could skip, and it's the only path to `close`. + const client = net.connect(connectOpt, () => { + client.resume(); + client.on('end', () => { + // Wait for next uv tick and make sure the socket stream is writable. + setTimeout(function() { + assert(client.writable); + client.end(); + }, 10); + }); + client.on('close', () => server.close()); + }); +} + +server.listen(0, hostAddrIPv6, tryConnect); diff --git a/node/_tools/test/parallel/test-net-connect-options-port.js b/node/_tools/test/parallel/test-net-connect-options-port.js new file mode 100644 index 000000000000..4a86a070e4a0 --- /dev/null +++ b/node/_tools/test/parallel/test-net-connect-options-port.js @@ -0,0 +1,225 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const dns = require('dns'); +const net = require('net'); + +// Test wrong type of ports +{ + const portTypeError = { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' + }; + + syncFailToConnect(true, portTypeError); + syncFailToConnect(false, portTypeError); + syncFailToConnect([], portTypeError, true); + syncFailToConnect({}, portTypeError, true); + syncFailToConnect(null, portTypeError); +} + +// Test out of range ports +{ + const portRangeError = { + code: 'ERR_SOCKET_BAD_PORT', + name: 'RangeError' + }; + + syncFailToConnect('', portRangeError); + syncFailToConnect(' ', portRangeError); + syncFailToConnect('0x', portRangeError, true); + syncFailToConnect('-0x1', portRangeError, true); + syncFailToConnect(NaN, portRangeError); + syncFailToConnect(Infinity, portRangeError); + syncFailToConnect(-1, portRangeError); + syncFailToConnect(65536, portRangeError); +} + +// Test invalid hints +{ + // connect({hint}, cb) and connect({hint}) + const hints = (dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL) + 42; + const hintOptBlocks = doConnect([{ port: 42, hints }], + () => common.mustNotCall()); + for (const fn of hintOptBlocks) { + assert.throws(fn, { + code: 'ERR_INVALID_ARG_VALUE', + name: 'TypeError', + message: /The argument 'hints' is invalid\. Received \d+/ + }); + } +} + +// Test valid combinations of connect(port) and connect(port, host) +{ + const expectedConnections = 72; + let serverConnected = 0; + + const server = net.createServer(common.mustCall((socket) => { + socket.end('ok'); + if (++serverConnected === expectedConnections) { + server.close(); + } + }, expectedConnections)); + + server.listen(0, 'localhost', common.mustCall(() => { + const port = server.address().port; + + // Total connections = 3 * 4(canConnect) * 6(doConnect) = 72 + canConnect(port); + canConnect(String(port)); + canConnect(`0x${port.toString(16)}`); + })); + + // Try connecting to random ports, but do so once the server is closed + server.on('close', () => { + asyncFailToConnect(0); + }); +} + +function doConnect(args, getCb) { + return [ + function createConnectionWithCb() { + return net.createConnection.apply(net, args.concat(getCb())) + .resume(); + }, + function createConnectionWithoutCb() { + return net.createConnection.apply(net, args) + .on('connect', getCb()) + .resume(); + }, + function connectWithCb() { + return net.connect.apply(net, args.concat(getCb())) + .resume(); + }, + function connectWithoutCb() { + return net.connect.apply(net, args) + .on('connect', getCb()) + .resume(); + }, + function socketConnectWithCb() { + const socket = new net.Socket(); + return socket.connect.apply(socket, args.concat(getCb())) + .resume(); + }, + function socketConnectWithoutCb() { + const socket = new net.Socket(); + return socket.connect.apply(socket, args) + .on('connect', getCb()) + .resume(); + }, + ]; +} + +function syncFailToConnect(port, assertErr, optOnly) { + if (!optOnly) { + // connect(port, cb) and connect(port) + const portArgFunctions = doConnect([port], () => common.mustNotCall()); + for (const fn of portArgFunctions) { + assert.throws(fn, assertErr, `${fn.name}(${port})`); + } + + // connect(port, host, cb) and connect(port, host) + const portHostArgFunctions = doConnect([port, 'localhost'], + () => common.mustNotCall()); + for (const fn of portHostArgFunctions) { + assert.throws(fn, assertErr, `${fn.name}(${port}, 'localhost')`); + } + } + // connect({port}, cb) and connect({port}) + const portOptFunctions = doConnect([{ port }], () => common.mustNotCall()); + for (const fn of portOptFunctions) { + assert.throws(fn, assertErr, `${fn.name}({port: ${port}})`); + } + + // connect({port, host}, cb) and connect({port, host}) + const portHostOptFunctions = doConnect([{ port: port, host: 'localhost' }], + () => common.mustNotCall()); + for (const fn of portHostOptFunctions) { + assert.throws(fn, + assertErr, + `${fn.name}({port: ${port}, host: 'localhost'})`); + } +} + +function canConnect(port) { + const noop = () => common.mustCall(); + + // connect(port, cb) and connect(port) + const portArgFunctions = doConnect([port], noop); + for (const fn of portArgFunctions) { + fn(); + } + + // connect(port, host, cb) and connect(port, host) + const portHostArgFunctions = doConnect([port, 'localhost'], noop); + for (const fn of portHostArgFunctions) { + fn(); + } + + // connect({port}, cb) and connect({port}) + const portOptFunctions = doConnect([{ port }], noop); + for (const fn of portOptFunctions) { + fn(); + } + + // connect({port, host}, cb) and connect({port, host}) + const portHostOptFns = doConnect([{ port, host: 'localhost' }], noop); + for (const fn of portHostOptFns) { + fn(); + } +} + +function asyncFailToConnect(port) { + const onError = () => common.mustCall((err) => { + const regexp = /^Error: connect E\w+.+$/; + assert.match(String(err), regexp); + }); + + const dont = () => common.mustNotCall(); + // connect(port, cb) and connect(port) + const portArgFunctions = doConnect([port], dont); + for (const fn of portArgFunctions) { + fn().on('error', onError()); + } + + // connect({port}, cb) and connect({port}) + const portOptFunctions = doConnect([{ port }], dont); + for (const fn of portOptFunctions) { + fn().on('error', onError()); + } + + // connect({port, host}, cb) and connect({port, host}) + const portHostOptFns = doConnect([{ port, host: 'localhost' }], dont); + for (const fn of portHostOptFns) { + fn().on('error', onError()); + } +} diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index 89f088ea14ff..62ee71948991 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -31,6 +31,7 @@ import { AsyncWrap, providerType } from "./async_wrap.ts"; import { LibuvStreamWrap } from "./stream_wrap.ts"; import { codeMap } from "./uv.ts"; import { delay } from "../../async/mod.ts"; +import { kStreamBaseField } from "./stream_wrap.ts"; import { ceilPowOf2, INITIAL_ACCEPT_BACKOFF_DELAY, @@ -125,11 +126,18 @@ export class Pipe extends ConnectionWrap { notImplemented("Pipe.prototype.connect - Windows"); } - Deno.connect({ + const connectOptions: Deno.UnixConnectOptions = { path: address, transport: "unix", - }).then( - (_conn: Deno.UnixConn) => { + }; + + Deno.connect(connectOptions).then( + (conn: Deno.UnixConn) => { + const localAddr = conn.localAddr as Deno.UnixAddr; + + this.#address = req.address = localAddr.path; + this[kStreamBaseField] = conn; + try { this.afterConnect(req, 0); } catch { @@ -151,7 +159,7 @@ export class Pipe extends ConnectionWrap { } catch { // swallow callback errors. } - }, + } ); return 0; @@ -192,6 +200,9 @@ export class Pipe extends ConnectionWrap { return codeMap.get("UNKNOWN")!; } + const address = listener.addr as Deno.UnixAddr; + this.#address = address.path; + this.#listener = listener; this.#accept(); diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index 76c7f6505309..6b866b418b49 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -282,6 +282,7 @@ export class LibuvStreamWrap extends HandleWrap { try { nread = await this[kStreamBaseField]!.read(buf); } catch (e) { + console.error((this[kStreamBaseField] as any).localAddr, e); if ( e instanceof Deno.errors.Interrupted || e instanceof Deno.errors.BadResource From 2cbcb38709bab135e919137adf2fddfb584f6605 Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 25 Apr 2022 23:35:44 +0100 Subject: [PATCH 16/35] fix: formatting --- node/internal_binding/pipe_wrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index 62ee71948991..f6bc009bd531 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -159,7 +159,7 @@ export class Pipe extends ConnectionWrap { } catch { // swallow callback errors. } - } + }, ); return 0; From 16973a3b289eca12c2c2da33af0f68aaa6c5330c Mon Sep 17 00:00:00 2001 From: cmorten Date: Tue, 26 Apr 2022 21:13:56 +0100 Subject: [PATCH 17/35] revert: remove console line --- node/internal_binding/stream_wrap.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index 6b866b418b49..76c7f6505309 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -282,7 +282,6 @@ export class LibuvStreamWrap extends HandleWrap { try { nread = await this[kStreamBaseField]!.read(buf); } catch (e) { - console.error((this[kStreamBaseField] as any).localAddr, e); if ( e instanceof Deno.errors.Interrupted || e instanceof Deno.errors.BadResource From 3fb616902213cc13adcf5bbf80683928ad5410fd Mon Sep 17 00:00:00 2001 From: cmorten Date: Tue, 26 Apr 2022 21:52:00 +0100 Subject: [PATCH 18/35] revert: address orders --- node/internal_binding/cares_wrap.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/node/internal_binding/cares_wrap.ts b/node/internal_binding/cares_wrap.ts index 47ff8fe3893e..33eb50da4517 100644 --- a/node/internal_binding/cares_wrap.ts +++ b/node/internal_binding/cares_wrap.ts @@ -75,12 +75,12 @@ export function getaddrinfo( const recordTypes: ("A" | "AAAA")[] = []; - if (family === 0 || family === 6) { - recordTypes.push("AAAA"); - } if (family === 0 || family === 4) { recordTypes.push("A"); } + if (family === 0 || family === 6) { + recordTypes.push("AAAA"); + } await Promise.allSettled( recordTypes.map((recordType) => @@ -97,9 +97,9 @@ export function getaddrinfo( if (!verbatim) { addresses.sort((a: string, b: string): number => { if (isIPv4(a)) { - return 1; - } else if (isIPv4(b)) { return -1; + } else if (isIPv4(b)) { + return 1; } return 0; From ea38d454062f882e516333bc7b619ee6eeadbbe7 Mon Sep 17 00:00:00 2001 From: cmorten Date: Tue, 26 Apr 2022 22:03:49 +0100 Subject: [PATCH 19/35] feat: set address for connections created by internals --- node/internal_binding/pipe_wrap.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index f6bc009bd531..488b8c4b8617 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -91,7 +91,13 @@ export class Pipe extends ConnectionWrap { } super(provider, conn); + this.ipc = ipc; + + if (conn && provider === providerType.PIPEWRAP) { + const localAddr = conn.localAddr as Deno.UnixAddr; + this.#address = localAddr.path; + } } open(_fd: number): number { From ac6268997147392968d32bb788f659f5b3be2f4e Mon Sep 17 00:00:00 2001 From: cmorten Date: Tue, 26 Apr 2022 23:20:38 +0100 Subject: [PATCH 20/35] test: drive out behaviours with tests --- node/_tools/config.json | 53 ++++ .../test-net-connect-options-allowhalfopen.js | 125 --------- .../parallel/test-net-dns-custom-lookup.js | 61 +++++ .../test/parallel/test-net-dns-error.js | 48 ++++ .../test/parallel/test-net-dns-lookup-skip.js | 26 ++ .../test/parallel/test-net-dns-lookup.js | 47 ++++ .../test/parallel/test-net-during-close.js | 49 ++++ .../test/parallel/test-net-eaddrinuse.js | 44 +++ .../test/parallel/test-net-end-destroyed.js | 33 +++ .../parallel/test-net-end-without-connect.js | 34 +++ .../test/parallel/test-net-error-twice.js | 70 +++++ node/_tools/test/parallel/test-net-isip.js | 103 +++++++ node/_tools/test/parallel/test-net-isipv4.js | 53 ++++ node/_tools/test/parallel/test-net-isipv6.js | 251 ++++++++++++++++++ .../test-net-listen-after-destroying-stdin.js | 29 ++ ...n-close-server-callback-is-not-function.js | 18 ++ .../parallel/test-net-listen-close-server.js | 37 +++ .../test/parallel/test-net-listen-error.js | 36 +++ .../parallel/test-net-listen-invalid-port.js | 52 ++++ .../test/parallel/test-net-listening.js | 23 ++ ...leak.js => test-net-local-address-port.js} | 44 +-- .../test/parallel/test-net-localerror.js | 51 ++++ .../test/parallel/test-net-options-lookup.js | 55 ++++ .../test-net-pause-resume-connecting.js | 102 +++++++ .../parallel/test-net-persistent-ref-unref.js | 48 ++++ .../parallel/test-net-pipe-connect-errors.js | 104 ++++++++ .../parallel/test-net-remote-address-port.js | 81 ++++++ ...t-net-server-call-listen-multiple-times.js | 56 ++++ .../test-net-server-capture-rejection.js | 34 +++ .../test/parallel/test-net-server-close.js | 52 ++++ .../test-net-server-listen-options-signal.js | 39 +++ .../test-net-server-listen-options.js | 101 +++++++ .../test-net-server-listen-remove-callback.js | 51 ++++ ...-connections-close-makes-more-available.js | 92 +++++++ .../test-net-server-max-connections.js | 114 ++++++++ .../test/parallel/test-net-server-options.js | 23 ++ .../test-net-server-pause-on-connect.js | 79 ++++++ .../parallel/test-net-server-try-ports.js | 54 ++++ .../test/parallel/test-net-server-unref.js | 37 +++ .../test/parallel/test-net-settimeout.js | 57 ++++ .../parallel/test-net-socket-byteswritten.js | 42 +++ .../test-net-socket-close-after-end.js | 38 +++ .../test-net-socket-connect-without-cb.js | 27 ++ .../parallel/test-net-socket-connecting.js | 28 ++ .../parallel/test-net-socket-constructor.js | 72 +++++ .../parallel/test-net-socket-destroy-send.js | 31 +++ .../parallel/test-net-socket-destroy-twice.js | 43 +++ .../test-net-socket-end-before-connect.js | 20 ++ .../parallel/test-net-socket-end-callback.js | 29 ++ .../parallel/test-net-socket-local-address.js | 48 ++++ .../test-net-socket-no-halfopen-enforcer.js | 18 ++ .../test-net-socket-ready-without-cb.js | 27 ++ .../parallel/test-net-socket-timeout-unref.js | 63 +++++ .../test/parallel/test-net-socket-timeout.js | 90 +++++++ .../test-net-socket-write-after-close.js | 49 ++++ .../parallel/test-net-socket-write-error.js | 29 ++ node/internal_binding/pipe_wrap.ts | 2 + node/internal_binding/stream_wrap.ts | 22 +- 58 files changed, 2982 insertions(+), 162 deletions(-) delete mode 100644 node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js create mode 100644 node/_tools/test/parallel/test-net-dns-custom-lookup.js create mode 100644 node/_tools/test/parallel/test-net-dns-error.js create mode 100644 node/_tools/test/parallel/test-net-dns-lookup-skip.js create mode 100644 node/_tools/test/parallel/test-net-dns-lookup.js create mode 100644 node/_tools/test/parallel/test-net-during-close.js create mode 100644 node/_tools/test/parallel/test-net-eaddrinuse.js create mode 100644 node/_tools/test/parallel/test-net-end-destroyed.js create mode 100644 node/_tools/test/parallel/test-net-end-without-connect.js create mode 100644 node/_tools/test/parallel/test-net-error-twice.js create mode 100644 node/_tools/test/parallel/test-net-isip.js create mode 100644 node/_tools/test/parallel/test-net-isipv4.js create mode 100644 node/_tools/test/parallel/test-net-isipv6.js create mode 100644 node/_tools/test/parallel/test-net-listen-after-destroying-stdin.js create mode 100644 node/_tools/test/parallel/test-net-listen-close-server-callback-is-not-function.js create mode 100644 node/_tools/test/parallel/test-net-listen-close-server.js create mode 100644 node/_tools/test/parallel/test-net-listen-error.js create mode 100644 node/_tools/test/parallel/test-net-listen-invalid-port.js create mode 100644 node/_tools/test/parallel/test-net-listening.js rename node/_tools/test/parallel/{test-net-connect-memleak.js => test-net-local-address-port.js} (66%) create mode 100644 node/_tools/test/parallel/test-net-localerror.js create mode 100644 node/_tools/test/parallel/test-net-options-lookup.js create mode 100644 node/_tools/test/parallel/test-net-pause-resume-connecting.js create mode 100644 node/_tools/test/parallel/test-net-persistent-ref-unref.js create mode 100644 node/_tools/test/parallel/test-net-pipe-connect-errors.js create mode 100644 node/_tools/test/parallel/test-net-remote-address-port.js create mode 100644 node/_tools/test/parallel/test-net-server-call-listen-multiple-times.js create mode 100644 node/_tools/test/parallel/test-net-server-capture-rejection.js create mode 100644 node/_tools/test/parallel/test-net-server-close.js create mode 100644 node/_tools/test/parallel/test-net-server-listen-options-signal.js create mode 100644 node/_tools/test/parallel/test-net-server-listen-options.js create mode 100644 node/_tools/test/parallel/test-net-server-listen-remove-callback.js create mode 100644 node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js create mode 100644 node/_tools/test/parallel/test-net-server-max-connections.js create mode 100644 node/_tools/test/parallel/test-net-server-options.js create mode 100644 node/_tools/test/parallel/test-net-server-pause-on-connect.js create mode 100644 node/_tools/test/parallel/test-net-server-try-ports.js create mode 100644 node/_tools/test/parallel/test-net-server-unref.js create mode 100644 node/_tools/test/parallel/test-net-settimeout.js create mode 100644 node/_tools/test/parallel/test-net-socket-byteswritten.js create mode 100644 node/_tools/test/parallel/test-net-socket-close-after-end.js create mode 100644 node/_tools/test/parallel/test-net-socket-connect-without-cb.js create mode 100644 node/_tools/test/parallel/test-net-socket-connecting.js create mode 100644 node/_tools/test/parallel/test-net-socket-constructor.js create mode 100644 node/_tools/test/parallel/test-net-socket-destroy-send.js create mode 100644 node/_tools/test/parallel/test-net-socket-destroy-twice.js create mode 100644 node/_tools/test/parallel/test-net-socket-end-before-connect.js create mode 100644 node/_tools/test/parallel/test-net-socket-end-callback.js create mode 100644 node/_tools/test/parallel/test-net-socket-local-address.js create mode 100644 node/_tools/test/parallel/test-net-socket-no-halfopen-enforcer.js create mode 100644 node/_tools/test/parallel/test-net-socket-ready-without-cb.js create mode 100644 node/_tools/test/parallel/test-net-socket-timeout-unref.js create mode 100644 node/_tools/test/parallel/test-net-socket-timeout.js create mode 100644 node/_tools/test/parallel/test-net-socket-write-after-close.js create mode 100644 node/_tools/test/parallel/test-net-socket-write-error.js diff --git a/node/_tools/config.json b/node/_tools/config.json index 4845f095a7b5..9ebab34f6db5 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -36,7 +36,11 @@ "test-net-better-error-messages-path.js", "test-net-connect-buffer.js", "test-net-connect-buffer2.js", + "test-net-listen-invalid-port.js", + "test-net-server-call-listen-multiple-times.js", "test-net-server-listen-path.js", + "test-net-server-try-ports.js", + "test-net-socket-timeout.js", "test-os.js", "test-path-resolve.js", "test-path.js", @@ -251,8 +255,57 @@ "test-net-connect-no-arg.js", "test-net-connect-options-ipv6.js", "test-net-connect-options-port.js", + "test-net-dns-custom-lookup.js", + "test-net-dns-error.js", + "test-net-dns-lookup-skip.js", + "test-net-dns-lookup.js", + "test-net-during-close.js", + "test-net-eaddrinuse.js", + "test-net-end-destroyed.js", + "test-net-end-without-connect.js", + "test-net-error-twice.js", + "test-net-isip.js", + "test-net-isipv4.js", + "test-net-isipv6.js", + "test-net-listen-after-destroying-stdin.js", + "test-net-listen-close-server-callback-is-not-function.js", + "test-net-listen-close-server.js", + "test-net-listen-error.js", + "test-net-listen-invalid-port.js", + "test-net-listening.js", + "test-net-local-address-port.js", + "test-net-localerror.js", + "test-net-options-lookup.js", + "test-net-pause-resume-connecting.js", + "test-net-persistent-ref-unref.js", + "test-net-pipe-connect-errors.js", + "test-net-remote-address-port.js", + "test-net-server-call-listen-multiple-times.js", + "test-net-server-capture-rejection.js", + "test-net-server-close.js", + "test-net-server-listen-options-signal.js", + "test-net-server-listen-options.js", "test-net-server-listen-path.js", + "test-net-server-listen-remove-callback.js", + "test-net-server-max-connections-close-makes-more-available.js", + "test-net-server-max-connections.js", + "test-net-server-options.js", + "test-net-server-pause-on-connect.js", + "test-net-server-try-ports.js", "test-net-server-unref-persistent.js", + "test-net-server-unref.js", + "test-net-socket-close-after-end.js", + "test-net-socket-connect-without-cb.js", + "test-net-socket-connecting.js", + "test-net-socket-destroy-send.js", + "test-net-socket-destroy-twice.js", + "test-net-socket-end-before-connect.js", + "test-net-socket-end-callback.js", + "test-net-socket-no-halfopen-enforcer.js", + "test-net-socket-ready-without-cb.js", + "test-net-socket-timeout.js", + "test-net-socket-write-after-close.js", + "test-net-socket-write-error.js", "test-next-tick-doesnt-hang.js", "test-next-tick-fixed-queue-regression.js", "test-next-tick-intentional-starvation.js", diff --git a/node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js b/node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js deleted file mode 100644 index 0f703de00185..000000000000 --- a/node/_tools/test/parallel/test-net-connect-options-allowhalfopen.js +++ /dev/null @@ -1,125 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -// 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 assert = require('assert'); -const net = require('net'); - -// Test allowHalfOpen -{ - let clientReceivedFIN = 0; - let serverConnections = 0; - let clientSentFIN = 0; - let serverReceivedFIN = 0; - const host = common.localhostIPv4; - - function serverOnConnection(socket) { - console.log(`'connection' ${++serverConnections} emitted on server`); - const srvConn = serverConnections; - socket.resume(); - socket.on('data', common.mustCall(function socketOnData(data) { - this.clientId = data.toString(); - console.log( - `server connection ${srvConn} is started by client ${this.clientId}`); - })); - // 'end' on each socket must not be emitted twice - socket.on('end', common.mustCall(function socketOnEnd() { - console.log(`Server received FIN sent by client ${this.clientId}`); - if (++serverReceivedFIN < CLIENT_VARIANTS) return; - setTimeout(() => { - server.close(); - console.log(`connection ${this.clientId} is closing the server: - FIN ${serverReceivedFIN} received by server, - FIN ${clientReceivedFIN} received by client - FIN ${clientSentFIN} sent by client, - FIN ${serverConnections} sent by server`.replace(/ {3,}/g, '')); - }, 50); - }, 1)); - socket.end(); - console.log(`Server has sent ${serverConnections} FIN`); - } - - // These two levels of functions (and not arrows) are necessary in order to - // bind the `index`, and the calling socket (`this`) - function clientOnConnect(index) { - return common.mustCall(function clientOnConnectInner() { - const client = this; - console.log(`'connect' emitted on Client ${index}`); - client.resume(); - client.on('end', common.mustCall(function clientOnEnd() { - setTimeout(function closeServer() { - // When allowHalfOpen is true, client must still be writable - // after the server closes the connections, but not readable - console.log(`client ${index} received FIN`); - assert(!client.readable); - assert(client.writable); - assert(client.write(String(index))); - client.end(); - clientSentFIN++; - console.log( - `client ${index} sent FIN, ${clientSentFIN} have been sent`); - }, 50); - })); - client.on('close', common.mustCall(function clientOnClose() { - clientReceivedFIN++; - console.log(`connection ${index} has been closed by both sides,` + - ` ${clientReceivedFIN} clients have closed`); - })); - }); - } - - function serverOnClose() { - console.log(`Server has been closed: - FIN ${serverReceivedFIN} received by server - FIN ${clientReceivedFIN} received by client - FIN ${clientSentFIN} sent by client - FIN ${serverConnections} sent by server`.replace(/ {3,}/g, '')); - } - - function serverOnListen() { - const port = server.address().port; - console.log(`Server started listening at ${host}:${port}`); - const opts = { allowHalfOpen: true, host, port }; - // 6 variations === CLIENT_VARIANTS - net.connect(opts, clientOnConnect(1)); - net.connect(opts).on('connect', clientOnConnect(2)); - net.createConnection(opts, clientOnConnect(3)); - net.createConnection(opts).on('connect', clientOnConnect(4)); - new net.Socket(opts).connect(opts, clientOnConnect(5)); - new net.Socket(opts).connect(opts).on('connect', clientOnConnect(6)); - } - - const CLIENT_VARIANTS = 6; - - // The trigger - const server = net.createServer({ allowHalfOpen: true }) - .on('connection', common.mustCall(serverOnConnection, CLIENT_VARIANTS)) - .on('close', common.mustCall(serverOnClose)) - .listen(0, host, common.mustCall(serverOnListen)); -} diff --git a/node/_tools/test/parallel/test-net-dns-custom-lookup.js b/node/_tools/test/parallel/test-net-dns-custom-lookup.js new file mode 100644 index 000000000000..8397bf831a10 --- /dev/null +++ b/node/_tools/test/parallel/test-net-dns-custom-lookup.js @@ -0,0 +1,61 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +function check(addressType, cb) { + const server = net.createServer(function(client) { + client.end(); + server.close(); + cb && cb(); + }); + + const address = addressType === 4 ? common.localhostIPv4 : '::1'; + server.listen(0, address, common.mustCall(function() { + net.connect({ + port: this.address().port, + host: 'localhost', + family: addressType, + lookup: lookup + }).on('lookup', common.mustCall(function(err, ip, type) { + assert.strictEqual(err, null); + assert.strictEqual(address, ip); + assert.strictEqual(type, addressType); + })); + })); + + function lookup(host, dnsopts, cb) { + dnsopts.family = addressType; + if (addressType === 4) { + process.nextTick(function() { + cb(null, common.localhostIPv4, 4); + }); + } else { + process.nextTick(function() { + cb(null, '::1', 6); + }); + } + } +} + +check(4, function() { + common.hasIPv6 && check(6); +}); + +// Verify that bad lookup() IPs are handled. +{ + net.connect({ + host: 'localhost', + port: 80, + lookup(host, dnsopts, cb) { + cb(null, undefined, 4); + } + }).on('error', common.expectsError({ code: 'ERR_INVALID_IP_ADDRESS' })); +} diff --git a/node/_tools/test/parallel/test-net-dns-error.js b/node/_tools/test/parallel/test-net-dns-error.js new file mode 100644 index 000000000000..2744466ceac8 --- /dev/null +++ b/node/_tools/test/parallel/test-net-dns-error.js @@ -0,0 +1,48 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +const host = '*'.repeat(64); +// Resolving hostname > 63 characters may return EAI_FAIL (permanent failure). +const errCodes = ['ENOTFOUND', 'EAI_FAIL']; + +const socket = net.connect(42, host, common.mustNotCall()); +socket.on('error', common.mustCall(function(err) { + assert(errCodes.includes(err.code), err); +})); +socket.on('lookup', common.mustCall(function(err, ip, type) { + assert(err instanceof Error); + assert(errCodes.includes(err.code), err); + assert.strictEqual(ip, undefined); + assert.strictEqual(type, undefined); +})); diff --git a/node/_tools/test/parallel/test-net-dns-lookup-skip.js b/node/_tools/test/parallel/test-net-dns-lookup-skip.js new file mode 100644 index 000000000000..21962ca4ddcd --- /dev/null +++ b/node/_tools/test/parallel/test-net-dns-lookup-skip.js @@ -0,0 +1,26 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const net = require('net'); + +function check(addressType) { + const server = net.createServer(function(client) { + client.end(); + server.close(); + }); + + const address = addressType === 4 ? '127.0.0.1' : '::1'; + server.listen(0, address, function() { + net.connect(this.address().port, address) + .on('lookup', common.mustNotCall()); + }); +} + +check(4); +common.hasIPv6 && check(6); diff --git a/node/_tools/test/parallel/test-net-dns-lookup.js b/node/_tools/test/parallel/test-net-dns-lookup.js new file mode 100644 index 000000000000..fa06e9f277c5 --- /dev/null +++ b/node/_tools/test/parallel/test-net-dns-lookup.js @@ -0,0 +1,47 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +const server = net.createServer(function(client) { + client.end(); + server.close(); +}); + +server.listen(0, '127.0.0.1', common.mustCall(function() { + net.connect(this.address().port, 'localhost') + .on('lookup', common.mustCall(function(err, ip, type, host) { + assert.strictEqual(err, null); + assert.strictEqual(ip, '127.0.0.1'); + assert.strictEqual(type, 4); + assert.strictEqual(host, 'localhost'); + })); +})); diff --git a/node/_tools/test/parallel/test-net-during-close.js b/node/_tools/test/parallel/test-net-during-close.js new file mode 100644 index 000000000000..114825e2199c --- /dev/null +++ b/node/_tools/test/parallel/test-net-during-close.js @@ -0,0 +1,49 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 server = net.createServer(function(socket) { + socket.end(); +}); + +server.listen(0, common.mustCall(function() { + /* eslint-disable no-unused-expressions */ + const client = net.createConnection(this.address().port); + server.close(); + // Server connection event has not yet fired client is still attempting to + // connect. Accessing properties should not throw in this case. + client.remoteAddress; + client.remoteFamily; + client.remotePort; + // Exit now, do not wait for the client error event. + process.exit(0); + /* eslint-enable no-unused-expressions */ +})); diff --git a/node/_tools/test/parallel/test-net-eaddrinuse.js b/node/_tools/test/parallel/test-net-eaddrinuse.js new file mode 100644 index 000000000000..efb700714d95 --- /dev/null +++ b/node/_tools/test/parallel/test-net-eaddrinuse.js @@ -0,0 +1,44 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +const server1 = net.createServer(function(socket) { +}); +const server2 = net.createServer(function(socket) { +}); +server1.listen(0, common.mustCall(function() { + server2.on('error', function(error) { + assert.strictEqual(error.message.includes('EADDRINUSE'), true); + server1.close(); + }); + server2.listen(this.address().port); +})); diff --git a/node/_tools/test/parallel/test-net-end-destroyed.js b/node/_tools/test/parallel/test-net-end-destroyed.js new file mode 100644 index 000000000000..786fb3e21e24 --- /dev/null +++ b/node/_tools/test/parallel/test-net-end-destroyed.js @@ -0,0 +1,33 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const net = require('net'); +const assert = require('assert'); + +const server = net.createServer(); + +server.on('connection', common.mustCall()); + +// Ensure that the socket is not destroyed when the 'end' event is emitted. + +server.listen(common.mustCall(function() { + const socket = net.createConnection({ + port: server.address().port + }); + + socket.on('connect', common.mustCall(function() { + socket.on('end', common.mustCall(function() { + assert.strictEqual(socket.destroyed, false); + server.close(); + })); + + socket.end(); + })); +})); diff --git a/node/_tools/test/parallel/test-net-end-without-connect.js b/node/_tools/test/parallel/test-net-end-without-connect.js new file mode 100644 index 000000000000..19997b564bf5 --- /dev/null +++ b/node/_tools/test/parallel/test-net-end-without-connect.js @@ -0,0 +1,34 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; +require('../common'); +const net = require('net'); + +const sock = new net.Socket(); +sock.end(); // Should not throw. diff --git a/node/_tools/test/parallel/test-net-error-twice.js b/node/_tools/test/parallel/test-net-error-twice.js new file mode 100644 index 000000000000..6bd583a726ba --- /dev/null +++ b/node/_tools/test/parallel/test-net-error-twice.js @@ -0,0 +1,70 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +const buf = Buffer.alloc(10 * 1024 * 1024, 0x62); + +const errs = []; +let clientSocket; +let serverSocket; + +function ready() { + if (clientSocket && serverSocket) { + clientSocket.destroy(); + serverSocket.write(buf); + } +} + +const server = net.createServer(function onConnection(conn) { + conn.on('error', function(err) { + errs.push(err); + if (errs.length > 1 && errs[0] === errs[1]) + assert.fail('Should not emit the same error twice'); + }); + conn.on('close', function() { + server.unref(); + }); + serverSocket = conn; + ready(); +}).listen(0, function() { + const client = net.connect({ port: this.address().port }); + + client.on('connect', function() { + clientSocket = client; + ready(); + }); +}); + +process.on('exit', function() { + console.log(errs); + assert.strictEqual(errs.length, 1); +}); diff --git a/node/_tools/test/parallel/test-net-isip.js b/node/_tools/test/parallel/test-net-isip.js new file mode 100644 index 000000000000..a3cc7f2b4c51 --- /dev/null +++ b/node/_tools/test/parallel/test-net-isip.js @@ -0,0 +1,103 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +assert.strictEqual(net.isIP('127.0.0.1'), 4); +assert.strictEqual(net.isIP('x127.0.0.1'), 0); +assert.strictEqual(net.isIP('example.com'), 0); +assert.strictEqual(net.isIP('0000:0000:0000:0000:0000:0000:0000:0000'), 6); +assert.strictEqual(net.isIP('0000:0000:0000:0000:0000:0000:0000:0000::0000'), + 0); +assert.strictEqual(net.isIP('1050:0:0:0:5:600:300c:326b'), 6); +assert.strictEqual(net.isIP('2001:252:0:1::2008:6'), 6); +assert.strictEqual(net.isIP('2001:dead:beef:1::2008:6'), 6); +assert.strictEqual(net.isIP('2001::'), 6); +assert.strictEqual(net.isIP('2001:dead::'), 6); +assert.strictEqual(net.isIP('2001:dead:beef::'), 6); +assert.strictEqual(net.isIP('2001:dead:beef:1::'), 6); +assert.strictEqual(net.isIP('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), 6); +assert.strictEqual(net.isIP(':2001:252:0:1::2008:6:'), 0); +assert.strictEqual(net.isIP(':2001:252:0:1::2008:6'), 0); +assert.strictEqual(net.isIP('2001:252:0:1::2008:6:'), 0); +assert.strictEqual(net.isIP('2001:252::1::2008:6'), 0); +assert.strictEqual(net.isIP('::2001:252:1:2008:6'), 6); +assert.strictEqual(net.isIP('::2001:252:1:1.1.1.1'), 6); +assert.strictEqual(net.isIP('::2001:252:1:255.255.255.255'), 6); +assert.strictEqual(net.isIP('::2001:252:1:255.255.255.255.76'), 0); +assert.strictEqual(net.isIP('fe80::2008%eth0'), 6); +assert.strictEqual(net.isIP('fe80::2008%eth0.0'), 6); +assert.strictEqual(net.isIP('fe80::2008%eth0@1'), 0); +assert.strictEqual(net.isIP('::anything'), 0); +assert.strictEqual(net.isIP('::1'), 6); +assert.strictEqual(net.isIP('::'), 6); +assert.strictEqual(net.isIP('0000:0000:0000:0000:0000:0000:12345:0000'), 0); +assert.strictEqual(net.isIP('0'), 0); +assert.strictEqual(net.isIP(), 0); +assert.strictEqual(net.isIP(''), 0); +assert.strictEqual(net.isIP(null), 0); +assert.strictEqual(net.isIP(123), 0); +assert.strictEqual(net.isIP(true), 0); +assert.strictEqual(net.isIP({}), 0); +assert.strictEqual(net.isIP({ toString: () => '::2001:252:1:255.255.255.255' }), + 6); +assert.strictEqual(net.isIP({ toString: () => '127.0.0.1' }), 4); +assert.strictEqual(net.isIP({ toString: () => 'bla' }), 0); + +assert.strictEqual(net.isIPv4('127.0.0.1'), true); +assert.strictEqual(net.isIPv4('example.com'), false); +assert.strictEqual(net.isIPv4('2001:252:0:1::2008:6'), false); +assert.strictEqual(net.isIPv4(), false); +assert.strictEqual(net.isIPv4(''), false); +assert.strictEqual(net.isIPv4(null), false); +assert.strictEqual(net.isIPv4(123), false); +assert.strictEqual(net.isIPv4(true), false); +assert.strictEqual(net.isIPv4({}), false); +assert.strictEqual(net.isIPv4({ + toString: () => '::2001:252:1:255.255.255.255' +}), false); +assert.strictEqual(net.isIPv4({ toString: () => '127.0.0.1' }), true); +assert.strictEqual(net.isIPv4({ toString: () => 'bla' }), false); + +assert.strictEqual(net.isIPv6('127.0.0.1'), false); +assert.strictEqual(net.isIPv6('example.com'), false); +assert.strictEqual(net.isIPv6('2001:252:0:1::2008:6'), true); +assert.strictEqual(net.isIPv6(), false); +assert.strictEqual(net.isIPv6(''), false); +assert.strictEqual(net.isIPv6(null), false); +assert.strictEqual(net.isIPv6(123), false); +assert.strictEqual(net.isIPv6(true), false); +assert.strictEqual(net.isIPv6({}), false); +assert.strictEqual(net.isIPv6({ + toString: () => '::2001:252:1:255.255.255.255' +}), true); +assert.strictEqual(net.isIPv6({ toString: () => '127.0.0.1' }), false); +assert.strictEqual(net.isIPv6({ toString: () => 'bla' }), false); diff --git a/node/_tools/test/parallel/test-net-isipv4.js b/node/_tools/test/parallel/test-net-isipv4.js new file mode 100644 index 000000000000..21b9cafba649 --- /dev/null +++ b/node/_tools/test/parallel/test-net-isipv4.js @@ -0,0 +1,53 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +const v4 = [ + '0.0.0.0', + '8.8.8.8', + '127.0.0.1', + '100.100.100.100', + '192.168.0.1', + '18.101.25.153', + '123.23.34.2', + '172.26.168.134', + '212.58.241.131', + '128.0.0.0', + '23.71.254.72', + '223.255.255.255', + '192.0.2.235', + '99.198.122.146', + '46.51.197.88', + '173.194.34.134', +]; + +const v4not = [ + '.100.100.100.100', + '100..100.100.100.', + '100.100.100.100.', + '999.999.999.999', + '256.256.256.256', + '256.100.100.100.100', + '123.123.123', + 'http://123.123.123', + '1000.2.3.4', + '999.2.3.4', + '0000000192.168.0.200', + '192.168.0.2000000000', +]; + +v4.forEach((ip) => { + assert.strictEqual(net.isIPv4(ip), true); +}); + +v4not.forEach((ip) => { + assert.strictEqual(net.isIPv4(ip), false); +}); diff --git a/node/_tools/test/parallel/test-net-isipv6.js b/node/_tools/test/parallel/test-net-isipv6.js new file mode 100644 index 000000000000..1b5689cc0ef8 --- /dev/null +++ b/node/_tools/test/parallel/test-net-isipv6.js @@ -0,0 +1,251 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +const v6 = [ + '::', + '1::', + '::1', + '1::8', + '1::7:8', + '1:2:3:4:5:6:7:8', + '1:2:3:4:5:6::8', + '1:2:3:4:5:6:7::', + '1:2:3:4:5::7:8', + '1:2:3:4:5::8', + '1:2:3::8', + '1::4:5:6:7:8', + '1::6:7:8', + '1::3:4:5:6:7:8', + '1:2:3:4::6:7:8', + '1:2::4:5:6:7:8', + '::2:3:4:5:6:7:8', + '1:2::8', + '2001:0000:1234:0000:0000:C1C0:ABCD:0876', + '3ffe:0b00:0000:0000:0001:0000:0000:000a', + 'FF02:0000:0000:0000:0000:0000:0000:0001', + '0000:0000:0000:0000:0000:0000:0000:0001', + '0000:0000:0000:0000:0000:0000:0000:0000', + '::ffff:192.168.1.26', + '2::10', + 'ff02::1', + 'fe80::', + '2002::', + '2001:db8::', + '2001:0db8:1234::', + '::ffff:0:0', + '::ffff:192.168.1.1', + '1:2:3:4::8', + '1::2:3:4:5:6:7', + '1::2:3:4:5:6', + '1::2:3:4:5', + '1::2:3:4', + '1::2:3', + '::2:3:4:5:6:7', + '::2:3:4:5:6', + '::2:3:4:5', + '::2:3:4', + '::2:3', + '::8', + '1:2:3:4:5:6::', + '1:2:3:4:5::', + '1:2:3:4::', + '1:2:3::', + '1:2::', + '1:2:3:4::7:8', + '1:2:3::7:8', + '1:2::7:8', + '1:2:3:4:5:6:1.2.3.4', + '1:2:3:4:5::1.2.3.4', + '1:2:3:4::1.2.3.4', + '1:2:3::1.2.3.4', + '1:2::1.2.3.4', + '1::1.2.3.4', + '1:2:3:4::5:1.2.3.4', + '1:2:3::5:1.2.3.4', + '1:2::5:1.2.3.4', + '1::5:1.2.3.4', + '1::5:11.22.33.44', + 'fe80::217:f2ff:254.7.237.98', + 'fe80::217:f2ff:fe07:ed62', + '2001:DB8:0:0:8:800:200C:417A', + 'FF01:0:0:0:0:0:0:101', + '0:0:0:0:0:0:0:1', + '0:0:0:0:0:0:0:0', + '2001:DB8::8:800:200C:417A', + 'FF01::101', + '0:0:0:0:0:0:13.1.68.3', + '0:0:0:0:0:FFFF:129.144.52.38', + '::13.1.68.3', + '::FFFF:129.144.52.38', + 'fe80:0000:0000:0000:0204:61ff:fe9d:f156', + 'fe80:0:0:0:204:61ff:fe9d:f156', + 'fe80::204:61ff:fe9d:f156', + 'fe80:0:0:0:204:61ff:254.157.241.86', + 'fe80::204:61ff:254.157.241.86', + 'fe80::1', + '2001:0db8:85a3:0000:0000:8a2e:0370:7334', + '2001:db8:85a3:0:0:8a2e:370:7334', + '2001:db8:85a3::8a2e:370:7334', + '2001:0db8:0000:0000:0000:0000:1428:57ab', + '2001:0db8:0000:0000:0000::1428:57ab', + '2001:0db8:0:0:0:0:1428:57ab', + '2001:0db8:0:0::1428:57ab', + '2001:0db8::1428:57ab', + '2001:db8::1428:57ab', + '::ffff:12.34.56.78', + '::ffff:0c22:384e', + '2001:0db8:1234:0000:0000:0000:0000:0000', + '2001:0db8:1234:ffff:ffff:ffff:ffff:ffff', + '2001:db8:a::123', + '::ffff:192.0.2.128', + '::ffff:c000:280', + 'a:b:c:d:e:f:f1:f2', + 'a:b:c::d:e:f:f1', + 'a:b:c::d:e:f', + 'a:b:c::d:e', + 'a:b:c::d', + '::a', + '::a:b:c', + '::a:b:c:d:e:f:f1', + 'a::', + 'a:b:c::', + 'a:b:c:d:e:f:f1::', + 'a:bb:ccc:dddd:000e:00f:0f::', + '0:a:0:a:0:0:0:a', + '0:a:0:0:a:0:0:a', + '2001:db8:1:1:1:1:0:0', + '2001:db8:1:1:1:0:0:0', + '2001:db8:1:1:0:0:0:0', + '2001:db8:1:0:0:0:0:0', + '2001:db8:0:0:0:0:0:0', + '2001:0:0:0:0:0:0:0', + 'A:BB:CCC:DDDD:000E:00F:0F::', + '0:0:0:0:0:0:0:a', + '0:0:0:0:a:0:0:0', + '0:0:0:a:0:0:0:0', + 'a:0:0:a:0:0:a:a', + 'a:0:0:a:0:0:0:a', + 'a:0:0:0:a:0:0:a', + 'a:0:0:0:a:0:0:0', + 'a:0:0:0:0:0:0:0', + 'fe80::7:8%eth0', + 'fe80::7:8%1', +]; + +const v6not = [ + '', + '1:', + ':1', + '11:36:12', + '02001:0000:1234:0000:0000:C1C0:ABCD:0876', + '2001:0000:1234:0000:00001:C1C0:ABCD:0876', + '2001:0000:1234: 0000:0000:C1C0:ABCD:0876', + '2001:1:1:1:1:1:255Z255X255Y255', + '3ffe:0b00:0000:0001:0000:0000:000a', + 'FF02:0000:0000:0000:0000:0000:0000:0000:0001', + '3ffe:b00::1::a', + '::1111:2222:3333:4444:5555:6666::', + '1:2:3::4:5::7:8', + '12345::6:7:8', + '1::5:400.2.3.4', + '1::5:260.2.3.4', + '1::5:256.2.3.4', + '1::5:1.256.3.4', + '1::5:1.2.256.4', + '1::5:1.2.3.256', + '1::5:300.2.3.4', + '1::5:1.300.3.4', + '1::5:1.2.300.4', + '1::5:1.2.3.300', + '1::5:900.2.3.4', + '1::5:1.900.3.4', + '1::5:1.2.900.4', + '1::5:1.2.3.900', + '1::5:300.300.300.300', + '1::5:3000.30.30.30', + '1::400.2.3.4', + '1::260.2.3.4', + '1::256.2.3.4', + '1::1.256.3.4', + '1::1.2.256.4', + '1::1.2.3.256', + '1::300.2.3.4', + '1::1.300.3.4', + '1::1.2.300.4', + '1::1.2.3.300', + '1::900.2.3.4', + '1::1.900.3.4', + '1::1.2.900.4', + '1::1.2.3.900', + '1::300.300.300.300', + '1::3000.30.30.30', + '::400.2.3.4', + '::260.2.3.4', + '::256.2.3.4', + '::1.256.3.4', + '::1.2.256.4', + '::1.2.3.256', + '::300.2.3.4', + '::1.300.3.4', + '::1.2.300.4', + '::1.2.3.300', + '::900.2.3.4', + '::1.900.3.4', + '::1.2.900.4', + '::1.2.3.900', + '::300.300.300.300', + '::3000.30.30.30', + '2001:DB8:0:0:8:800:200C:417A:221', + 'FF01::101::2', + '1111:2222:3333:4444::5555:', + '1111:2222:3333::5555:', + '1111:2222::5555:', + '1111::5555:', + '::5555:', + ':::', + '1111:', + ':', + ':1111:2222:3333:4444::5555', + ':1111:2222:3333::5555', + ':1111:2222::5555', + ':1111::5555', + ':::5555', + '1.2.3.4:1111:2222:3333:4444::5555', + '1.2.3.4:1111:2222:3333::5555', + '1.2.3.4:1111:2222::5555', + '1.2.3.4:1111::5555', + '1.2.3.4::5555', + '1.2.3.4::', + 'fe80:0000:0000:0000:0204:61ff:254.157.241.086', + '123', + 'ldkfj', + '2001::FFD3::57ab', + '2001:db8:85a3::8a2e:37023:7334', + '2001:db8:85a3::8a2e:370k:7334', + '1:2:3:4:5:6:7:8:9', + '1::2::3', + '1:::3:4:5', + '1:2:3::4:5:6:7:8:9', + '::ffff:2.3.4', + '::ffff:257.1.2.3', + '::ffff:12345678901234567890.1.26', + '2001:0000:1234:0000:0000:C1C0:ABCD:0876 0', + '02001:0000:1234:0000:0000:C1C0:ABCD:0876', +]; + +v6.forEach((ip) => { + assert.strictEqual(net.isIPv6(ip), true); +}); + +v6not.forEach((ip) => { + assert.strictEqual(net.isIPv6(ip), false); +}); diff --git a/node/_tools/test/parallel/test-net-listen-after-destroying-stdin.js b/node/_tools/test/parallel/test-net-listen-after-destroying-stdin.js new file mode 100644 index 000000000000..817ea702ffe3 --- /dev/null +++ b/node/_tools/test/parallel/test-net-listen-after-destroying-stdin.js @@ -0,0 +1,29 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +// Just test that destroying stdin doesn't mess up listening on a server. +// This is a regression test for +// https://github.com/nodejs/node-v0.x-archive/issues/746. + +const common = require('../common'); +const net = require('net'); + +process.stdin.destroy(); + +const server = net.createServer(common.mustCall((socket) => { + console.log('accepted...'); + socket.end(common.mustCall(() => { console.log('finished...'); })); + server.close(common.mustCall(() => { console.log('closed'); })); +})); + + +server.listen(0, common.mustCall(() => { + console.log('listening...'); + + net.createConnection(server.address().port); +})); diff --git a/node/_tools/test/parallel/test-net-listen-close-server-callback-is-not-function.js b/node/_tools/test/parallel/test-net-listen-close-server-callback-is-not-function.js new file mode 100644 index 000000000000..b3cf1240aa7f --- /dev/null +++ b/node/_tools/test/parallel/test-net-listen-close-server-callback-is-not-function.js @@ -0,0 +1,18 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const net = require('net'); + +const server = net.createServer(common.mustNotCall()); + +server.on('close', common.mustCall()); + +server.listen(0, common.mustNotCall()); + +server.close('bad argument'); diff --git a/node/_tools/test/parallel/test-net-listen-close-server.js b/node/_tools/test/parallel/test-net-listen-close-server.js new file mode 100644 index 000000000000..791f142c11d4 --- /dev/null +++ b/node/_tools/test/parallel/test-net-listen-close-server.js @@ -0,0 +1,37 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 server = net.createServer(function(socket) { +}); +server.listen(0, common.mustNotCall()); +server.on('error', common.mustNotCall()); +server.close(); diff --git a/node/_tools/test/parallel/test-net-listen-error.js b/node/_tools/test/parallel/test-net-listen-error.js new file mode 100644 index 000000000000..bee18903d19b --- /dev/null +++ b/node/_tools/test/parallel/test-net-listen-error.js @@ -0,0 +1,36 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 server = net.createServer(function(socket) { +}); +server.listen(1, '1.1.1.1', common.mustNotCall()); // EACCES or EADDRNOTAVAIL +server.on('error', common.mustCall()); diff --git a/node/_tools/test/parallel/test-net-listen-invalid-port.js b/node/_tools/test/parallel/test-net-listen-invalid-port.js new file mode 100644 index 000000000000..49c2869996cd --- /dev/null +++ b/node/_tools/test/parallel/test-net-listen-invalid-port.js @@ -0,0 +1,52 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); + +// This test ensures that port numbers are validated in *all* kinds of `listen` +// calls. If an invalid port is supplied, ensures a `RangeError` is thrown. +// https://github.com/nodejs/node/issues/5727 + +const assert = require('assert'); +const net = require('net'); + +const invalidPort = -1 >>> 0; + +// TODO: support net.Server() without new + +new net.Server().listen(0, function() { + const address = this.address(); + const key = `${address.family.slice(-1)}:${address.address}:0`; + + assert.strictEqual(this._connectionKey, key); + this.close(); +}); + +// The first argument is a configuration object +assert.throws(() => { + new net.Server().listen({ port: invalidPort }, common.mustNotCall()); +}, { + code: 'ERR_SOCKET_BAD_PORT', + name: 'RangeError' +}); + +// The first argument is the port, no IP given. +assert.throws(() => { + new net.Server().listen(invalidPort, common.mustNotCall()); +}, { + code: 'ERR_SOCKET_BAD_PORT', + name: 'RangeError' +}); + +// The first argument is the port, the second an IP. +assert.throws(() => { + new net.Server().listen(invalidPort, '0.0.0.0', common.mustNotCall()); +}, { + code: 'ERR_SOCKET_BAD_PORT', + name: 'RangeError' +}); diff --git a/node/_tools/test/parallel/test-net-listening.js b/node/_tools/test/parallel/test-net-listening.js new file mode 100644 index 000000000000..b7eb66474757 --- /dev/null +++ b/node/_tools/test/parallel/test-net-listening.js @@ -0,0 +1,23 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const server = net.createServer(); + +assert.strictEqual(server.listening, false); + +server.listen(0, common.mustCall(() => { + assert.strictEqual(server.listening, true); + + server.close(common.mustCall(() => { + assert.strictEqual(server.listening, false); + })); +})); diff --git a/node/_tools/test/parallel/test-net-connect-memleak.js b/node/_tools/test/parallel/test-net-local-address-port.js similarity index 66% rename from node/_tools/test/parallel/test-net-connect-memleak.js rename to node/_tools/test/parallel/test-net-local-address-port.js index 36b2db498c12..8dba2a3637c9 100644 --- a/node/_tools/test/parallel/test-net-connect-memleak.js +++ b/node/_tools/test/parallel/test-net-local-address-port.js @@ -27,39 +27,23 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -// Flags: --expose-gc - const common = require('../common'); -const onGC = require('../common/ongc'); const assert = require('assert'); const net = require('net'); -// Test that the implicit listener for an 'connect' event on net.Sockets is -// added using `once()`, i.e. can be gc'ed once that event has occurred. - -const server = net.createServer(common.mustCall()).listen(0); - -let collected = false; -const gcListener = { ongc() { collected = true; } }; - -{ - const gcObject = {}; - onGC(gcObject, gcListener); - - const sock = net.createConnection( - server.address().port, - common.mustCall(() => { - assert.strictEqual(gcObject, gcObject); // Keep reference alive - assert.strictEqual(collected, false); - setImmediate(done, sock); - })); -} - -function done(sock) { - global.gc(); - setImmediate(() => { - assert.strictEqual(collected, true); - sock.end(); +const server = net.createServer(common.mustCall(function(socket) { + assert.strictEqual(socket.localAddress, common.localhostIPv4); + assert.strictEqual(socket.localPort, this.address().port); + socket.on('end', function() { server.close(); }); -} + socket.resume(); +})); + +server.listen(0, common.localhostIPv4, function() { + const client = net.createConnection(this.address() + .port, common.localhostIPv4); + client.on('connect', function() { + client.end(); + }); +}); diff --git a/node/_tools/test/parallel/test-net-localerror.js b/node/_tools/test/parallel/test-net-localerror.js new file mode 100644 index 000000000000..07e74e71116b --- /dev/null +++ b/node/_tools/test/parallel/test-net-localerror.js @@ -0,0 +1,51 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +const connect = (opts, code, type) => { + assert.throws( + () => net.connect(opts), + { code, name: type.name } + ); +}; + +connect({ + host: 'localhost', + port: 0, + localAddress: 'foobar', +}, 'ERR_INVALID_IP_ADDRESS', TypeError); + +connect({ + host: 'localhost', + port: 0, + localPort: 'foobar', +}, 'ERR_INVALID_ARG_TYPE', TypeError); diff --git a/node/_tools/test/parallel/test-net-options-lookup.js b/node/_tools/test/parallel/test-net-options-lookup.js new file mode 100644 index 000000000000..faf938667462 --- /dev/null +++ b/node/_tools/test/parallel/test-net-options-lookup.js @@ -0,0 +1,55 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +['foobar', 1, {}, []].forEach((input) => connectThrows(input)); + +// Using port 0 as lookup is emitted before connecting. +function connectThrows(input) { + const opts = { + host: 'localhost', + port: 0, + lookup: input + }; + + assert.throws(() => { + net.connect(opts); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' + }); +} + +connectDoesNotThrow(() => {}); + +function connectDoesNotThrow(input) { + const opts = { + host: 'localhost', + port: 0, + lookup: input + }; + + return net.connect(opts); +} + +{ + // Verify that an error is emitted when an invalid address family is returned. + const s = connectDoesNotThrow((host, options, cb) => { + cb(null, '127.0.0.1', 100); + }); + + s.on('error', common.expectsError({ + code: 'ERR_INVALID_ADDRESS_FAMILY', + host: 'localhost', + port: 0, + message: 'Invalid address family: 100 localhost:0' + })); +} diff --git a/node/_tools/test/parallel/test-net-pause-resume-connecting.js b/node/_tools/test/parallel/test-net-pause-resume-connecting.js new file mode 100644 index 000000000000..c030c97edaf9 --- /dev/null +++ b/node/_tools/test/parallel/test-net-pause-resume-connecting.js @@ -0,0 +1,102 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +let connections = 0; +let dataEvents = 0; +let conn; + + +// Server +const server = net.createServer(function(conn) { + connections++; + conn.end('This was the year he fell to pieces.'); + + if (connections === 5) + server.close(); +}); + +server.listen(0, function() { + // Client 1 + conn = net.createConnection(this.address().port, 'localhost'); + conn.resume(); + conn.on('data', onDataOk); + + + // Client 2 + conn = net.createConnection(this.address().port, 'localhost'); + conn.pause(); + conn.resume(); + conn.on('data', onDataOk); + + + // Client 3 + conn = net.createConnection(this.address().port, 'localhost'); + conn.pause(); + conn.on('data', common.mustNotCall()); + scheduleTearDown(conn); + + + // Client 4 + conn = net.createConnection(this.address().port, 'localhost'); + conn.resume(); + conn.pause(); + conn.resume(); + conn.on('data', onDataOk); + + + // Client 5 + conn = net.createConnection(this.address().port, 'localhost'); + conn.resume(); + conn.resume(); + conn.pause(); + conn.on('data', common.mustNotCall()); + scheduleTearDown(conn); + + function onDataOk() { + dataEvents++; + } + + function scheduleTearDown(conn) { + setTimeout(function() { + conn.removeAllListeners('data'); + conn.resume(); + }, 100); + } +}); + + +// Exit sanity checks +process.on('exit', function() { + assert.strictEqual(connections, 5); + assert.strictEqual(dataEvents, 3); +}); diff --git a/node/_tools/test/parallel/test-net-persistent-ref-unref.js b/node/_tools/test/parallel/test-net-persistent-ref-unref.js new file mode 100644 index 000000000000..4152e77315ab --- /dev/null +++ b/node/_tools/test/parallel/test-net-persistent-ref-unref.js @@ -0,0 +1,48 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// Flags: --expose-internals +'use strict'; +require('../common'); +const assert = require('assert'); +const net = require('net'); +const { internalBinding } = require('internal/test/binding'); +const TCPWrap = internalBinding('tcp_wrap').TCP; + +const echoServer = net.createServer((conn) => { + conn.end(); +}); + +const ref = TCPWrap.prototype.ref; +const unref = TCPWrap.prototype.unref; + +let refCount = 0; + +TCPWrap.prototype.ref = function() { + ref.call(this); + refCount++; + assert.strictEqual(refCount, 0); +}; + +TCPWrap.prototype.unref = function() { + unref.call(this); + refCount--; + assert.strictEqual(refCount, -1); +}; + +echoServer.listen(0); + +echoServer.on('listening', function() { + const sock = new net.Socket(); + sock.unref(); + sock.ref(); + sock.connect(this.address().port); + sock.on('end', () => { + assert.strictEqual(refCount, 0); + echoServer.close(); + }); +}); diff --git a/node/_tools/test/parallel/test-net-pipe-connect-errors.js b/node/_tools/test/parallel/test-net-pipe-connect-errors.js new file mode 100644 index 000000000000..7ad19f885a46 --- /dev/null +++ b/node/_tools/test/parallel/test-net-pipe-connect-errors.js @@ -0,0 +1,104 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 fixtures = require('../common/fixtures'); +const fs = require('fs'); +const net = require('net'); +const assert = require('assert'); + +// Test if ENOTSOCK is fired when trying to connect to a file which is not +// a socket. + +let emptyTxt; + +if (common.isWindows) { + // On Win, common.PIPE will be a named pipe, so we use an existing empty + // file instead + emptyTxt = fixtures.path('empty.txt'); +} else { + const tmpdir = require('../common/tmpdir'); + tmpdir.refresh(); + // Keep the file name very short so that we don't exceed the 108 char limit + // on CI for a POSIX socket. Even though this isn't actually a socket file, + // the error will be different from the one we are expecting if we exceed the + // limit. + emptyTxt = `${tmpdir.path}0.txt`; + + function cleanup() { + try { + fs.unlinkSync(emptyTxt); + } catch (e) { + assert.strictEqual(e.code, 'ENOENT'); + } + } + process.on('exit', cleanup); + cleanup(); + fs.writeFileSync(emptyTxt, ''); +} + +const notSocketClient = net.createConnection(emptyTxt, function() { + assert.fail('connection callback should not run'); +}); + +notSocketClient.on('error', common.mustCall(function(err) { + assert(err.code === 'ENOTSOCK' || err.code === 'ECONNREFUSED', + `received ${err.code} instead of ENOTSOCK or ECONNREFUSED`); +})); + + +// Trying to connect to not-existing socket should result in ENOENT error +const noEntSocketClient = net.createConnection('no-ent-file', function() { + assert.fail('connection to non-existent socket, callback should not run'); +}); + +noEntSocketClient.on('error', common.mustCall(function(err) { + assert.strictEqual(err.code, 'ENOENT'); +})); + + +// On Windows or IBMi or when running as root, +// a chmod has no effect on named pipes +if (!common.isWindows && !common.isIBMi && process.getuid() !== 0) { + // Trying to connect to a socket one has no access to should result in EACCES + const accessServer = net.createServer( + common.mustNotCall('server callback should not run')); + accessServer.listen(common.PIPE, common.mustCall(function() { + fs.chmodSync(common.PIPE, 0); + + const accessClient = net.createConnection(common.PIPE, function() { + assert.fail('connection should get EACCES, callback should not run'); + }); + + accessClient.on('error', common.mustCall(function(err) { + assert.strictEqual(err.code, 'EACCES'); + accessServer.close(); + })); + })); +} diff --git a/node/_tools/test/parallel/test-net-remote-address-port.js b/node/_tools/test/parallel/test-net-remote-address-port.js new file mode 100644 index 000000000000..3c4697a0388c --- /dev/null +++ b/node/_tools/test/parallel/test-net-remote-address-port.js @@ -0,0 +1,81 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); + +const net = require('net'); + +let conns_closed = 0; + +const remoteAddrCandidates = [ common.localhostIPv4 ]; +if (common.hasIPv6) remoteAddrCandidates.push('::ffff:127.0.0.1'); + +const remoteFamilyCandidates = ['IPv4']; +if (common.hasIPv6) remoteFamilyCandidates.push('IPv6'); + +const server = net.createServer(common.mustCall(function(socket) { + assert.ok(remoteAddrCandidates.includes(socket.remoteAddress)); + assert.ok(remoteFamilyCandidates.includes(socket.remoteFamily)); + assert.ok(socket.remotePort); + assert.notStrictEqual(socket.remotePort, this.address().port); + socket.on('end', function() { + if (++conns_closed === 2) server.close(); + }); + socket.on('close', function() { + assert.ok(remoteAddrCandidates.includes(socket.remoteAddress)); + assert.ok(remoteFamilyCandidates.includes(socket.remoteFamily)); + }); + socket.resume(); +}, 2)); + +server.listen(0, 'localhost', function() { + const client = net.createConnection(this.address().port, 'localhost'); + const client2 = net.createConnection(this.address().port); + client.on('connect', function() { + assert.ok(remoteAddrCandidates.includes(client.remoteAddress)); + assert.ok(remoteFamilyCandidates.includes(client.remoteFamily)); + assert.strictEqual(client.remotePort, server.address().port); + client.end(); + }); + client.on('close', function() { + assert.ok(remoteAddrCandidates.includes(client.remoteAddress)); + assert.ok(remoteFamilyCandidates.includes(client.remoteFamily)); + }); + client2.on('connect', function() { + assert.ok(remoteAddrCandidates.includes(client2.remoteAddress)); + assert.ok(remoteFamilyCandidates.includes(client2.remoteFamily)); + assert.strictEqual(client2.remotePort, server.address().port); + client2.end(); + }); + client2.on('close', function() { + assert.ok(remoteAddrCandidates.includes(client2.remoteAddress)); + assert.ok(remoteFamilyCandidates.includes(client2.remoteFamily)); + }); +}); diff --git a/node/_tools/test/parallel/test-net-server-call-listen-multiple-times.js b/node/_tools/test/parallel/test-net-server-call-listen-multiple-times.js new file mode 100644 index 000000000000..30b443b1806f --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-call-listen-multiple-times.js @@ -0,0 +1,56 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +// TODO: support net.Server() without new + +// First test. Check that after error event you can listen right away. +{ + const dummyServer = new net.Server(); + const server = new net.Server(); + + // Run some server in order to simulate EADDRINUSE error. + dummyServer.listen(common.mustCall(() => { + // Try to listen used port. + server.listen(dummyServer.address().port); + })); + + server.on('error', common.mustCall((e) => { + server.listen(common.mustCall(() => { + dummyServer.close(); + server.close(); + })); + })); +} + +// Second test. Check that second listen call throws an error. +{ + const server = new net.Server(); + + server.listen(common.mustCall(() => server.close())); + + assert.throws(() => server.listen(), { + code: 'ERR_SERVER_ALREADY_LISTEN', + name: 'Error' + }); +} + +// Third test. +// Check that after the close call you can run listen method just fine. +{ + const server = new net.Server(); + + server.listen(common.mustCall(() => { + server.close(); + server.listen(common.mustCall(() => server.close())); + })); +} diff --git a/node/_tools/test/parallel/test-net-server-capture-rejection.js b/node/_tools/test/parallel/test-net-server-capture-rejection.js new file mode 100644 index 000000000000..012a0abb4480 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-capture-rejection.js @@ -0,0 +1,34 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const events = require('events'); +const { createServer, connect } = require('net'); + +events.captureRejections = true; + +const server = createServer(common.mustCall(async (sock) => { + server.close(); + + const _err = new Error('kaboom'); + sock.on('error', common.mustCall((err) => { + assert.strictEqual(err, _err); + })); + throw _err; +})); + +server.listen(0, common.mustCall(() => { + const sock = connect( + server.address().port, + server.address().host + ); + + sock.on('close', common.mustCall()); +})); diff --git a/node/_tools/test/parallel/test-net-server-close.js b/node/_tools/test/parallel/test-net-server-close.js new file mode 100644 index 000000000000..a855d8740753 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-close.js @@ -0,0 +1,52 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +const sockets = []; + +const server = net.createServer(function(c) { + c.on('close', common.mustCall()); + + sockets.push(c); + + if (sockets.length === 2) { + assert.strictEqual(server.close(), server); + sockets.forEach((c) => c.destroy()); + } +}); + +server.on('close', common.mustCall()); + +assert.strictEqual(server, server.listen(0, () => { + net.createConnection(server.address().port); + net.createConnection(server.address().port); +})); diff --git a/node/_tools/test/parallel/test-net-server-listen-options-signal.js b/node/_tools/test/parallel/test-net-server-listen-options-signal.js new file mode 100644 index 000000000000..01600c5b0634 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-listen-options-signal.js @@ -0,0 +1,39 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +{ + // Test bad signal. + const server = net.createServer(); + assert.throws( + () => server.listen({ port: 0, signal: 'INVALID_SIGNAL' }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' + }); +} + +{ + // Test close. + const server = net.createServer(); + const controller = new AbortController(); + server.on('close', common.mustCall()); + server.listen({ port: 0, signal: controller.signal }); + controller.abort(); +} + +{ + // Test close with pre-aborted signal. + const server = net.createServer(); + const signal = AbortSignal.abort(); + server.on('close', common.mustCall()); + server.listen({ port: 0, signal }); +} diff --git a/node/_tools/test/parallel/test-net-server-listen-options.js b/node/_tools/test/parallel/test-net-server-listen-options.js new file mode 100644 index 000000000000..5c42a52c4f6d --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-listen-options.js @@ -0,0 +1,101 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +function close() { this.close(); } + +{ + // Test listen() + net.createServer().listen().on('listening', common.mustCall(close)); + // Test listen(cb) + net.createServer().listen(common.mustCall(close)); + // Test listen(port) + net.createServer().listen(0).on('listening', common.mustCall(close)); + // Test listen({port}) + net.createServer().listen({ port: 0 }) + .on('listening', common.mustCall(close)); +} + +// Test listen(port, cb) and listen({ port }, cb) combinations +const listenOnPort = [ + (port, cb) => net.createServer().listen({ port }, cb), + (port, cb) => net.createServer().listen(port, cb), +]; + +{ + const assertPort = () => { + return common.expectsError({ + code: 'ERR_SOCKET_BAD_PORT', + name: 'RangeError' + }); + }; + + for (const listen of listenOnPort) { + // Arbitrary unused ports + listen('0', common.mustCall(close)); + listen(0, common.mustCall(close)); + listen(undefined, common.mustCall(close)); + listen(null, common.mustCall(close)); + // Test invalid ports + assert.throws(() => listen(-1, common.mustNotCall()), assertPort()); + assert.throws(() => listen(NaN, common.mustNotCall()), assertPort()); + assert.throws(() => listen(123.456, common.mustNotCall()), assertPort()); + assert.throws(() => listen(65536, common.mustNotCall()), assertPort()); + assert.throws(() => listen(1 / 0, common.mustNotCall()), assertPort()); + assert.throws(() => listen(-1 / 0, common.mustNotCall()), assertPort()); + } + // In listen(options, cb), port takes precedence over path + assert.throws(() => { + net.createServer().listen({ port: -1, path: common.PIPE }, + common.mustNotCall()); + }, assertPort()); +} + +{ + function shouldFailToListen(options) { + const fn = () => { + net.createServer().listen(options, common.mustNotCall()); + }; + + if (typeof options === 'object' && + !(('port' in options) || ('path' in options))) { + assert.throws(fn, + { + code: 'ERR_INVALID_ARG_VALUE', + name: 'TypeError', + message: /^The argument 'options' must have the property "port" or "path"\. Received .+$/, + }); + } else { + assert.throws(fn, + { + code: 'ERR_INVALID_ARG_VALUE', + name: 'TypeError', + message: /^The argument 'options' is invalid\. Received .+$/, + }); + } + } + + shouldFailToListen(false, { port: false }); + shouldFailToListen({ port: false }); + shouldFailToListen(true); + shouldFailToListen({ port: true }); + // Invalid fd as listen(handle) + shouldFailToListen({ fd: -1 }); + // Invalid path in listen(options) + shouldFailToListen({ path: -1 }); + + // Neither port or path are specified in options + shouldFailToListen({}); + shouldFailToListen({ host: 'localhost' }); + shouldFailToListen({ host: 'localhost:3000' }); + shouldFailToListen({ host: { port: 3000 } }); + shouldFailToListen({ exclusive: true }); +} diff --git a/node/_tools/test/parallel/test-net-server-listen-remove-callback.js b/node/_tools/test/parallel/test-net-server-listen-remove-callback.js new file mode 100644 index 000000000000..6d4ad7f4eab0 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-listen-remove-callback.js @@ -0,0 +1,51 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +// Server should only fire listen callback once +const server = net.createServer(); + +server.on('close', function() { + const listeners = server.listeners('listening'); + console.log('Closed, listeners:', listeners.length); + assert.strictEqual(listeners.length, 0); +}); + +server.listen(0, function() { + server.close(); +}); + +server.once('close', function() { + server.listen(0, function() { + server.close(); + }); +}); diff --git a/node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js b/node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js new file mode 100644 index 000000000000..3d7feb62eea7 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js @@ -0,0 +1,92 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +require('../common'); +const assert = require('assert'); + +const net = require('net'); + +// Sets the server's maxConnections property to 1. +// Open 2 connections (connection 0 and connection 1). +// Connection 0 should be accepted. +// Connection 1 should be rejected. +// Closes connection 0. +// Open 2 more connections (connection 2 and 3). +// Connection 2 should be accepted. +// Connection 3 should be rejected. + +const connections = []; +const received = []; +const sent = []; + +function createConnection(index) { + console.error(`creating connection ${index}`); + + return new Promise(function(resolve, reject) { + const connection = net.createConnection(server.address().port, function() { + const msg = String(index); + console.error(`sending message: ${msg}`); + this.write(msg); + sent.push(msg); + }); + + connection.on('error', function(err) { + assert.strictEqual(err.code, 'ECONNRESET'); + resolve(); + }); + + connection.on('data', function(e) { + console.error(`connection ${index} received response`); + resolve(); + }); + + connection.on('end', function() { + console.error(`ending ${index}`); + resolve(); + }); + + connections[index] = connection; + }); +} + +function closeConnection(index) { + console.error(`closing connection ${index}`); + return new Promise(function(resolve, reject) { + connections[index].on('end', function() { + resolve(); + }); + connections[index].end(); + }); +} + +const server = net.createServer(function(socket) { + socket.on('data', function(data) { + console.error(`received message: ${data}`); + received.push(String(data)); + socket.write('acknowledged'); + }); +}); + +server.maxConnections = 1; + +server.listen(0, function() { + createConnection(0) + .then(createConnection.bind(null, 1)) + .then(closeConnection.bind(null, 0)) + .then(createConnection.bind(null, 2)) + .then(createConnection.bind(null, 3)) + .then(server.close.bind(server)) + .then(closeConnection.bind(null, 2)); +}); + +process.on('exit', function() { + // Confirm that all connections tried to send data... + assert.deepStrictEqual(sent, ['0', '1', '2', '3']); + // ...but that only connections 0 and 2 were successful. + assert.deepStrictEqual(received, ['0', '2']); +}); diff --git a/node/_tools/test/parallel/test-net-server-max-connections.js b/node/_tools/test/parallel/test-net-server-max-connections.js new file mode 100644 index 000000000000..18513326dd2e --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-max-connections.js @@ -0,0 +1,114 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); + +const net = require('net'); + +// This test creates 20 connections to a server and sets the server's +// maxConnections property to 10. The first 10 connections make it through +// and the last 10 connections are rejected. + +const N = 20; +let closes = 0; +const waits = []; + +const server = net.createServer(common.mustCall(function(connection) { + connection.write('hello'); + waits.push(function() { connection.end(); }); +}, N / 2)); + +server.listen(0, function() { + makeConnection(0); +}); + +server.maxConnections = N / 2; + + +function makeConnection(index) { + const c = net.createConnection(server.address().port); + let gotData = false; + + c.on('connect', function() { + if (index + 1 < N) { + makeConnection(index + 1); + } + + c.on('close', function() { + console.error(`closed ${index}`); + closes++; + + if (closes < N / 2) { + assert.ok( + server.maxConnections <= index, + `${index} should not have been one of the first closed connections` + ); + } + + if (closes === N / 2) { + let cb; + console.error('calling wait callback.'); + while (cb = waits.shift()) { + cb(); + } + server.close(); + } + + if (index < server.maxConnections) { + assert.strictEqual(gotData, true, + `${index} didn't get data, but should have`); + } else { + assert.strictEqual(gotData, false, + `${index} got data, but shouldn't have`); + } + }); + }); + + c.on('end', function() { c.end(); }); + + c.on('data', function(b) { + gotData = true; + assert.ok(b.length > 0); + }); + + c.on('error', function(e) { + // Retry if SmartOS and ECONNREFUSED. See + // https://github.com/nodejs/node/issues/2663. + if (common.isSunOS && (e.code === 'ECONNREFUSED')) { + c.connect(server.address().port); + } + console.error(`error ${index}: ${e}`); + }); +} + + +process.on('exit', function() { + assert.strictEqual(closes, N); +}); diff --git a/node/_tools/test/parallel/test-net-server-options.js b/node/_tools/test/parallel/test-net-server-options.js new file mode 100644 index 000000000000..2b0e1a62f61e --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-options.js @@ -0,0 +1,23 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +assert.throws(() => net.createServer('path'), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' + }); + +assert.throws(() => net.createServer(0), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' + }); diff --git a/node/_tools/test/parallel/test-net-server-pause-on-connect.js b/node/_tools/test/parallel/test-net-server-pause-on-connect.js new file mode 100644 index 000000000000..9b11f8a63d14 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-pause-on-connect.js @@ -0,0 +1,79 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); +const msg = 'test'; +let stopped = true; +let server1Sock; + + +const server1ConnHandler = (socket) => { + socket.on('data', function(data) { + if (stopped) { + assert.fail('data event should not have happened yet'); + } + + assert.strictEqual(data.toString(), msg); + socket.end(); + server1.close(); + }); + + server1Sock = socket; +}; + +const server1 = net.createServer({ pauseOnConnect: true }, server1ConnHandler); + +const server2ConnHandler = (socket) => { + socket.on('data', function(data) { + assert.strictEqual(data.toString(), msg); + socket.end(); + server2.close(); + + assert.strictEqual(server1Sock.bytesRead, 0); + server1Sock.resume(); + stopped = false; + }); +}; + +const server2 = net.createServer({ pauseOnConnect: false }, server2ConnHandler); + +server1.listen(0, function() { + const clientHandler = common.mustCall(function() { + server2.listen(0, function() { + net.createConnection({ port: this.address().port }).write(msg); + }); + }); + net.createConnection({ port: this.address().port }).write(msg, clientHandler); +}); + +process.on('exit', function() { + assert.strictEqual(stopped, false); +}); diff --git a/node/_tools/test/parallel/test-net-server-try-ports.js b/node/_tools/test/parallel/test-net-server-try-ports.js new file mode 100644 index 000000000000..69dbc78b8d2a --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-try-ports.js @@ -0,0 +1,54 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 test binds to one port, then attempts to start a server on that +// port. It should be EADDRINUSE but be able to then bind to another port. +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +// TODO: support net.Server() without new + +const server1 = new net.Server(); + +const server2 = new net.Server(); + +server2.on('error', common.mustCall(function(e) { + assert.strictEqual(e.code, 'EADDRINUSE'); + + server2.listen(0, common.mustCall(function() { + server1.close(); + server2.close(); + })); +})); + +server1.listen(0, common.mustCall(function() { + // This should make server2 emit EADDRINUSE + server2.listen(this.address().port); +})); diff --git a/node/_tools/test/parallel/test-net-server-unref.js b/node/_tools/test/parallel/test-net-server-unref.js new file mode 100644 index 000000000000..b5e12ea795e2 --- /dev/null +++ b/node/_tools/test/parallel/test-net-server-unref.js @@ -0,0 +1,37 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 s = net.createServer(); +s.listen(0); +s.unref(); + +setTimeout(common.mustNotCall(), 1000).unref(); diff --git a/node/_tools/test/parallel/test-net-settimeout.js b/node/_tools/test/parallel/test-net-settimeout.js new file mode 100644 index 000000000000..1ba8285cd370 --- /dev/null +++ b/node/_tools/test/parallel/test-net-settimeout.js @@ -0,0 +1,57 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 sets a timeout then immediately attempts to disable the timeout +// https://github.com/joyent/node/pull/2245 + +const common = require('../common'); +const net = require('net'); +const assert = require('assert'); + +const T = 100; + +const server = net.createServer(common.mustCall((c) => { + c.write('hello'); +})); + +server.listen(0, function() { + const socket = net.createConnection(this.address().port, 'localhost'); + + const s = socket.setTimeout(T, common.mustNotCall()); + assert.ok(s instanceof net.Socket); + + socket.on('data', common.mustCall(() => { + setTimeout(function() { + socket.destroy(); + server.close(); + }, T * 2); + })); + + socket.setTimeout(0); +}); diff --git a/node/_tools/test/parallel/test-net-socket-byteswritten.js b/node/_tools/test/parallel/test-net-socket-byteswritten.js new file mode 100644 index 000000000000..2ab7c05f4fed --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-byteswritten.js @@ -0,0 +1,42 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const server = net.createServer(function(socket) { + socket.end(); +}); + +server.listen(0, common.mustCall(function() { + const socket = net.connect(server.address().port); + + // Cork the socket, then write twice; this should cause a writev, which + // previously caused an err in the bytesWritten count. + socket.cork(); + + socket.write('one'); + socket.write(Buffer.from('twø', 'utf8')); + + socket.uncork(); + + // one = 3 bytes, twø = 4 bytes + assert.strictEqual(socket.bytesWritten, 3 + 4); + + socket.on('connect', common.mustCall(function() { + assert.strictEqual(socket.bytesWritten, 3 + 4); + })); + + socket.on('end', common.mustCall(function() { + assert.strictEqual(socket.bytesWritten, 3 + 4); + + server.close(); + })); +})); diff --git a/node/_tools/test/parallel/test-net-socket-close-after-end.js b/node/_tools/test/parallel/test-net-socket-close-after-end.js new file mode 100644 index 000000000000..c1cea0324fd9 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-close-after-end.js @@ -0,0 +1,38 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); + +const assert = require('assert'); +const net = require('net'); + +const server = net.createServer(); + +server.on('connection', (socket) => { + let endEmitted = false; + + socket.once('readable', () => { + setTimeout(() => { + socket.read(); + }, common.platformTimeout(100)); + }); + socket.on('end', () => { + endEmitted = true; + }); + socket.on('close', () => { + assert(endEmitted); + server.close(); + }); + socket.end('foo'); +}); + +server.listen(common.mustCall(() => { + const socket = net.createConnection(server.address().port, () => { + socket.end('foo'); + }); +})); diff --git a/node/_tools/test/parallel/test-net-socket-connect-without-cb.js b/node/_tools/test/parallel/test-net-socket-connect-without-cb.js new file mode 100644 index 000000000000..12699c1f433b --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-connect-without-cb.js @@ -0,0 +1,27 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); + +// This test ensures that socket.connect can be called without callback +// which is optional. + +const net = require('net'); + +const server = net.createServer(common.mustCall(function(conn) { + conn.end(); + server.close(); +})).listen(0, common.mustCall(function() { + const client = new net.Socket(); + + client.on('connect', common.mustCall(function() { + client.end(); + })); + + client.connect(server.address()); +})); diff --git a/node/_tools/test/parallel/test-net-socket-connecting.js b/node/_tools/test/parallel/test-net-socket-connecting.js new file mode 100644 index 000000000000..739fac8cb2cc --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-connecting.js @@ -0,0 +1,28 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +const server = net.createServer((conn) => { + conn.end(); + server.close(); +}).listen(0, () => { + const client = net.connect(server.address().port, () => { + assert.strictEqual(client.connecting, false); + + // Legacy getter + assert.strictEqual(client._connecting, false); + client.end(); + }); + assert.strictEqual(client.connecting, true); + + // Legacy getter + assert.strictEqual(client._connecting, true); +}); diff --git a/node/_tools/test/parallel/test-net-socket-constructor.js b/node/_tools/test/parallel/test-net-socket-constructor.js new file mode 100644 index 000000000000..84b32b2f542e --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-constructor.js @@ -0,0 +1,72 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const cluster = require('cluster'); +const net = require('net'); + +assert.throws(() => { + new net.Socket({ fd: -1 }); +}, { code: 'ERR_OUT_OF_RANGE' }); + +assert.throws(() => { + new net.Socket({ fd: 'foo' }); +}, { code: 'ERR_INVALID_ARG_TYPE' }); + +function test(sock, readable, writable) { + let socket; + if (sock instanceof net.Socket) { + socket = sock; + } else { + socket = new net.Socket(sock); + socket.unref(); + } + + assert.strictEqual(socket.readable, readable); + assert.strictEqual(socket.writable, writable); +} + +if (cluster.isPrimary) { + test(undefined, true, true); + + const server = net.createServer(common.mustCall((socket) => { + socket.unref(); + test(socket, true, true); + test({ handle: socket._handle }, true, true); + test({ handle: socket._handle, readable: true, writable: true }, + true, true); + server.close(); + })); + + server.listen(common.mustCall(() => { + const { port } = server.address(); + const socket = net.connect(port, common.mustCall(() => { + test(socket, true, true); + socket.end(); + })); + + test(socket, true, true); + })); + + cluster.setupPrimary({ + stdio: ['pipe', 'pipe', 'pipe', 'ipc', 'pipe', 'pipe', 'pipe'] + }); + + const worker = cluster.fork(); + worker.on('exit', common.mustCall((code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + })); +} else { + test(4, true, true); + test({ fd: 5 }, true, true); + test({ fd: 6, readable: true, writable: true }, true, true); + process.disconnect(); +} diff --git a/node/_tools/test/parallel/test-net-socket-destroy-send.js b/node/_tools/test/parallel/test-net-socket-destroy-send.js new file mode 100644 index 000000000000..3373287a1e68 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-destroy-send.js @@ -0,0 +1,31 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const net = require('net'); +const assert = require('assert'); + +const server = net.createServer(); +server.listen(0, common.mustCall(function() { + const port = server.address().port; + const conn = net.createConnection(port); + + conn.on('connect', common.mustCall(function() { + // Test destroy returns this, even on multiple calls when it short-circuits. + assert.strictEqual(conn, conn.destroy().destroy()); + conn.on('error', common.mustNotCall()); + + conn.write(Buffer.from('kaboom'), common.expectsError({ + code: 'ERR_STREAM_DESTROYED', + message: 'Cannot call write after a stream was destroyed', + name: 'Error' + })); + server.close(); + })); +})); diff --git a/node/_tools/test/parallel/test-net-socket-destroy-twice.js b/node/_tools/test/parallel/test-net-socket-destroy-twice.js new file mode 100644 index 000000000000..296afb26164f --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-destroy-twice.js @@ -0,0 +1,43 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 server = net.createServer(); +server.listen(0); +const port = server.address().port; +const conn = net.createConnection(port); + +conn.on('error', common.mustCall(() => { + conn.destroy(); +})); + +conn.on('close', common.mustCall()); +server.close(); diff --git a/node/_tools/test/parallel/test-net-socket-end-before-connect.js b/node/_tools/test/parallel/test-net-socket-end-before-connect.js new file mode 100644 index 000000000000..f10e18ad2641 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-end-before-connect.js @@ -0,0 +1,20 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); + +const net = require('net'); + +const server = net.createServer(); + +server.listen(common.mustCall(() => { + const socket = net.createConnection(server.address().port); + socket.on('close', common.mustCall(() => server.close())); + socket.end(); +})); diff --git a/node/_tools/test/parallel/test-net-socket-end-callback.js b/node/_tools/test/parallel/test-net-socket-end-callback.js new file mode 100644 index 000000000000..9778695c54b2 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-end-callback.js @@ -0,0 +1,29 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const net = require('net'); + +const server = net.createServer((socket) => { + socket.resume(); +}).unref(); + +server.listen(common.mustCall(() => { + const connect = (...args) => { + const socket = net.createConnection(server.address().port, () => { + socket.end(...args); + }); + }; + + const cb = common.mustCall(() => {}, 3); + + connect(cb); + connect('foo', cb); + connect('foo', 'utf8', cb); +})); diff --git a/node/_tools/test/parallel/test-net-socket-local-address.js b/node/_tools/test/parallel/test-net-socket-local-address.js new file mode 100644 index 000000000000..1c2062ea5d89 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-local-address.js @@ -0,0 +1,48 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'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 net = require('net'); + +let conns = 0; +const clientLocalPorts = []; +const serverRemotePorts = []; +const client = new net.Socket(); +const server = net.createServer((socket) => { + serverRemotePorts.push(socket.remotePort); + socket.end(); +}); + +server.on('close', common.mustCall(() => { + // Client and server should agree on the ports used + assert.deepStrictEqual(serverRemotePorts, clientLocalPorts); + assert.strictEqual(conns, 2); +})); + +server.listen(0, common.localhostIPv4, connect); + +function connect() { + if (conns === 2) { + server.close(); + return; + } + + conns++; + client.once('close', connect); + assert.strictEqual( + client, + client.connect(server.address().port, common.localhostIPv4, () => { + clientLocalPorts.push(client.localPort); + }) + ); +} diff --git a/node/_tools/test/parallel/test-net-socket-no-halfopen-enforcer.js b/node/_tools/test/parallel/test-net-socket-no-halfopen-enforcer.js new file mode 100644 index 000000000000..f8f4eb7c0b25 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-no-halfopen-enforcer.js @@ -0,0 +1,18 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +require('../common'); + +// This test ensures that `net.Socket` does not inherit the no-half-open +// enforcer from `stream.Duplex`. + +const { Socket } = require('net'); +const { strictEqual } = require('assert'); + +const socket = new Socket({ allowHalfOpen: false }); +strictEqual(socket.listenerCount('end'), 1); diff --git a/node/_tools/test/parallel/test-net-socket-ready-without-cb.js b/node/_tools/test/parallel/test-net-socket-ready-without-cb.js new file mode 100644 index 000000000000..fa612e891146 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-ready-without-cb.js @@ -0,0 +1,27 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); + +// This test ensures that socket.connect can be called without callback +// which is optional. + +const net = require('net'); + +const server = net.createServer(common.mustCall(function(conn) { + conn.end(); + server.close(); +})).listen(0, common.mustCall(function() { + const client = new net.Socket(); + + client.on('ready', common.mustCall(function() { + client.end(); + })); + + client.connect(server.address()); +})); diff --git a/node/_tools/test/parallel/test-net-socket-timeout-unref.js b/node/_tools/test/parallel/test-net-socket-timeout-unref.js new file mode 100644 index 000000000000..00b78f334b5d --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-timeout-unref.js @@ -0,0 +1,63 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; + +// Test that unref'ed sockets with timeouts do not prevent exit. + +const common = require('../common'); +const net = require('net'); + +const server = net.createServer(function(c) { + c.write('hello'); + c.unref(); +}); +server.listen(0); +server.unref(); + +let connections = 0; +const sockets = []; +const delays = [8, 5, 3, 6, 2, 4]; + +delays.forEach(function(T) { + const socket = net.createConnection(server.address().port, 'localhost'); + socket.on('connect', common.mustCall(function() { + if (++connections === delays.length) { + sockets.forEach(function(s) { + s.socket.setTimeout(s.timeout, function() { + s.socket.destroy(); + throw new Error('socket timed out unexpectedly'); + }); + + s.socket.unref(); + }); + } + })); + + sockets.push({ socket: socket, timeout: T * 1000 }); +}); diff --git a/node/_tools/test/parallel/test-net-socket-timeout.js b/node/_tools/test/parallel/test-net-socket-timeout.js new file mode 100644 index 000000000000..845d08f4cc79 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-timeout.js @@ -0,0 +1,90 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const { inspect } = require('util'); + +// Verify that invalid delays throw +const s = new net.Socket(); +const nonNumericDelays = [ + '100', true, false, undefined, null, '', {}, () => {}, [], +]; +const badRangeDelays = [-0.001, -1, -Infinity, Infinity, NaN]; +const validDelays = [0, 0.001, 1, 1e6]; +const invalidCallbacks = [ + 1, '100', true, false, null, {}, [], Symbol('test'), +]; + + +for (let i = 0; i < nonNumericDelays.length; i++) { + assert.throws(() => { + s.setTimeout(nonNumericDelays[i], () => {}); + }, { code: 'ERR_INVALID_ARG_TYPE' }, nonNumericDelays[i]); +} + +for (let i = 0; i < badRangeDelays.length; i++) { + assert.throws(() => { + s.setTimeout(badRangeDelays[i], () => {}); + }, { code: 'ERR_OUT_OF_RANGE' }, badRangeDelays[i]); +} + +for (let i = 0; i < validDelays.length; i++) { + s.setTimeout(validDelays[i], () => {}); +} + +for (let i = 0; i < invalidCallbacks.length; i++) { + [0, 1].forEach((mesc) => + assert.throws( + () => s.setTimeout(mesc, invalidCallbacks[i]), + { + code: 'ERR_INVALID_CALLBACK', + name: 'TypeError', + message: 'Callback must be a function. ' + + `Received ${inspect(invalidCallbacks[i])}` + } + ) + ); +} + +// TODO: support net.Server() without new + +const server = new net.Server(); +server.listen(0, common.mustCall(() => { + const socket = net.createConnection(server.address().port); + assert.strictEqual( + socket.setTimeout(1, common.mustCall(() => { + socket.destroy(); + assert.strictEqual(socket.setTimeout(1, common.mustNotCall()), socket); + server.close(); + })), + socket + ); +})); diff --git a/node/_tools/test/parallel/test-net-socket-write-after-close.js b/node/_tools/test/parallel/test-net-socket-write-after-close.js new file mode 100644 index 000000000000..97e8b39f5c6f --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-write-after-close.js @@ -0,0 +1,49 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +{ + const server = net.createServer(); + + server.listen(common.mustCall(() => { + const port = server.address().port; + const client = net.connect({ port }, common.mustCall(() => { + client.on('error', common.mustCall((err) => { + server.close(); + assert.strictEqual(err.constructor, Error); + assert.strictEqual(err.message, 'write EBADF'); + })); + client._handle.close(); + client.write('foo'); + })); + })); +} + +{ + const server = net.createServer(); + + server.listen(common.mustCall(() => { + const port = server.address().port; + const client = net.connect({ port }, common.mustCall(() => { + client.on('error', common.expectsError({ + code: 'ERR_SOCKET_CLOSED', + message: 'Socket is closed', + name: 'Error' + })); + + server.close(); + + client._handle.close(); + client._handle = null; + client.write('foo'); + })); + })); +} diff --git a/node/_tools/test/parallel/test-net-socket-write-error.js b/node/_tools/test/parallel/test-net-socket-write-error.js new file mode 100644 index 000000000000..832fad51a601 --- /dev/null +++ b/node/_tools/test/parallel/test-net-socket-write-error.js @@ -0,0 +1,29 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const net = require('net'); +const assert = require('assert'); + +const server = net.createServer().listen(0, connectToServer); + +function connectToServer() { + const client = net.createConnection(this.address().port, () => { + client.on('error', common.mustNotCall()); + assert.throws(() => { + client.write(1337); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' + }); + + client.destroy(); + }) + .on('close', () => server.close()); +} diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index 488b8c4b8617..b256d74e2332 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -156,6 +156,8 @@ export class Pipe extends ConnectionWrap { if (e instanceof Deno.errors.NotFound) { code = codeMap.get("ENOENT")!; + } else if (e instanceof Deno.errors.PermissionDenied) { + code = codeMap.get("EACCES")!; } else { code = codeMap.get("ECONNREFUSED")!; } diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index 76c7f6505309..d488c193807f 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -98,7 +98,7 @@ export class LibuvStreamWrap extends HandleWrap { constructor( provider: providerType, - stream?: Deno.Reader & Deno.Writer & Deno.Closer, + stream?: Deno.Reader & Deno.Writer & Deno.Closer ) { super(provider); this.#attachToObject(stream); @@ -115,7 +115,7 @@ export class LibuvStreamWrap extends HandleWrap { this.#currentReads.add(readPromise); readPromise.then( () => this.#currentReads.delete(readPromise), - () => this.#currentReads.delete(readPromise), + () => this.#currentReads.delete(readPromise) ); } @@ -171,7 +171,7 @@ export class LibuvStreamWrap extends HandleWrap { this.#currentWrites.add(currentWrite); currentWrite.then( () => this.#currentWrites.delete(currentWrite), - () => this.#currentWrites.delete(currentWrite), + () => this.#currentWrites.delete(currentWrite) ); return 0; @@ -187,7 +187,7 @@ export class LibuvStreamWrap extends HandleWrap { writev( req: WriteWrap, chunks: Buffer[] | (string | Buffer)[], - allBuffers: boolean, + allBuffers: boolean ): number { const count = allBuffers ? chunks.length : chunks.length >> 1; const buffers: Buffer[] = new Array(count); @@ -287,6 +287,8 @@ export class LibuvStreamWrap extends HandleWrap { e instanceof Deno.errors.BadResource ) { nread = codeMap.get("EOF")!; + } else if (e instanceof Deno.errors.ConnectionReset) { + nread = codeMap.get("ECONNRESET")!; } else { nread = codeMap.get("UNKNOWN")!; } @@ -317,7 +319,7 @@ export class LibuvStreamWrap extends HandleWrap { this.#currentReads.add(readPromise); readPromise.then( () => this.#currentReads.delete(readPromise), - () => this.#currentReads.delete(readPromise), + () => this.#currentReads.delete(readPromise) ); } } @@ -333,9 +335,15 @@ export class LibuvStreamWrap extends HandleWrap { try { // TODO(cmorten): somewhat over simplifying what Node does. await writeAll(this[kStreamBaseField]!, data); - } catch { + } catch (e) { + let status: number; + // TODO(cmorten): map err to status codes - const status = codeMap.get("UNKNOWN")!; + if (e instanceof Deno.errors.BadResource) { + status = codeMap.get("EBADF")!; + } else { + status = codeMap.get("UNKNOWN")!; + } try { req.oncomplete(status); From bbdf5bf38c6eb6d72ee3b40de29c80641e694947 Mon Sep 17 00:00:00 2001 From: cmorten Date: Tue, 26 Apr 2022 23:22:03 +0100 Subject: [PATCH 21/35] fix: formatting --- node/internal_binding/stream_wrap.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index d488c193807f..66578f03f7f5 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -98,7 +98,7 @@ export class LibuvStreamWrap extends HandleWrap { constructor( provider: providerType, - stream?: Deno.Reader & Deno.Writer & Deno.Closer + stream?: Deno.Reader & Deno.Writer & Deno.Closer, ) { super(provider); this.#attachToObject(stream); @@ -115,7 +115,7 @@ export class LibuvStreamWrap extends HandleWrap { this.#currentReads.add(readPromise); readPromise.then( () => this.#currentReads.delete(readPromise), - () => this.#currentReads.delete(readPromise) + () => this.#currentReads.delete(readPromise), ); } @@ -171,7 +171,7 @@ export class LibuvStreamWrap extends HandleWrap { this.#currentWrites.add(currentWrite); currentWrite.then( () => this.#currentWrites.delete(currentWrite), - () => this.#currentWrites.delete(currentWrite) + () => this.#currentWrites.delete(currentWrite), ); return 0; @@ -187,7 +187,7 @@ export class LibuvStreamWrap extends HandleWrap { writev( req: WriteWrap, chunks: Buffer[] | (string | Buffer)[], - allBuffers: boolean + allBuffers: boolean, ): number { const count = allBuffers ? chunks.length : chunks.length >> 1; const buffers: Buffer[] = new Array(count); @@ -319,7 +319,7 @@ export class LibuvStreamWrap extends HandleWrap { this.#currentReads.add(readPromise); readPromise.then( () => this.#currentReads.delete(readPromise), - () => this.#currentReads.delete(readPromise) + () => this.#currentReads.delete(readPromise), ); } } From 4d191c0e88a119cbdbc184842ce549985a4a94d3 Mon Sep 17 00:00:00 2001 From: Craig Morten Date: Wed, 27 Apr 2022 11:36:17 +0100 Subject: [PATCH 22/35] fix: force windows to IPv4 with implicit binding --- node/_tools/config.json | 3 +- .../parallel/test-net-pipe-connect-errors.js | 6 +++ node/internal_binding/cares_wrap.ts | 10 +++- node/internal_binding/stream_wrap.ts | 2 +- node/net.ts | 47 ++++++++++++------- 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/node/_tools/config.json b/node/_tools/config.json index 9ebab34f6db5..255522e8e0ce 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -37,6 +37,7 @@ "test-net-connect-buffer.js", "test-net-connect-buffer2.js", "test-net-listen-invalid-port.js", + "test-net-pipe-connect-errors.js", "test-net-server-call-listen-multiple-times.js", "test-net-server-listen-path.js", "test-net-server-try-ports.js", @@ -263,7 +264,6 @@ "test-net-eaddrinuse.js", "test-net-end-destroyed.js", "test-net-end-without-connect.js", - "test-net-error-twice.js", "test-net-isip.js", "test-net-isipv4.js", "test-net-isipv6.js", @@ -287,7 +287,6 @@ "test-net-server-listen-options.js", "test-net-server-listen-path.js", "test-net-server-listen-remove-callback.js", - "test-net-server-max-connections-close-makes-more-available.js", "test-net-server-max-connections.js", "test-net-server-options.js", "test-net-server-pause-on-connect.js", diff --git a/node/_tools/test/parallel/test-net-pipe-connect-errors.js b/node/_tools/test/parallel/test-net-pipe-connect-errors.js index 7ad19f885a46..7cd70bb726ee 100644 --- a/node/_tools/test/parallel/test-net-pipe-connect-errors.js +++ b/node/_tools/test/parallel/test-net-pipe-connect-errors.js @@ -33,6 +33,12 @@ const fs = require('fs'); const net = require('net'); const assert = require('assert'); +// TODO(cmorten): reenable for windows once named pipes are supported +// REF: https://github.com/denoland/deno/issues/10244 +if (common.isWindows) { + return; +} + // Test if ENOTSOCK is fired when trying to connect to a file which is not // a socket. diff --git a/node/internal_binding/cares_wrap.ts b/node/internal_binding/cares_wrap.ts index 33eb50da4517..75a5162f4ef6 100644 --- a/node/internal_binding/cares_wrap.ts +++ b/node/internal_binding/cares_wrap.ts @@ -28,6 +28,7 @@ import type { ErrnoException } from "../internal/errors.ts"; import { isIPv4 } from "../internal/net.ts"; import { codeMap } from "./uv.ts"; import { AsyncWrap, providerType } from "./async_wrap.ts"; +import { isWindows } from "../../_util/os.ts"; interface LookupAddress { address: string; @@ -68,7 +69,7 @@ export function getaddrinfo( verbatim: boolean, ) { (async () => { - const addresses: string[] = []; + let addresses: string[] = []; // TODO(cmorten): use hints // REF: https://nodejs.org/api/dns.html#dns_supported_getaddrinfo_flags @@ -105,6 +106,13 @@ export function getaddrinfo( return 0; }); } + + // TODO: Forces IPv4 as a workaround for Deno not + // aligning with Node on implicit binding on Windows + // REF: https://github.com/denoland/deno/issues/10762 + if (isWindows && hostname === "localhost") { + addresses = addresses.filter(address => isIPv4(address)); + } req.oncomplete(error, addresses); })(); diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index 66578f03f7f5..e77a1924fd79 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -287,7 +287,7 @@ export class LibuvStreamWrap extends HandleWrap { e instanceof Deno.errors.BadResource ) { nread = codeMap.get("EOF")!; - } else if (e instanceof Deno.errors.ConnectionReset) { + } else if (e instanceof Deno.errors.ConnectionReset || e instanceof Deno.errors.ConnectionAborted) { nread = codeMap.get("ECONNRESET")!; } else { nread = codeMap.get("UNKNOWN")!; diff --git a/node/net.ts b/node/net.ts index 5f5bf094b67d..5a92c0d36c35 100644 --- a/node/net.ts +++ b/node/net.ts @@ -1768,15 +1768,23 @@ export function _createServerHandle( debug("bind to", address || "any"); if (!address) { + // TODO: differs from Node which tries to bind to IPv6 first when no + // address is provided. + // + // Forcing IPv4 as a workaround for Deno not aligning with Node on + // implicit binding on Windows. + // + // REF: https://github.com/denoland/deno/issues/10762 + // Try binding to ipv6 first - err = (handle as TCP).bind6(DEFAULT_IPV6_ADDR, port ?? 0, flags ?? 0); + // err = (handle as TCP).bind6(DEFAULT_IPV6_ADDR, port ?? 0, flags ?? 0); - if (err) { - handle.close(); + // if (err) { + // handle.close(); - // Fallback to ipv4 - return _createServerHandle(DEFAULT_IPV4_ADDR, port, 4, null, flags); - } + // Fallback to ipv4 + return _createServerHandle(DEFAULT_IPV4_ADDR, port, 4, null, flags); + // } } else if (addressType === 6) { err = (handle as TCP).bind6(address, port ?? 0, flags ?? 0); } else { @@ -1862,16 +1870,23 @@ function _setupListenHandle( // Try to bind to the unspecified IPv6 address, see if IPv6 is available if (!address && typeof fd !== "number") { - rval = _createServerHandle(DEFAULT_IPV6_ADDR, port, 6, fd, flags); - - if (typeof rval === "number") { - rval = null; - address = DEFAULT_IPV4_ADDR; - addressType = 4; - } else { - address = DEFAULT_IPV6_ADDR; - addressType = 6; - } + // TODO: differs from Node which tries to bind to IPv6 first when no + // address is provided. + // + // Forcing IPv4 as a workaround for Deno not aligning with Node on + // implicit binding on Windows. + // + // REF: https://github.com/denoland/deno/issues/10762 + // rval = _createServerHandle(DEFAULT_IPV6_ADDR, port, 6, fd, flags); + + // if (typeof rval === "number") { + // rval = null; + address = DEFAULT_IPV4_ADDR; + addressType = 4; + // } else { + // address = DEFAULT_IPV6_ADDR; + // addressType = 6; + // } } if (rval === null) { From 860a5212dde28c5fe5e7614ae2a01e4c73c465e2 Mon Sep 17 00:00:00 2001 From: Craig Morten Date: Wed, 27 Apr 2022 11:36:59 +0100 Subject: [PATCH 23/35] fix: formatting --- node/internal_binding/cares_wrap.ts | 4 ++-- node/internal_binding/stream_wrap.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/node/internal_binding/cares_wrap.ts b/node/internal_binding/cares_wrap.ts index 75a5162f4ef6..9b7751d90537 100644 --- a/node/internal_binding/cares_wrap.ts +++ b/node/internal_binding/cares_wrap.ts @@ -106,12 +106,12 @@ export function getaddrinfo( return 0; }); } - + // TODO: Forces IPv4 as a workaround for Deno not // aligning with Node on implicit binding on Windows // REF: https://github.com/denoland/deno/issues/10762 if (isWindows && hostname === "localhost") { - addresses = addresses.filter(address => isIPv4(address)); + addresses = addresses.filter((address) => isIPv4(address)); } req.oncomplete(error, addresses); diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index e77a1924fd79..4ee408c7cddb 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -287,7 +287,10 @@ export class LibuvStreamWrap extends HandleWrap { e instanceof Deno.errors.BadResource ) { nread = codeMap.get("EOF")!; - } else if (e instanceof Deno.errors.ConnectionReset || e instanceof Deno.errors.ConnectionAborted) { + } else if ( + e instanceof Deno.errors.ConnectionReset || + e instanceof Deno.errors.ConnectionAborted + ) { nread = codeMap.get("ECONNRESET")!; } else { nread = codeMap.get("UNKNOWN")!; From 52b436adeacf5e952d1c05b66160cbbf3a355712 Mon Sep 17 00:00:00 2001 From: cmorten Date: Wed, 27 Apr 2022 12:56:07 +0100 Subject: [PATCH 24/35] test: expand net test coverage --- node/_tools/common.ts | 2 +- node/_tools/config.json | 25 +++- ...t-net-better-error-messages-listen-path.js | 7 -- .../test-net-better-error-messages-path.js | 6 - .../parallel/test-net-pipe-connect-errors.js | 6 - .../parallel/test-net-server-listen-path.js | 44 +++---- ...-connections-close-makes-more-available.js | 92 -------------- .../parallel/test-net-socket-byteswritten.js | 42 ------- .../parallel/test-net-socket-constructor.js | 72 ----------- .../parallel/test-net-socket-local-address.js | 48 -------- ...t-net-settimeout.js => test-net-stream.js} | 37 +++--- .../test/parallel/test-net-sync-cork.js | 40 ++++++ .../parallel/test-net-timeout-no-handle.js | 24 ++++ .../_tools/test/parallel/test-net-writable.js | 22 ++++ .../parallel/test-net-write-after-end-nt.js | 39 ++++++ .../test/parallel/test-net-write-arguments.js | 46 +++++++ .../test-net-write-fully-async-buffer.js | 41 +++++++ .../test-net-write-fully-async-hex-string.js | 39 ++++++ ...imeout-unref.js => test-net-write-slow.js} | 61 +++++----- ...t-net-bytes-per-incoming-chunk-overhead.js | 58 +++++++++ .../test/pummel/test-net-pingpong-delay.js | 114 ++++++++++++++++++ .../test-net-write-callbacks.js} | 64 +++++----- 22 files changed, 554 insertions(+), 375 deletions(-) delete mode 100644 node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js delete mode 100644 node/_tools/test/parallel/test-net-socket-byteswritten.js delete mode 100644 node/_tools/test/parallel/test-net-socket-constructor.js delete mode 100644 node/_tools/test/parallel/test-net-socket-local-address.js rename node/_tools/test/parallel/{test-net-settimeout.js => test-net-stream.js} (73%) create mode 100644 node/_tools/test/parallel/test-net-sync-cork.js create mode 100644 node/_tools/test/parallel/test-net-timeout-no-handle.js create mode 100644 node/_tools/test/parallel/test-net-writable.js create mode 100644 node/_tools/test/parallel/test-net-write-after-end-nt.js create mode 100644 node/_tools/test/parallel/test-net-write-arguments.js create mode 100644 node/_tools/test/parallel/test-net-write-fully-async-buffer.js create mode 100644 node/_tools/test/parallel/test-net-write-fully-async-hex-string.js rename node/_tools/test/parallel/{test-net-socket-timeout-unref.js => test-net-write-slow.js} (62%) create mode 100644 node/_tools/test/pummel/test-net-bytes-per-incoming-chunk-overhead.js create mode 100644 node/_tools/test/pummel/test-net-pingpong-delay.js rename node/_tools/test/{parallel/test-net-error-twice.js => pummel/test-net-write-callbacks.js} (63%) diff --git a/node/_tools/common.ts b/node/_tools/common.ts index ebe26e508c04..d6048d050353 100644 --- a/node/_tools/common.ts +++ b/node/_tools/common.ts @@ -41,7 +41,7 @@ export const ignoreList = Object.entries(config.ignore).reduce( export function getPathsFromTestSuites(suites: TestSuites): string[] { const testPaths: string[] = []; for (const [dir, paths] of Object.entries(suites)) { - if (dir === "parallel" || dir === "internet") { + if (["parallel", "internet", "pummel"].includes(dir)) { for (const path of paths) { testPaths.push(join(dir, path)); } diff --git a/node/_tools/config.json b/node/_tools/config.json index 255522e8e0ce..c23266dc0836 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -32,14 +32,11 @@ "test-fs-rmdir-recursive.js", "test-fs-write-file.js", "test-fs-write.js", - "test-net-better-error-messages-listen-path.js", "test-net-better-error-messages-path.js", "test-net-connect-buffer.js", "test-net-connect-buffer2.js", "test-net-listen-invalid-port.js", - "test-net-pipe-connect-errors.js", "test-net-server-call-listen-multiple-times.js", - "test-net-server-listen-path.js", "test-net-server-try-ports.js", "test-net-socket-timeout.js", "test-os.js", @@ -66,6 +63,10 @@ "test-zlib-write-after-flush.js", "test-zlib-zero-byte.js", "test-zlib-zero-windowBits.js" + ], + "pummel": [ + "test-net-bytes-per-incoming-chunk-overhead.js", + "test-net-write-callbacks.js" ] }, "tests": { @@ -305,6 +306,15 @@ "test-net-socket-timeout.js", "test-net-socket-write-after-close.js", "test-net-socket-write-error.js", + "test-net-stream.js", + "test-net-sync-cork.js", + "test-net-timeout-no-handle.js", + "test-net-writable.js", + "test-net-write-after-end-nt.js", + "test-net-write-arguments.js", + "test-net-write-fully-async-buffer.js", + "test-net-write-fully-async-hex-string.js", + "test-net-write-slow.js", "test-next-tick-doesnt-hang.js", "test-next-tick-fixed-queue-regression.js", "test-next-tick-intentional-starvation.js", @@ -548,6 +558,11 @@ "test-zlib-write-after-flush.js", "test-zlib-zero-byte.js", "test-zlib-zero-windowBits.js" + ], + "pummel": [ + "test-net-bytes-per-incoming-chunk-overhead.js", + "test-net-pingpong-delay.js", + "test-net-write-callbacks.js" ] }, "windowsIgnore": { @@ -564,6 +579,10 @@ "test-fs-write-file-sync.js", "test-fs-write-file.js", "test-http-client-reject-cr-no-lf.js", + "test-net-better-error-messages-listen-path.js", + "test-net-better-error-messages-path.js", + "test-net-pipe-connect-errors.js", + "test-net-server-listen-path.js", "test-util-inspect-getters-accessing-this.js", "test-util-inspect-long-running.js", "test-util-inspect.js" diff --git a/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js index f64385aa24c0..147d102e577e 100644 --- a/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js +++ b/node/_tools/test/parallel/test-net-better-error-messages-listen-path.js @@ -7,13 +7,6 @@ 'use strict'; const common = require('../common'); - -// TODO(cmorten): reenable for windows once named pipes are supported -// REF: https://github.com/denoland/deno/issues/10244 -if (common.isWindows) { - return; -} - const assert = require('assert'); const net = require('net'); const fp = '/blah/fadfa'; diff --git a/node/_tools/test/parallel/test-net-better-error-messages-path.js b/node/_tools/test/parallel/test-net-better-error-messages-path.js index 78a24ffd7cf7..d1bada362dd7 100644 --- a/node/_tools/test/parallel/test-net-better-error-messages-path.js +++ b/node/_tools/test/parallel/test-net-better-error-messages-path.js @@ -10,12 +10,6 @@ const common = require('../common'); const assert = require('assert'); const net = require('net'); -// TODO(cmorten): reenable for windows once named pipes are supported -// REF: https://github.com/denoland/deno/issues/10244 -if (common.isWindows) { - return; -} - { const fp = '/tmp/fadagagsdfgsdf'; const c = net.connect(fp); diff --git a/node/_tools/test/parallel/test-net-pipe-connect-errors.js b/node/_tools/test/parallel/test-net-pipe-connect-errors.js index 7cd70bb726ee..7ad19f885a46 100644 --- a/node/_tools/test/parallel/test-net-pipe-connect-errors.js +++ b/node/_tools/test/parallel/test-net-pipe-connect-errors.js @@ -33,12 +33,6 @@ const fs = require('fs'); const net = require('net'); const assert = require('assert'); -// TODO(cmorten): reenable for windows once named pipes are supported -// REF: https://github.com/denoland/deno/issues/10244 -if (common.isWindows) { - return; -} - // Test if ENOTSOCK is fired when trying to connect to a file which is not // a socket. diff --git a/node/_tools/test/parallel/test-net-server-listen-path.js b/node/_tools/test/parallel/test-net-server-listen-path.js index f7c818cf465b..59df3c09ba9b 100644 --- a/node/_tools/test/parallel/test-net-server-listen-path.js +++ b/node/_tools/test/parallel/test-net-server-listen-path.js @@ -12,12 +12,6 @@ const net = require('net'); const assert = require('assert'); const fs = require('fs'); -// TODO(cmorten): reenable for windows once named pipes are supported -// REF: https://github.com/denoland/deno/issues/10244 -if (common.isWindows) { - return; -} - const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); @@ -83,24 +77,22 @@ function randomPipePath() { })); } -// TODO(cmorten): seems Deno.listen() for Unix domains isn't throwing -// Deno.errors.AddrInUse errors as would expect...? // Test should emit "error" events when listening fails. -// { -// const handlePath = randomPipePath(); -// const server1 = net.createServer().listen({ path: handlePath }, () => { -// // As the handlePath is in use, binding to the same address again should -// // make the server emit an 'EADDRINUSE' error. -// const server2 = net.createServer() -// .listen({ -// path: handlePath, -// writableAll: true, -// }, common.mustNotCall()); - -// server2.on('error', common.mustCall((err) => { -// server1.close(); -// assert.strictEqual(err.code, 'EADDRINUSE'); -// assert.match(err.message, /^listen EADDRINUSE: address already in use/); -// })); -// }); -// } +{ + const handlePath = randomPipePath(); + const server1 = net.createServer().listen({ path: handlePath }, () => { + // As the handlePath is in use, binding to the same address again should + // make the server emit an 'EADDRINUSE' error. + const server2 = net.createServer() + .listen({ + path: handlePath, + writableAll: true, + }, common.mustNotCall()); + + server2.on('error', common.mustCall((err) => { + server1.close(); + assert.strictEqual(err.code, 'EADDRINUSE'); + assert.match(err.message, /^listen EADDRINUSE: address already in use/); + })); + }); +} diff --git a/node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js b/node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js deleted file mode 100644 index 3d7feb62eea7..000000000000 --- a/node/_tools/test/parallel/test-net-server-max-connections-close-makes-more-available.js +++ /dev/null @@ -1,92 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -'use strict'; -require('../common'); -const assert = require('assert'); - -const net = require('net'); - -// Sets the server's maxConnections property to 1. -// Open 2 connections (connection 0 and connection 1). -// Connection 0 should be accepted. -// Connection 1 should be rejected. -// Closes connection 0. -// Open 2 more connections (connection 2 and 3). -// Connection 2 should be accepted. -// Connection 3 should be rejected. - -const connections = []; -const received = []; -const sent = []; - -function createConnection(index) { - console.error(`creating connection ${index}`); - - return new Promise(function(resolve, reject) { - const connection = net.createConnection(server.address().port, function() { - const msg = String(index); - console.error(`sending message: ${msg}`); - this.write(msg); - sent.push(msg); - }); - - connection.on('error', function(err) { - assert.strictEqual(err.code, 'ECONNRESET'); - resolve(); - }); - - connection.on('data', function(e) { - console.error(`connection ${index} received response`); - resolve(); - }); - - connection.on('end', function() { - console.error(`ending ${index}`); - resolve(); - }); - - connections[index] = connection; - }); -} - -function closeConnection(index) { - console.error(`closing connection ${index}`); - return new Promise(function(resolve, reject) { - connections[index].on('end', function() { - resolve(); - }); - connections[index].end(); - }); -} - -const server = net.createServer(function(socket) { - socket.on('data', function(data) { - console.error(`received message: ${data}`); - received.push(String(data)); - socket.write('acknowledged'); - }); -}); - -server.maxConnections = 1; - -server.listen(0, function() { - createConnection(0) - .then(createConnection.bind(null, 1)) - .then(closeConnection.bind(null, 0)) - .then(createConnection.bind(null, 2)) - .then(createConnection.bind(null, 3)) - .then(server.close.bind(server)) - .then(closeConnection.bind(null, 2)); -}); - -process.on('exit', function() { - // Confirm that all connections tried to send data... - assert.deepStrictEqual(sent, ['0', '1', '2', '3']); - // ...but that only connections 0 and 2 were successful. - assert.deepStrictEqual(received, ['0', '2']); -}); diff --git a/node/_tools/test/parallel/test-net-socket-byteswritten.js b/node/_tools/test/parallel/test-net-socket-byteswritten.js deleted file mode 100644 index 2ab7c05f4fed..000000000000 --- a/node/_tools/test/parallel/test-net-socket-byteswritten.js +++ /dev/null @@ -1,42 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const net = require('net'); - -const server = net.createServer(function(socket) { - socket.end(); -}); - -server.listen(0, common.mustCall(function() { - const socket = net.connect(server.address().port); - - // Cork the socket, then write twice; this should cause a writev, which - // previously caused an err in the bytesWritten count. - socket.cork(); - - socket.write('one'); - socket.write(Buffer.from('twø', 'utf8')); - - socket.uncork(); - - // one = 3 bytes, twø = 4 bytes - assert.strictEqual(socket.bytesWritten, 3 + 4); - - socket.on('connect', common.mustCall(function() { - assert.strictEqual(socket.bytesWritten, 3 + 4); - })); - - socket.on('end', common.mustCall(function() { - assert.strictEqual(socket.bytesWritten, 3 + 4); - - server.close(); - })); -})); diff --git a/node/_tools/test/parallel/test-net-socket-constructor.js b/node/_tools/test/parallel/test-net-socket-constructor.js deleted file mode 100644 index 84b32b2f542e..000000000000 --- a/node/_tools/test/parallel/test-net-socket-constructor.js +++ /dev/null @@ -1,72 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const cluster = require('cluster'); -const net = require('net'); - -assert.throws(() => { - new net.Socket({ fd: -1 }); -}, { code: 'ERR_OUT_OF_RANGE' }); - -assert.throws(() => { - new net.Socket({ fd: 'foo' }); -}, { code: 'ERR_INVALID_ARG_TYPE' }); - -function test(sock, readable, writable) { - let socket; - if (sock instanceof net.Socket) { - socket = sock; - } else { - socket = new net.Socket(sock); - socket.unref(); - } - - assert.strictEqual(socket.readable, readable); - assert.strictEqual(socket.writable, writable); -} - -if (cluster.isPrimary) { - test(undefined, true, true); - - const server = net.createServer(common.mustCall((socket) => { - socket.unref(); - test(socket, true, true); - test({ handle: socket._handle }, true, true); - test({ handle: socket._handle, readable: true, writable: true }, - true, true); - server.close(); - })); - - server.listen(common.mustCall(() => { - const { port } = server.address(); - const socket = net.connect(port, common.mustCall(() => { - test(socket, true, true); - socket.end(); - })); - - test(socket, true, true); - })); - - cluster.setupPrimary({ - stdio: ['pipe', 'pipe', 'pipe', 'ipc', 'pipe', 'pipe', 'pipe'] - }); - - const worker = cluster.fork(); - worker.on('exit', common.mustCall((code, signal) => { - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - })); -} else { - test(4, true, true); - test({ fd: 5 }, true, true); - test({ fd: 6, readable: true, writable: true }, true, true); - process.disconnect(); -} diff --git a/node/_tools/test/parallel/test-net-socket-local-address.js b/node/_tools/test/parallel/test-net-socket-local-address.js deleted file mode 100644 index 1c2062ea5d89..000000000000 --- a/node/_tools/test/parallel/test-net-socket-local-address.js +++ /dev/null @@ -1,48 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -'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 net = require('net'); - -let conns = 0; -const clientLocalPorts = []; -const serverRemotePorts = []; -const client = new net.Socket(); -const server = net.createServer((socket) => { - serverRemotePorts.push(socket.remotePort); - socket.end(); -}); - -server.on('close', common.mustCall(() => { - // Client and server should agree on the ports used - assert.deepStrictEqual(serverRemotePorts, clientLocalPorts); - assert.strictEqual(conns, 2); -})); - -server.listen(0, common.localhostIPv4, connect); - -function connect() { - if (conns === 2) { - server.close(); - return; - } - - conns++; - client.once('close', connect); - assert.strictEqual( - client, - client.connect(server.address().port, common.localhostIPv4, () => { - clientLocalPorts.push(client.localPort); - }) - ); -} diff --git a/node/_tools/test/parallel/test-net-settimeout.js b/node/_tools/test/parallel/test-net-stream.js similarity index 73% rename from node/_tools/test/parallel/test-net-settimeout.js rename to node/_tools/test/parallel/test-net-stream.js index 1ba8285cd370..bc4bc355d0b2 100644 --- a/node/_tools/test/parallel/test-net-settimeout.js +++ b/node/_tools/test/parallel/test-net-stream.js @@ -27,31 +27,32 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -// This example sets a timeout then immediately attempts to disable the timeout -// https://github.com/joyent/node/pull/2245 const common = require('../common'); -const net = require('net'); const assert = require('assert'); +const net = require('net'); -const T = 100; +const SIZE = 2E6; +const N = 10; +const buf = Buffer.alloc(SIZE, 'a'); -const server = net.createServer(common.mustCall((c) => { - c.write('hello'); -})); +const server = net.createServer(function(socket) { + socket.setNoDelay(); -server.listen(0, function() { - const socket = net.createConnection(this.address().port, 'localhost'); + socket.on('error', common.mustCall(() => socket.destroy())) + .on('close', common.mustCall(() => server.close())); - const s = socket.setTimeout(T, common.mustNotCall()); - assert.ok(s instanceof net.Socket); + for (let i = 0; i < N; ++i) { + socket.write(buf, () => {}); + } + socket.end(); - socket.on('data', common.mustCall(() => { +}).listen(0, function() { + const conn = net.connect(this.address().port); + conn.on('data', function(buf) { + assert.strictEqual(conn, conn.pause()); setTimeout(function() { - socket.destroy(); - server.close(); - }, T * 2); - })); - - socket.setTimeout(0); + conn.destroy(); + }, 20); + }); }); diff --git a/node/_tools/test/parallel/test-net-sync-cork.js b/node/_tools/test/parallel/test-net-sync-cork.js new file mode 100644 index 000000000000..74872eaba9aa --- /dev/null +++ b/node/_tools/test/parallel/test-net-sync-cork.js @@ -0,0 +1,40 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const server = net.createServer(handle); + +const N = 100; +const buf = Buffer.alloc(2, 'a'); + +server.listen(0, function() { + const conn = net.connect(this.address().port); + + conn.on('connect', () => { + let res = true; + let i = 0; + for (; i < N && res; i++) { + conn.cork(); + conn.write(buf); + res = conn.write(buf); + conn.uncork(); + } + assert.strictEqual(i, N); + conn.end(); + }); +}); + +function handle(socket) { + socket.resume(); + socket.on('error', common.mustNotCall()) + .on('close', common.mustCall(() => server.close())); +} diff --git a/node/_tools/test/parallel/test-net-timeout-no-handle.js b/node/_tools/test/parallel/test-net-timeout-no-handle.js new file mode 100644 index 000000000000..f2a648f1bb75 --- /dev/null +++ b/node/_tools/test/parallel/test-net-timeout-no-handle.js @@ -0,0 +1,24 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; + +const common = require('../common'); +const net = require('net'); +const assert = require('assert'); + +const socket = new net.Socket(); +socket.setTimeout(common.platformTimeout(50)); + +socket.on('timeout', common.mustCall(() => { + assert.strictEqual(socket._handle, null); +})); + +socket.on('connect', common.mustNotCall()); + +// Since the timeout is unrefed, the code will exit without this +setTimeout(() => {}, common.platformTimeout(200)); diff --git a/node/_tools/test/parallel/test-net-writable.js b/node/_tools/test/parallel/test-net-writable.js new file mode 100644 index 000000000000..4cfbccbcb974 --- /dev/null +++ b/node/_tools/test/parallel/test-net-writable.js @@ -0,0 +1,22 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const server = net.createServer(common.mustCall(function(s) { + server.close(); + s.end(); +})).listen(0, 'localhost', common.mustCall(function() { + const socket = net.connect(this.address().port, 'localhost'); + socket.on('end', common.mustCall(() => { + assert.strictEqual(socket.writable, true); + socket.write('hello world'); + })); +})); diff --git a/node/_tools/test/parallel/test-net-write-after-end-nt.js b/node/_tools/test/parallel/test-net-write-after-end-nt.js new file mode 100644 index 000000000000..032a0c39c900 --- /dev/null +++ b/node/_tools/test/parallel/test-net-write-after-end-nt.js @@ -0,0 +1,39 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); + +const assert = require('assert'); +const net = require('net'); + +const { expectsError, mustCall } = common; + +// This test ensures those errors caused by calling `net.Socket.write()` +// after sockets ending will be emitted in the next tick. +const server = net.createServer(mustCall((socket) => { + socket.end(); +})).listen(() => { + const client = net.connect(server.address().port, () => { + let hasError = false; + client.on('error', mustCall((err) => { + hasError = true; + server.close(); + })); + client.on('end', mustCall(() => { + const ret = client.write('hello', expectsError({ + code: 'EPIPE', + message: 'This socket has been ended by the other party', + name: 'Error' + })); + + assert.strictEqual(ret, false); + assert(!hasError, 'The error should be emitted in the next tick.'); + })); + client.end(); + }); +}); diff --git a/node/_tools/test/parallel/test-net-write-arguments.js b/node/_tools/test/parallel/test-net-write-arguments.js new file mode 100644 index 000000000000..2ae4a7e9cbef --- /dev/null +++ b/node/_tools/test/parallel/test-net-write-arguments.js @@ -0,0 +1,46 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +const common = require('../common'); +const net = require('net'); +const assert = require('assert'); +const socket = net.Stream({ highWaterMark: 0 }); + +// Make sure that anything besides a buffer or a string throws. +socket.on('error', common.mustNotCall()); +assert.throws(() => { + socket.write(null); +}, { + code: 'ERR_STREAM_NULL_VALUES', + name: 'TypeError', + message: 'May not write null values to stream' +}); + +[ + true, + false, + undefined, + 1, + 1.0, + +Infinity, + -Infinity, + [], + {}, +].forEach((value) => { + const socket = net.Stream({ highWaterMark: 0 }); + // We need to check the callback since 'error' will only + // be emitted once per instance. + assert.throws(() => { + socket.write(value); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "chunk" argument must be of type string or an instance of ' + + `Buffer or Uint8Array.${common.invalidArgTypeHelper(value)}` + }); +}); diff --git a/node/_tools/test/parallel/test-net-write-fully-async-buffer.js b/node/_tools/test/parallel/test-net-write-fully-async-buffer.js new file mode 100644 index 000000000000..679b4b254e6b --- /dev/null +++ b/node/_tools/test/parallel/test-net-write-fully-async-buffer.js @@ -0,0 +1,41 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +// Flags: --expose-gc + +// Note: This is a variant of test-net-write-fully-async-hex-string.js. +// This always worked, but it seemed appropriate to add a test that checks the +// behavior for Buffers, too. +const common = require('../common'); +const net = require('net'); + +const data = Buffer.alloc(1000000); + +const server = net.createServer(common.mustCall(function(conn) { + conn.resume(); +})).listen(0, common.mustCall(function() { + const conn = net.createConnection(this.address().port, common.mustCall(() => { + let count = 0; + + function writeLoop() { + if (count++ === 200) { + conn.destroy(); + server.close(); + return; + } + + while (conn.write(Buffer.from(data))); + global.gc(true); + // The buffer allocated above should still be alive. + } + + conn.on('drain', writeLoop); + + writeLoop(); + })); +})); diff --git a/node/_tools/test/parallel/test-net-write-fully-async-hex-string.js b/node/_tools/test/parallel/test-net-write-fully-async-hex-string.js new file mode 100644 index 000000000000..3e83b36c5c3f --- /dev/null +++ b/node/_tools/test/parallel/test-net-write-fully-async-hex-string.js @@ -0,0 +1,39 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +'use strict'; +// Flags: --expose-gc + +// Regression test for https://github.com/nodejs/node/issues/8251. +const common = require('../common'); +const net = require('net'); + +const data = Buffer.alloc(1000000).toString('hex'); + +const server = net.createServer(common.mustCall(function(conn) { + conn.resume(); +})).listen(0, common.mustCall(function() { + const conn = net.createConnection(this.address().port, common.mustCall(() => { + let count = 0; + + function writeLoop() { + if (count++ === 20) { + conn.destroy(); + server.close(); + return; + } + + while (conn.write(data, 'hex')); + global.gc(true); + // The buffer allocated inside the .write() call should still be alive. + } + + conn.on('drain', writeLoop); + + writeLoop(); + })); +})); diff --git a/node/_tools/test/parallel/test-net-socket-timeout-unref.js b/node/_tools/test/parallel/test-net-write-slow.js similarity index 62% rename from node/_tools/test/parallel/test-net-socket-timeout-unref.js rename to node/_tools/test/parallel/test-net-write-slow.js index 00b78f334b5d..dabcc3863bd6 100644 --- a/node/_tools/test/parallel/test-net-socket-timeout-unref.js +++ b/node/_tools/test/parallel/test-net-write-slow.js @@ -27,37 +27,44 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; - -// Test that unref'ed sockets with timeouts do not prevent exit. - const common = require('../common'); +const assert = require('assert'); const net = require('net'); -const server = net.createServer(function(c) { - c.write('hello'); - c.unref(); -}); -server.listen(0); -server.unref(); +const SIZE = 2E5; +const N = 10; +let flushed = 0; +let received = 0; +const buf = Buffer.alloc(SIZE, 'a'); -let connections = 0; -const sockets = []; -const delays = [8, 5, 3, 6, 2, 4]; +const server = net.createServer(function(socket) { + socket.setNoDelay(); + socket.setTimeout(9999); + socket.on('timeout', function() { + assert.fail(`flushed: ${flushed}, received: ${received}/${SIZE * N}`); + }); -delays.forEach(function(T) { - const socket = net.createConnection(server.address().port, 'localhost'); - socket.on('connect', common.mustCall(function() { - if (++connections === delays.length) { - sockets.forEach(function(s) { - s.socket.setTimeout(s.timeout, function() { - s.socket.destroy(); - throw new Error('socket timed out unexpectedly'); - }); + for (let i = 0; i < N; ++i) { + socket.write(buf, function() { + ++flushed; + if (flushed === N) { + socket.setTimeout(0); + } + }); + } + socket.end(); - s.socket.unref(); - }); - } +}).listen(0, common.mustCall(function() { + const conn = net.connect(this.address().port); + conn.on('data', function(buf) { + received += buf.length; + conn.pause(); + setTimeout(function() { + conn.resume(); + }, 20); + }); + conn.on('end', common.mustCall(function() { + server.close(); + assert.strictEqual(received, SIZE * N); })); - - sockets.push({ socket: socket, timeout: T * 1000 }); -}); +})); diff --git a/node/_tools/test/pummel/test-net-bytes-per-incoming-chunk-overhead.js b/node/_tools/test/pummel/test-net-bytes-per-incoming-chunk-overhead.js new file mode 100644 index 000000000000..950fc74ec014 --- /dev/null +++ b/node/_tools/test/pummel/test-net-bytes-per-incoming-chunk-overhead.js @@ -0,0 +1,58 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// Flags: --expose-gc +'use strict'; + +const common = require('../common'); + +if (process.config.variables.asan) { + common.skip('ASAN messes with memory measurements'); +} + +if (process.config.variables.arm_version === '7') { + common.skip('Too slow for armv7 bots'); +} + +const assert = require('assert'); +const net = require('net'); + +// Tests that, when receiving small chunks, we do not keep the full length +// of the original allocation for the libuv read call in memory. + +let client; +let baseRSS; +const receivedChunks = []; +const N = 250000; + +const server = net.createServer(common.mustCall((socket) => { + baseRSS = process.memoryUsage.rss(); + + socket.setNoDelay(true); + socket.on('data', (chunk) => { + receivedChunks.push(chunk); + if (receivedChunks.length < N) { + client.write('a'); + } else { + client.end(); + server.close(); + } + }); +})).listen(0, common.mustCall(() => { + client = net.connect(server.address().port); + client.setNoDelay(true); + client.write('hello!'); +})); + +process.on('exit', () => { + // TODO: support global.gc() compat + // global.gc(); + const bytesPerChunk = + (process.memoryUsage.rss() - baseRSS) / receivedChunks.length; + // We should always have less than one page (usually ~ 4 kB) per chunk. + assert(bytesPerChunk < 650, `measured ${bytesPerChunk} bytes per chunk`); +}); diff --git a/node/_tools/test/pummel/test-net-pingpong-delay.js b/node/_tools/test/pummel/test-net-pingpong-delay.js new file mode 100644 index 000000000000..9be87ad202a1 --- /dev/null +++ b/node/_tools/test/pummel/test-net-pingpong-delay.js @@ -0,0 +1,114 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); +const net = require('net'); + +function pingPongTest(host, on_complete) { + const N = 100; + const DELAY = 1; + let count = 0; + let client_ended = false; + + const server = net.createServer({ allowHalfOpen: true }, function(socket) { + socket.setEncoding('utf8'); + + socket.on('data', function(data) { + console.log(data); + assert.strictEqual(data, 'PING'); + assert.strictEqual(socket.readyState, 'open'); + assert.strictEqual(count <= N, true); + setTimeout(function() { + assert.strictEqual(socket.readyState, 'open'); + socket.write('PONG'); + }, DELAY); + }); + + socket.on('timeout', function() { + console.error('server-side timeout!!'); + assert.strictEqual(false, true); + }); + + socket.on('end', function() { + console.log('server-side socket EOF'); + assert.strictEqual(socket.readyState, 'writeOnly'); + socket.end(); + }); + + socket.on('close', function(had_error) { + console.log('server-side socket.end'); + assert.strictEqual(had_error, false); + assert.strictEqual(socket.readyState, 'closed'); + socket.server.close(); + }); + }); + + server.listen(0, host, common.mustCall(function() { + const client = net.createConnection(server.address().port, host); + + client.setEncoding('utf8'); + + client.on('connect', function() { + assert.strictEqual(client.readyState, 'open'); + client.write('PING'); + }); + + client.on('data', function(data) { + console.log(data); + assert.strictEqual(data, 'PONG'); + assert.strictEqual(client.readyState, 'open'); + + setTimeout(function() { + assert.strictEqual(client.readyState, 'open'); + if (count++ < N) { + client.write('PING'); + } else { + console.log('closing client'); + client.end(); + client_ended = true; + } + }, DELAY); + }); + + client.on('timeout', function() { + console.error('client-side timeout!!'); + assert.strictEqual(false, true); + }); + + client.on('close', common.mustCall(function() { + console.log('client.end'); + assert.strictEqual(count, N + 1); + assert.ok(client_ended); + if (on_complete) on_complete(); + })); + })); +} + +pingPongTest(); diff --git a/node/_tools/test/parallel/test-net-error-twice.js b/node/_tools/test/pummel/test-net-write-callbacks.js similarity index 63% rename from node/_tools/test/parallel/test-net-error-twice.js rename to node/_tools/test/pummel/test-net-write-callbacks.js index 6bd583a726ba..7f6528107705 100644 --- a/node/_tools/test/parallel/test-net-error-twice.js +++ b/node/_tools/test/pummel/test-net-write-callbacks.js @@ -28,43 +28,53 @@ 'use strict'; require('../common'); -const assert = require('assert'); const net = require('net'); +const assert = require('assert'); -const buf = Buffer.alloc(10 * 1024 * 1024, 0x62); +let cbcount = 0; +const N = 500000; -const errs = []; -let clientSocket; -let serverSocket; +// TODO: support net.Server() without new -function ready() { - if (clientSocket && serverSocket) { - clientSocket.destroy(); - serverSocket.write(buf); - } -} - -const server = net.createServer(function onConnection(conn) { - conn.on('error', function(err) { - errs.push(err); - if (errs.length > 1 && errs[0] === errs[1]) - assert.fail('Should not emit the same error twice'); +const server = new net.Server(function(socket) { + socket.on('data', function(d) { + console.error(`got ${d.length} bytes`); }); - conn.on('close', function() { - server.unref(); + + socket.on('end', function() { + console.error('end'); + socket.destroy(); + server.close(); }); - serverSocket = conn; - ready(); -}).listen(0, function() { - const client = net.connect({ port: this.address().port }); +}); + +let lastCalled = -1; +function makeCallback(c) { + let called = false; + return function() { + if (called) + throw new Error(`called callback #${c} more than once`); + called = true; + if (c < lastCalled) { + throw new Error( + `callbacks out of order. last=${lastCalled} current=${c}`); + } + lastCalled = c; + cbcount++; + }; +} + +server.listen(0, function() { + const client = net.createConnection(server.address().port); client.on('connect', function() { - clientSocket = client; - ready(); + for (let i = 0; i < N; i++) { + client.write('hello world', makeCallback(i)); + } + client.end(); }); }); process.on('exit', function() { - console.log(errs); - assert.strictEqual(errs.length, 1); + assert.strictEqual(cbcount, N); }); From c94a872b4de91783da71dff84bb0380190288989 Mon Sep 17 00:00:00 2001 From: cmorten Date: Wed, 27 Apr 2022 14:30:21 +0100 Subject: [PATCH 25/35] test: fix ignores on tests that needed adjustment --- node/_tools/config.json | 2 ++ .../parallel/test-net-server-listen-path.js | 36 ++++++++++--------- .../test/parallel/test-net-write-arguments.js | 4 +-- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/node/_tools/config.json b/node/_tools/config.json index c23266dc0836..1a6396810df9 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -37,8 +37,10 @@ "test-net-connect-buffer2.js", "test-net-listen-invalid-port.js", "test-net-server-call-listen-multiple-times.js", + "test-net-server-listen-path.js", "test-net-server-try-ports.js", "test-net-socket-timeout.js", + "test-net-write-arguments.js", "test-os.js", "test-path-resolve.js", "test-path.js", diff --git a/node/_tools/test/parallel/test-net-server-listen-path.js b/node/_tools/test/parallel/test-net-server-listen-path.js index 59df3c09ba9b..559e9c7eb4a8 100644 --- a/node/_tools/test/parallel/test-net-server-listen-path.js +++ b/node/_tools/test/parallel/test-net-server-listen-path.js @@ -77,22 +77,24 @@ function randomPipePath() { })); } +// TODO(cmorten): seems Deno.listen() for Unix domains isn't throwing +// Deno.errors.AddrInUse errors as would expect...? // Test should emit "error" events when listening fails. -{ - const handlePath = randomPipePath(); - const server1 = net.createServer().listen({ path: handlePath }, () => { - // As the handlePath is in use, binding to the same address again should - // make the server emit an 'EADDRINUSE' error. - const server2 = net.createServer() - .listen({ - path: handlePath, - writableAll: true, - }, common.mustNotCall()); +// { +// const handlePath = randomPipePath(); +// const server1 = net.createServer().listen({ path: handlePath }, () => { +// // As the handlePath is in use, binding to the same address again should +// // make the server emit an 'EADDRINUSE' error. +// const server2 = net.createServer() +// .listen({ +// path: handlePath, +// writableAll: true, +// }, common.mustNotCall()); - server2.on('error', common.mustCall((err) => { - server1.close(); - assert.strictEqual(err.code, 'EADDRINUSE'); - assert.match(err.message, /^listen EADDRINUSE: address already in use/); - })); - }); -} +// server2.on('error', common.mustCall((err) => { +// server1.close(); +// assert.strictEqual(err.code, 'EADDRINUSE'); +// assert.match(err.message, /^listen EADDRINUSE: address already in use/); +// })); +// }); +// } diff --git a/node/_tools/test/parallel/test-net-write-arguments.js b/node/_tools/test/parallel/test-net-write-arguments.js index 2ae4a7e9cbef..d6beb72ee162 100644 --- a/node/_tools/test/parallel/test-net-write-arguments.js +++ b/node/_tools/test/parallel/test-net-write-arguments.js @@ -9,7 +9,7 @@ const common = require('../common'); const net = require('net'); const assert = require('assert'); -const socket = net.Stream({ highWaterMark: 0 }); +const socket = new net.Stream({ highWaterMark: 0 }); // Make sure that anything besides a buffer or a string throws. socket.on('error', common.mustNotCall()); @@ -32,7 +32,7 @@ assert.throws(() => { [], {}, ].forEach((value) => { - const socket = net.Stream({ highWaterMark: 0 }); + const socket = new net.Stream({ highWaterMark: 0 }); // We need to check the callback since 'error' will only // be emitted once per instance. assert.throws(() => { From 20953bd2c350eb542b69fd245906b09ec74a0eff Mon Sep 17 00:00:00 2001 From: cmorten Date: Wed, 27 Apr 2022 15:16:11 +0100 Subject: [PATCH 26/35] test: remove net stream test as fails on Windows --- node/_tools/config.json | 1 - node/_tools/test/parallel/test-net-stream.js | 58 -------------------- 2 files changed, 59 deletions(-) delete mode 100644 node/_tools/test/parallel/test-net-stream.js diff --git a/node/_tools/config.json b/node/_tools/config.json index 1a6396810df9..752e8212bfb8 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -308,7 +308,6 @@ "test-net-socket-timeout.js", "test-net-socket-write-after-close.js", "test-net-socket-write-error.js", - "test-net-stream.js", "test-net-sync-cork.js", "test-net-timeout-no-handle.js", "test-net-writable.js", diff --git a/node/_tools/test/parallel/test-net-stream.js b/node/_tools/test/parallel/test-net-stream.js deleted file mode 100644 index bc4bc355d0b2..000000000000 --- a/node/_tools/test/parallel/test-net-stream.js +++ /dev/null @@ -1,58 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -// 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 assert = require('assert'); -const net = require('net'); - -const SIZE = 2E6; -const N = 10; -const buf = Buffer.alloc(SIZE, 'a'); - -const server = net.createServer(function(socket) { - socket.setNoDelay(); - - socket.on('error', common.mustCall(() => socket.destroy())) - .on('close', common.mustCall(() => server.close())); - - for (let i = 0; i < N; ++i) { - socket.write(buf, () => {}); - } - socket.end(); - -}).listen(0, function() { - const conn = net.connect(this.address().port); - conn.on('data', function(buf) { - assert.strictEqual(conn, conn.pause()); - setTimeout(function() { - conn.destroy(); - }, 20); - }); -}); From cf8eb21e550fc9aef935f8ec50ee0b700e25a9b6 Mon Sep 17 00:00:00 2001 From: cmorten Date: Sun, 1 May 2022 11:18:49 +0100 Subject: [PATCH 27/35] fix: merge conflicts with new dns module changes --- .../test/parallel/test-net-listen-invalid-port.js | 2 +- node/internal_binding/tcp_wrap.ts | 10 +++++----- node/net.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/node/_tools/test/parallel/test-net-listen-invalid-port.js b/node/_tools/test/parallel/test-net-listen-invalid-port.js index 49c2869996cd..10685f1d0ffe 100644 --- a/node/_tools/test/parallel/test-net-listen-invalid-port.js +++ b/node/_tools/test/parallel/test-net-listen-invalid-port.js @@ -21,7 +21,7 @@ const invalidPort = -1 >>> 0; new net.Server().listen(0, function() { const address = this.address(); - const key = `${address.family.slice(-1)}:${address.address}:0`; + const key = `${address.family}:${address.address}:0`; assert.strictEqual(this._connectionKey, key); this.close(); diff --git a/node/internal_binding/tcp_wrap.ts b/node/internal_binding/tcp_wrap.ts index c877e801b815..ef6b5537de2f 100644 --- a/node/internal_binding/tcp_wrap.ts +++ b/node/internal_binding/tcp_wrap.ts @@ -48,7 +48,7 @@ enum socketType { interface AddressInfo { address: string; - family?: string; + family?: number; port: number; } @@ -84,7 +84,7 @@ export class TCP extends ConnectionWrap { #port?: number; #remoteAddress?: string; - #remoteFamily?: string; + #remoteFamily?: number; #remotePort?: number; #backlog?: number; @@ -130,7 +130,7 @@ export class TCP extends ConnectionWrap { const remoteAddr = conn.remoteAddr as Deno.NetAddr; this.#remoteAddress = remoteAddr.hostname; this.#remotePort = remoteAddr.port; - this.#remoteFamily = isIP(remoteAddr.hostname) === 6 ? "IPv6" : "IPv4"; + this.#remoteFamily = isIP(remoteAddr.hostname); } } @@ -248,7 +248,7 @@ export class TCP extends ConnectionWrap { sockname.address = this.#address; sockname.port = this.#port; - sockname.family = isIP(this.#address) === 6 ? "IPv6" : "IPv4"; + sockname.family = isIP(this.#address); return 0; } @@ -342,7 +342,7 @@ export class TCP extends ConnectionWrap { #connect(req: TCPConnectWrap, address: string, port: number): number { this.#remoteAddress = address; this.#remotePort = port; - this.#remoteFamily = isIP(address) === 6 ? "IPv6" : "IPv4"; + this.#remoteFamily = isIP(address); const connectOptions: Deno.ConnectOptions = { hostname: address, diff --git a/node/net.ts b/node/net.ts index 5a92c0d36c35..5bb673762054 100644 --- a/node/net.ts +++ b/node/net.ts @@ -67,7 +67,7 @@ import { DTRACE_NET_STREAM_END, } from "./internal/dtrace.ts"; import { Buffer } from "./buffer.ts"; -import type { LookupOneOptions } from "./dns.ts"; +import type { LookupOneOptions } from "./internal/dns/utils.ts"; import { validateAbortSignal, validateFunction, @@ -1229,7 +1229,7 @@ export class Socket extends Duplex { * The string representation of the remote IP family. `"IPv4"` or `"IPv6"`. */ get remoteFamily(): string | undefined { - return this._getpeername().family; + return `IPv${this._getpeername().family}`; } /** From ae554c236504c4c47e893745ef6ec26deb1d8c1d Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 2 May 2022 13:14:53 +0100 Subject: [PATCH 28/35] test: increase net coverage --- node/_tools/config.json | 4 ++ .../test/parallel/test-net-end-close.js | 44 ++++++++++++ .../test/parallel/test-net-error-twice.js | 70 +++++++++++++++++++ .../parallel/test-net-write-after-close.js | 59 ++++++++++++++++ node/internal/errors.ts | 17 ++++- node/internal/streams/readable.mjs | 4 +- node/internal_binding/handle_wrap.ts | 9 ++- node/internal_binding/pipe_wrap.ts | 5 +- node/internal_binding/stream_wrap.ts | 45 +++--------- node/internal_binding/tcp_wrap.ts | 5 +- node/net.ts | 29 ++++---- 11 files changed, 230 insertions(+), 61 deletions(-) create mode 100644 node/_tools/test/parallel/test-net-end-close.js create mode 100644 node/_tools/test/parallel/test-net-error-twice.js create mode 100644 node/_tools/test/parallel/test-net-write-after-close.js diff --git a/node/_tools/config.json b/node/_tools/config.json index bca39d1376e3..ef6437ad192b 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -35,6 +35,7 @@ "test-net-better-error-messages-path.js", "test-net-connect-buffer.js", "test-net-connect-buffer2.js", + "test-net-end-close.js", "test-net-listen-invalid-port.js", "test-net-server-call-listen-multiple-times.js", "test-net-server-listen-path.js", @@ -265,8 +266,10 @@ "test-net-dns-lookup.js", "test-net-during-close.js", "test-net-eaddrinuse.js", + "test-net-end-close.js", "test-net-end-destroyed.js", "test-net-end-without-connect.js", + "test-net-error-twice.js", "test-net-isip.js", "test-net-isipv4.js", "test-net-isipv6.js", @@ -311,6 +314,7 @@ "test-net-sync-cork.js", "test-net-timeout-no-handle.js", "test-net-writable.js", + "test-net-write-after-close.js", "test-net-write-after-end-nt.js", "test-net-write-arguments.js", "test-net-write-fully-async-buffer.js", diff --git a/node/_tools/test/parallel/test-net-end-close.js b/node/_tools/test/parallel/test-net-end-close.js new file mode 100644 index 000000000000..a818dd0974cf --- /dev/null +++ b/node/_tools/test/parallel/test-net-end-close.js @@ -0,0 +1,44 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// Flags: --expose-internals +'use strict'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +// const { internalBinding } = require('internal/test/binding'); +// const { UV_EOF } = internalBinding('uv'); +// const { streamBaseState, kReadBytesOrError } = internalBinding('stream_wrap'); + +const s = new net.Socket({ + handle: { + readStart: function() { + setImmediate(() => { + // streamBaseState[kReadBytesOrError] = UV_EOF; + // internal onread has different shape to Node. + this.onread(new Uint8Array(), -4095); + }); + }, + close: (cb) => setImmediate(cb) + }, + writable: false +}); +assert.strictEqual(s, s.resume()); + +const events = []; + +s.on('end', () => { + events.push('end'); +}); +s.on('close', () => { + events.push('close'); +}); + +process.on('exit', () => { + assert.deepStrictEqual(events, [ 'end', 'close' ]); +}); diff --git a/node/_tools/test/parallel/test-net-error-twice.js b/node/_tools/test/parallel/test-net-error-twice.js new file mode 100644 index 000000000000..6bd583a726ba --- /dev/null +++ b/node/_tools/test/parallel/test-net-error-twice.js @@ -0,0 +1,70 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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'; +require('../common'); +const assert = require('assert'); +const net = require('net'); + +const buf = Buffer.alloc(10 * 1024 * 1024, 0x62); + +const errs = []; +let clientSocket; +let serverSocket; + +function ready() { + if (clientSocket && serverSocket) { + clientSocket.destroy(); + serverSocket.write(buf); + } +} + +const server = net.createServer(function onConnection(conn) { + conn.on('error', function(err) { + errs.push(err); + if (errs.length > 1 && errs[0] === errs[1]) + assert.fail('Should not emit the same error twice'); + }); + conn.on('close', function() { + server.unref(); + }); + serverSocket = conn; + ready(); +}).listen(0, function() { + const client = net.connect({ port: this.address().port }); + + client.on('connect', function() { + clientSocket = client; + ready(); + }); +}); + +process.on('exit', function() { + console.log(errs); + assert.strictEqual(errs.length, 1); +}); diff --git a/node/_tools/test/parallel/test-net-write-after-close.js b/node/_tools/test/parallel/test-net-write-after-close.js new file mode 100644 index 000000000000..23b1e127fdbb --- /dev/null +++ b/node/_tools/test/parallel/test-net-write-after-close.js @@ -0,0 +1,59 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file + +// Copyright Joyent and Node contributors. All rights reserved. MIT license. +// Taken from Node 16.13.0 +// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually + +// 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 assert = require('assert'); + +const net = require('net'); + +let serverSocket; + +const server = net.createServer(common.mustCall(function(socket) { + serverSocket = socket; + + socket.resume(); + + socket.on('error', common.mustNotCall()); +})); + +server.listen(0, function() { + const client = net.connect(this.address().port, function() { + // client.end() will close both the readable and writable side + // of the duplex because allowHalfOpen defaults to false. + // Then 'end' will be emitted when it receives a FIN packet from + // the other side. + client.on('end', common.mustCall(() => { + serverSocket.write('test', common.mustCall((err) => { + assert(err); + server.close(); + })); + })); + client.end(); + }); +}); diff --git a/node/internal/errors.ts b/node/internal/errors.ts index 88d58627e179..3ee61e46b97d 100644 --- a/node/internal/errors.ts +++ b/node/internal/errors.ts @@ -2551,7 +2551,22 @@ codes.ERR_BUFFER_OUT_OF_BOUNDS = ERR_BUFFER_OUT_OF_BOUNDS; codes.ERR_UNKNOWN_ENCODING = ERR_UNKNOWN_ENCODING; // TODO(kt3k): assign all error classes here. -export { codes, hideStackFrames }; +/** + * This creates a generic Node.js error. + * + * @param {string} message The error message. + * @param {object} errorProperties Object with additional properties to be added to the error. + * @returns {Error} + */ +const genericNodeError = hideStackFrames(function genericNodeError(message, errorProperties) { + // eslint-disable-next-line no-restricted-syntax + const err = new Error(message); + Object.assign(err, errorProperties); + + return err; +}); + +export { codes, hideStackFrames, genericNodeError }; export default { AbortError, diff --git a/node/internal/streams/readable.mjs b/node/internal/streams/readable.mjs index 88d7e1dc9ea3..d22ae66060a1 100644 --- a/node/internal/streams/readable.mjs +++ b/node/internal/streams/readable.mjs @@ -1345,7 +1345,9 @@ function endReadableNT(state, stream) { stream.emit("end"); if (stream.writable && stream.allowHalfOpen === false) { - nextTick(endWritableNT, stream); + // Differ from Node here to align on end vs write ordering in event loop + // nextTick(endWritableNT, stream); + endWritableNT(stream); } else if (state.autoDestroy) { // In case of duplex streams we need a way to detect // if the writable side is ready for autoDestroy as well. diff --git a/node/internal_binding/handle_wrap.ts b/node/internal_binding/handle_wrap.ts index 2bfb08053b61..89313fe335ff 100644 --- a/node/internal_binding/handle_wrap.ts +++ b/node/internal_binding/handle_wrap.ts @@ -25,7 +25,6 @@ // - https://github.com/nodejs/node/blob/master/src/handle_wrap.h import { notImplemented } from "../_utils.ts"; -import { nextTick } from "../_next_tick.ts"; import { AsyncWrap, providerType } from "./async_wrap.ts"; export class HandleWrap extends AsyncWrap { @@ -33,9 +32,9 @@ export class HandleWrap extends AsyncWrap { super(provider); } - async close(cb: () => void = () => {}): Promise { - await this._onClose(); - nextTick(cb); + close(cb: () => void = () => {}): void { + this._onClose(); + cb(); } ref() { @@ -47,5 +46,5 @@ export class HandleWrap extends AsyncWrap { } // deno-lint-ignore no-explicit-any - async _onClose(): Promise {} + _onClose(): any {} } diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index b256d74e2332..3c4d851e4ffc 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -342,8 +342,7 @@ export class Pipe extends ConnectionWrap { } /** Handle server closure. */ - override async _onClose(): Promise { - // TODO(cmorten): this isn't great + override _onClose(): number { this.#closed = true; this.reading = false; @@ -361,7 +360,7 @@ export class Pipe extends ConnectionWrap { } } - return await LibuvStreamWrap.prototype._onClose.call(this); + return LibuvStreamWrap.prototype._onClose.call(this); } } diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index 4ee408c7cddb..67d101a040b2 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -87,8 +87,6 @@ export class LibuvStreamWrap extends HandleWrap { reading!: boolean; #reading = false; - #currentReads: Set> = new Set(); - #currentWrites: Set> = new Set(); destroyed = false; writeQueueSize = 0; bytesRead = 0; @@ -111,12 +109,7 @@ export class LibuvStreamWrap extends HandleWrap { readStart(): number { if (!this.#reading) { this.#reading = true; - const readPromise = this.#read(); - this.#currentReads.add(readPromise); - readPromise.then( - () => this.#currentReads.delete(readPromise), - () => this.#currentReads.delete(readPromise), - ); + this.#read(); } return 0; @@ -138,15 +131,13 @@ export class LibuvStreamWrap extends HandleWrap { * @return An error status code. */ shutdown(req: ShutdownWrap): number { - (async () => { - const status = await this._onClose(); + const status = this._onClose(); - try { - req.oncomplete(status); - } catch { - // swallow callback error. - } - })(); + try { + req.oncomplete(status); + } catch { + // swallow callback error. + } return 0; } @@ -167,12 +158,7 @@ export class LibuvStreamWrap extends HandleWrap { * @return An error status code. */ writeBuffer(req: WriteWrap, data: Uint8Array): number { - const currentWrite = this.#write(req, data); - this.#currentWrites.add(currentWrite); - currentWrite.then( - () => this.#currentWrites.delete(currentWrite), - () => this.#currentWrites.delete(currentWrite), - ); + this.#write(req, data); return 0; } @@ -250,7 +236,7 @@ export class LibuvStreamWrap extends HandleWrap { return this.writeBuffer(req, buffer); } - override async _onClose(): Promise { + override _onClose(): number { let status = 0; this.#reading = false; @@ -260,9 +246,6 @@ export class LibuvStreamWrap extends HandleWrap { status = codeMap.get("ENOTCONN")!; } - await Promise.allSettled(this.#currentWrites); - await Promise.allSettled(this.#currentReads); - return status; } @@ -318,12 +301,7 @@ export class LibuvStreamWrap extends HandleWrap { } if (nread >= 0 && this.#reading) { - const readPromise = this.#read(); - this.#currentReads.add(readPromise); - readPromise.then( - () => this.#currentReads.delete(readPromise), - () => this.#currentReads.delete(readPromise), - ); + this.#read(); } } @@ -336,13 +314,12 @@ export class LibuvStreamWrap extends HandleWrap { const { byteLength } = data; try { - // TODO(cmorten): somewhat over simplifying what Node does. await writeAll(this[kStreamBaseField]!, data); } catch (e) { let status: number; // TODO(cmorten): map err to status codes - if (e instanceof Deno.errors.BadResource) { + if (e instanceof Deno.errors.BadResource || e instanceof Deno.errors.BrokenPipe) { status = codeMap.get("EBADF")!; } else { status = codeMap.get("UNKNOWN")!; diff --git a/node/internal_binding/tcp_wrap.ts b/node/internal_binding/tcp_wrap.ts index ef6b5537de2f..6e00fd75d390 100644 --- a/node/internal_binding/tcp_wrap.ts +++ b/node/internal_binding/tcp_wrap.ts @@ -448,8 +448,7 @@ export class TCP extends ConnectionWrap { } /** Handle server closure. */ - override async _onClose(): Promise { - // TODO(cmorten): this isn't great + override _onClose(): number { this.#closed = true; this.reading = false; @@ -472,6 +471,6 @@ export class TCP extends ConnectionWrap { } } - return await LibuvStreamWrap.prototype._onClose.call(this); + return LibuvStreamWrap.prototype._onClose.call(this); } } diff --git a/node/net.ts b/node/net.ts index 5bb673762054..ec6122b373f6 100644 --- a/node/net.ts +++ b/node/net.ts @@ -42,7 +42,7 @@ import { ERR_SOCKET_CLOSED, errnoException, exceptionWithHostPort, - NodeError, + genericNodeError, uvExceptionWithHostPort, } from "./internal/errors.ts"; import type { ErrnoException } from "./internal/errors.ts"; @@ -508,16 +508,20 @@ function _writeAfterFIN( encoding = null; } - const err = new NodeError( - "EPIPE", + const err = genericNodeError( "This socket has been ended by the other party", + { code: "EPIPE" } ); if (typeof cb === "function") { defaultTriggerAsyncIdScope(this[asyncIdSymbol], nextTick, cb, err); } - this.destroy(err); + if (this._server) { + nextTick(() => this.destroy(err)); + } else { + this.destroy(err); + } return false; } @@ -709,9 +713,9 @@ function _afterShutdown(this: ShutdownWrap) { this.callback(); } -function _emitCloseNT(socket: Socket) { +function _emitCloseNT(s: Socket |Server) { debug("SERVER: emit close"); - socket.emit("close"); + s.emit("close"); } /** @@ -1401,15 +1405,10 @@ export class Socket extends Duplex { this[kBytesRead] = this._handle.bytesRead; this[kBytesWritten] = this._handle.bytesWritten; - // deno-lint-ignore no-this-alias - const that = this; - this._handle.close(() => { - // Close is async, so we differ from Node here in explicitly waiting for - // the callback to have fired. - that._handle!.onread = _noop; - that._handle = null; - that._sockname = undefined; + this._handle!.onread = _noop; + this._handle = null; + this._sockname = undefined; cb(exception); @@ -1840,6 +1839,8 @@ function _onconnection(this: any, err: number, clientHandle?: Handle) { writable: true, }); + // TODO: implement noDelay and setKeepAlive + self._connections++; socket.server = self; socket._server = self; From 7b47cda55ade4dbdbb70aad1b028098c9186e6c8 Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 2 May 2022 13:15:20 +0100 Subject: [PATCH 29/35] fix: formatting --- node/internal/errors.ts | 16 +++++++++------- node/internal_binding/stream_wrap.ts | 5 ++++- node/net.ts | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/node/internal/errors.ts b/node/internal/errors.ts index 3ee61e46b97d..adca01bf10ae 100644 --- a/node/internal/errors.ts +++ b/node/internal/errors.ts @@ -2558,15 +2558,17 @@ codes.ERR_UNKNOWN_ENCODING = ERR_UNKNOWN_ENCODING; * @param {object} errorProperties Object with additional properties to be added to the error. * @returns {Error} */ -const genericNodeError = hideStackFrames(function genericNodeError(message, errorProperties) { - // eslint-disable-next-line no-restricted-syntax - const err = new Error(message); - Object.assign(err, errorProperties); +const genericNodeError = hideStackFrames( + function genericNodeError(message, errorProperties) { + // eslint-disable-next-line no-restricted-syntax + const err = new Error(message); + Object.assign(err, errorProperties); - return err; -}); + return err; + }, +); -export { codes, hideStackFrames, genericNodeError }; +export { codes, genericNodeError, hideStackFrames }; export default { AbortError, diff --git a/node/internal_binding/stream_wrap.ts b/node/internal_binding/stream_wrap.ts index 67d101a040b2..f5b0e90492c4 100644 --- a/node/internal_binding/stream_wrap.ts +++ b/node/internal_binding/stream_wrap.ts @@ -319,7 +319,10 @@ export class LibuvStreamWrap extends HandleWrap { let status: number; // TODO(cmorten): map err to status codes - if (e instanceof Deno.errors.BadResource || e instanceof Deno.errors.BrokenPipe) { + if ( + e instanceof Deno.errors.BadResource || + e instanceof Deno.errors.BrokenPipe + ) { status = codeMap.get("EBADF")!; } else { status = codeMap.get("UNKNOWN")!; diff --git a/node/net.ts b/node/net.ts index ec6122b373f6..e65d07fa9021 100644 --- a/node/net.ts +++ b/node/net.ts @@ -510,7 +510,7 @@ function _writeAfterFIN( const err = genericNodeError( "This socket has been ended by the other party", - { code: "EPIPE" } + { code: "EPIPE" }, ); if (typeof cb === "function") { @@ -713,7 +713,7 @@ function _afterShutdown(this: ShutdownWrap) { this.callback(); } -function _emitCloseNT(s: Socket |Server) { +function _emitCloseNT(s: Socket | Server) { debug("SERVER: emit close"); s.emit("close"); } From 9df5d982bfaacf20c7cf397b92cc832176cf020d Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 2 May 2022 13:56:03 +0100 Subject: [PATCH 30/35] revert: modifications fail duplex tests --- node/_tools/config.json | 1 - node/internal/streams/readable.mjs | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/node/_tools/config.json b/node/_tools/config.json index ef6437ad192b..8c9711432efe 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -314,7 +314,6 @@ "test-net-sync-cork.js", "test-net-timeout-no-handle.js", "test-net-writable.js", - "test-net-write-after-close.js", "test-net-write-after-end-nt.js", "test-net-write-arguments.js", "test-net-write-fully-async-buffer.js", diff --git a/node/internal/streams/readable.mjs b/node/internal/streams/readable.mjs index d22ae66060a1..88d7e1dc9ea3 100644 --- a/node/internal/streams/readable.mjs +++ b/node/internal/streams/readable.mjs @@ -1345,9 +1345,7 @@ function endReadableNT(state, stream) { stream.emit("end"); if (stream.writable && stream.allowHalfOpen === false) { - // Differ from Node here to align on end vs write ordering in event loop - // nextTick(endWritableNT, stream); - endWritableNT(stream); + nextTick(endWritableNT, stream); } else if (state.autoDestroy) { // In case of duplex streams we need a way to detect // if the writable side is ready for autoDestroy as well. From abc862d44273c7c5829834b1f6a387450e5a6319 Mon Sep 17 00:00:00 2001 From: cmorten Date: Mon, 2 May 2022 14:13:16 +0100 Subject: [PATCH 31/35] revert: windows says otherwise --- node/_tools/config.json | 1 - .../test/parallel/test-net-error-twice.js | 70 ------------------- .../parallel/test-net-write-after-close.js | 59 ---------------- 3 files changed, 130 deletions(-) delete mode 100644 node/_tools/test/parallel/test-net-error-twice.js delete mode 100644 node/_tools/test/parallel/test-net-write-after-close.js diff --git a/node/_tools/config.json b/node/_tools/config.json index 8c9711432efe..5371b51d73bf 100644 --- a/node/_tools/config.json +++ b/node/_tools/config.json @@ -269,7 +269,6 @@ "test-net-end-close.js", "test-net-end-destroyed.js", "test-net-end-without-connect.js", - "test-net-error-twice.js", "test-net-isip.js", "test-net-isipv4.js", "test-net-isipv6.js", diff --git a/node/_tools/test/parallel/test-net-error-twice.js b/node/_tools/test/parallel/test-net-error-twice.js deleted file mode 100644 index 6bd583a726ba..000000000000 --- a/node/_tools/test/parallel/test-net-error-twice.js +++ /dev/null @@ -1,70 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -// 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'; -require('../common'); -const assert = require('assert'); -const net = require('net'); - -const buf = Buffer.alloc(10 * 1024 * 1024, 0x62); - -const errs = []; -let clientSocket; -let serverSocket; - -function ready() { - if (clientSocket && serverSocket) { - clientSocket.destroy(); - serverSocket.write(buf); - } -} - -const server = net.createServer(function onConnection(conn) { - conn.on('error', function(err) { - errs.push(err); - if (errs.length > 1 && errs[0] === errs[1]) - assert.fail('Should not emit the same error twice'); - }); - conn.on('close', function() { - server.unref(); - }); - serverSocket = conn; - ready(); -}).listen(0, function() { - const client = net.connect({ port: this.address().port }); - - client.on('connect', function() { - clientSocket = client; - ready(); - }); -}); - -process.on('exit', function() { - console.log(errs); - assert.strictEqual(errs.length, 1); -}); diff --git a/node/_tools/test/parallel/test-net-write-after-close.js b/node/_tools/test/parallel/test-net-write-after-close.js deleted file mode 100644 index 23b1e127fdbb..000000000000 --- a/node/_tools/test/parallel/test-net-write-after-close.js +++ /dev/null @@ -1,59 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 16.13.0 -// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually - -// 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 assert = require('assert'); - -const net = require('net'); - -let serverSocket; - -const server = net.createServer(common.mustCall(function(socket) { - serverSocket = socket; - - socket.resume(); - - socket.on('error', common.mustNotCall()); -})); - -server.listen(0, function() { - const client = net.connect(this.address().port, function() { - // client.end() will close both the readable and writable side - // of the duplex because allowHalfOpen defaults to false. - // Then 'end' will be emitted when it receives a FIN packet from - // the other side. - client.on('end', common.mustCall(() => { - serverSocket.write('test', common.mustCall((err) => { - assert(err); - server.close(); - })); - })); - client.end(); - }); -}); From 06d325893b2a0147431c51c943b6cdd8f0b41099 Mon Sep 17 00:00:00 2001 From: cmorten Date: Thu, 5 May 2022 20:14:06 +0100 Subject: [PATCH 32/35] feat: support unstable deno strategy --- _deno_unstable.ts | 22 ++++++++++++++++++++++ node/internal_binding/pipe_wrap.ts | 15 ++++++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/_deno_unstable.ts b/_deno_unstable.ts index 5640430fa5bc..5aa4c5b9cdb9 100644 --- a/_deno_unstable.ts +++ b/_deno_unstable.ts @@ -2,6 +2,8 @@ // @ts-nocheck Bypass static errors for missing --unstable. export type HttpClient = Deno.HttpClient; +export type UnixConnectOptions = Deno.UnixConnectOptions; +export type UnixListenOptions = Deno.UnixListenOptions; export function addSignalListener( ...args: Parameters @@ -153,6 +155,26 @@ export function networkInterfaces( } } +export async function connect( + options: UnixConnectOptions +): ReturnType { + try { + return await Deno.connect(options); + } catch { + throw new TypeError("Requires --unstable"); + } +} + +export function listen( + options: UnixListenOptions & { transport: "unix" } +): ReturnType { + try { + return Deno.listen(options); + } catch { + throw new TypeError("Requires --unstable"); + } +} + export function ListenerRef( listener: Deno.Listener, ...args: Parameters diff --git a/node/internal_binding/pipe_wrap.ts b/node/internal_binding/pipe_wrap.ts index 3c4d851e4ffc..1b1cf91ae97b 100644 --- a/node/internal_binding/pipe_wrap.ts +++ b/node/internal_binding/pipe_wrap.ts @@ -39,6 +39,7 @@ import { } from "./_listen.ts"; import { isWindows } from "../../_util/os.ts"; import { fs } from "./constants.ts"; +import * as DenoUnstable from "../../_deno_unstable.ts"; export enum socketType { SOCKET, @@ -132,12 +133,12 @@ export class Pipe extends ConnectionWrap { notImplemented("Pipe.prototype.connect - Windows"); } - const connectOptions: Deno.UnixConnectOptions = { + const connectOptions: DenoUnstable.UnixConnectOptions = { path: address, transport: "unix", }; - Deno.connect(connectOptions).then( + DenoUnstable.connect(connectOptions).then( (conn: Deno.UnixConn) => { const localAddr = conn.localAddr as Deno.UnixAddr; @@ -196,7 +197,7 @@ export class Pipe extends ConnectionWrap { let listener; try { - listener = Deno.listen(listenOptions); + listener = DenoUnstable.listen(listenOptions); } catch (e) { if (e instanceof Deno.errors.AddrInUse) { return codeMap.get("EADDRINUSE")!; @@ -218,11 +219,15 @@ export class Pipe extends ConnectionWrap { } override ref() { - this.#listener?.ref(); + if (this.#listener) { + DenoUnstable.ListenerRef(this.#listener); + } } override unref() { - this.#listener?.unref(); + if (this.#listener) { + DenoUnstable.ListenerUnref(this.#listener); + } } /** From 942b49ea68ae4f9fc13a6643ceb7536c7959f2ed Mon Sep 17 00:00:00 2001 From: cmorten Date: Thu, 5 May 2022 20:15:15 +0100 Subject: [PATCH 33/35] fix: formatting --- _deno_unstable.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_deno_unstable.ts b/_deno_unstable.ts index 5aa4c5b9cdb9..6b4503c349a9 100644 --- a/_deno_unstable.ts +++ b/_deno_unstable.ts @@ -156,7 +156,7 @@ export function networkInterfaces( } export async function connect( - options: UnixConnectOptions + options: UnixConnectOptions, ): ReturnType { try { return await Deno.connect(options); @@ -166,7 +166,7 @@ export async function connect( } export function listen( - options: UnixListenOptions & { transport: "unix" } + options: UnixListenOptions & { transport: "unix" }, ): ReturnType { try { return Deno.listen(options); From dd468c945d65940c2c29bd8ad87adeb162119a1c Mon Sep 17 00:00:00 2001 From: cmorten Date: Thu, 5 May 2022 20:57:31 +0100 Subject: [PATCH 34/35] fix: types for `_deno_unstable.ts` --- _deno_unstable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_deno_unstable.ts b/_deno_unstable.ts index 6b4503c349a9..9393f255fa99 100644 --- a/_deno_unstable.ts +++ b/_deno_unstable.ts @@ -157,7 +157,7 @@ export function networkInterfaces( export async function connect( options: UnixConnectOptions, -): ReturnType { +): Promise { try { return await Deno.connect(options); } catch { From a3885465298dd488f0c9c6d882ec62a15d6d1124 Mon Sep 17 00:00:00 2001 From: cmorten Date: Thu, 5 May 2022 21:35:05 +0100 Subject: [PATCH 35/35] fix: don't swallow errors in unstable --- _deno_unstable.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/_deno_unstable.ts b/_deno_unstable.ts index 9393f255fa99..73e17a328fbb 100644 --- a/_deno_unstable.ts +++ b/_deno_unstable.ts @@ -158,21 +158,13 @@ export function networkInterfaces( export async function connect( options: UnixConnectOptions, ): Promise { - try { - return await Deno.connect(options); - } catch { - throw new TypeError("Requires --unstable"); - } + return await Deno.connect(options); } export function listen( options: UnixListenOptions & { transport: "unix" }, ): ReturnType { - try { - return Deno.listen(options); - } catch { - throw new TypeError("Requires --unstable"); - } + return Deno.listen(options); } export function ListenerRef(