async_wrap: add provider types for net server

Adds `TCPSERVERWRAP` and `PIPESERVERWRAP` as provider types. This
makes it possible to distinguish servers from connections.

PR-URL: https://github.com/nodejs/node/pull/17157
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
Andreas Madsen 2017-11-20 17:18:40 +01:00 committed by Anna Henningsen
parent 91d131210c
commit b44efded84
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
32 changed files with 286 additions and 168 deletions

View File

@ -14,7 +14,7 @@ const bench = common.createBenchmark(main, {
dur: [5]
});
const TCP = process.binding('tcp_wrap').TCP;
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
const WriteWrap = process.binding('stream_wrap').WriteWrap;
const PORT = common.PORT;
@ -36,7 +36,7 @@ function fail(err, syscall) {
}
function server() {
const serverHandle = new TCP();
const serverHandle = new TCP(TCPConstants.SERVER);
var err = serverHandle.bind('127.0.0.1', PORT);
if (err)
fail(err, 'bind');
@ -92,7 +92,7 @@ function client() {
throw new Error(`invalid type: ${type}`);
}
const clientHandle = new TCP();
const clientHandle = new TCP(TCPConstants.SOCKET);
const connectReq = new TCPConnectWrap();
const err = clientHandle.connect(connectReq, '127.0.0.1', PORT);

View File

@ -14,7 +14,7 @@ const bench = common.createBenchmark(main, {
dur: [5]
});
const TCP = process.binding('tcp_wrap').TCP;
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
const WriteWrap = process.binding('stream_wrap').WriteWrap;
const PORT = common.PORT;
@ -35,7 +35,7 @@ function fail(err, syscall) {
}
function server() {
const serverHandle = new TCP();
const serverHandle = new TCP(TCPConstants.SERVER);
var err = serverHandle.bind('127.0.0.1', PORT);
if (err)
fail(err, 'bind');
@ -89,7 +89,7 @@ function client() {
throw new Error(`invalid type: ${type}`);
}
const clientHandle = new TCP();
const clientHandle = new TCP(TCPConstants.SOCKET);
const connectReq = new TCPConnectWrap();
const err = clientHandle.connect(connectReq, '127.0.0.1', PORT);
var bytes = 0;

View File

@ -14,7 +14,7 @@ const bench = common.createBenchmark(main, {
dur: [5]
});
const TCP = process.binding('tcp_wrap').TCP;
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
const WriteWrap = process.binding('stream_wrap').WriteWrap;
const PORT = common.PORT;
@ -35,7 +35,7 @@ function fail(err, syscall) {
}
function server() {
const serverHandle = new TCP();
const serverHandle = new TCP(TCPConstants.SERVER);
var err = serverHandle.bind('127.0.0.1', PORT);
if (err)
fail(err, 'bind');
@ -107,7 +107,7 @@ function server() {
}
function client() {
const clientHandle = new TCP();
const clientHandle = new TCP(TCPConstants.SOCKET);
const connectReq = new TCPConnectWrap();
const err = clientHandle.connect(connectReq, '127.0.0.1', PORT);

View File

@ -236,7 +236,7 @@ resource's constructor.
```text
FSEVENTWRAP, FSREQWRAP, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPPARSER,
JSSTREAM, PIPECONNECTWRAP, PIPEWRAP, PROCESSWRAP, QUERYWRAP, SHUTDOWNWRAP,
SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPWRAP, TIMERWRAP, TTYWRAP,
SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVER, TCPWRAP, TIMERWRAP, TTYWRAP,
UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST,
RANDOMBYTESREQUEST, TLSWRAP, Timeout, Immediate, TickObject
```
@ -275,13 +275,13 @@ require('net').createServer((conn) => {}).listen(8080);
Output when hitting the server with `nc localhost 8080`:
```console
TCPWRAP(2): trigger: 1 execution: 1
TCPSERVERWRAP(2): trigger: 1 execution: 1
TCPWRAP(4): trigger: 2 execution: 0
```
The first `TCPWRAP` is the server which receives the connections.
The `TCPSERVERWRAP` is the server which receives the connections.
The second `TCPWRAP` is the new connection from the client. When a new
The `TCPWRAP` is the new connection from the client. When a new
connection is made the `TCPWrap` instance is immediately constructed. This
happens outside of any JavaScript stack (side note: a `executionAsyncId()` of `0`
means it's being executed from C++, with no JavaScript stack above it).
@ -354,7 +354,7 @@ require('net').createServer(() => {}).listen(8080, () => {
Output from only starting the server:
```console
TCPWRAP(2): trigger: 1 execution: 1
TCPSERVERWRAP(2): trigger: 1 execution: 1
TickObject(3): trigger: 2 execution: 1
before: 3
Timeout(4): trigger: 3 execution: 3
@ -387,7 +387,7 @@ Only using `execution` to graph resource allocation results in the following:
TTYWRAP(6) -> Timeout(4) -> TIMERWRAP(5) -> TickObject(3) -> root(1)
```
The `TCPWRAP` is not part of this graph, even though it was the reason for
The `TCPSERVERWRAP` is not part of this graph, even though it was the reason for
`console.log()` being called. This is because binding to a port without a
hostname is a *synchronous* operation, but to maintain a completely asynchronous
API the user's callback is placed in a `process.nextTick()`.

View File

@ -34,8 +34,8 @@ const { Buffer } = require('buffer');
const debug = util.debuglog('tls');
const { Timer } = process.binding('timer_wrap');
const tls_wrap = process.binding('tls_wrap');
const { TCP } = process.binding('tcp_wrap');
const { Pipe } = process.binding('pipe_wrap');
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
const errors = require('internal/errors');
const kConnectOptions = Symbol('connect-options');
const kDisableRenegotiation = Symbol('disable-renegotiation');
@ -398,7 +398,9 @@ TLSSocket.prototype._wrapHandle = function(wrap) {
var options = this._tlsOptions;
if (!handle) {
handle = options.pipe ? new Pipe() : new TCP();
handle = options.pipe ?
new Pipe(PipeConstants.SOCKET) :
new TCP(TCPConstants.SOCKET);
handle.owner = this;
}

View File

@ -28,7 +28,7 @@ const { createPromise,
promiseResolve, promiseReject } = process.binding('util');
const debug = util.debuglog('child_process');
const { Buffer } = require('buffer');
const { Pipe } = process.binding('pipe_wrap');
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
const { errname } = process.binding('uv');
const child_process = require('internal/child_process');
const {
@ -103,7 +103,7 @@ exports.fork = function(modulePath /*, args, options*/) {
exports._forkChild = function(fd) {
// set process.send()
var p = new Pipe(true);
var p = new Pipe(PipeConstants.IPC);
p.open(fd);
p.unref();
const control = setupChannel(process, p);

View File

@ -10,7 +10,7 @@ const assert = require('assert');
const { Process } = process.binding('process_wrap');
const { WriteWrap } = process.binding('stream_wrap');
const { Pipe } = process.binding('pipe_wrap');
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
const { TTY } = process.binding('tty_wrap');
const { TCP } = process.binding('tcp_wrap');
const { UDP } = process.binding('udp_wrap');
@ -863,7 +863,7 @@ function _validateStdio(stdio, sync) {
};
if (!sync)
a.handle = new Pipe();
a.handle = new Pipe(PipeConstants.SOCKET);
acc.push(a);
} else if (stdio === 'ipc') {
@ -876,7 +876,7 @@ function _validateStdio(stdio, sync) {
throw new errors.Error('ERR_IPC_SYNC_FORK');
}
ipc = new Pipe(true);
ipc = new Pipe(PipeConstants.IPC);
ipcFd = i;
acc.push({

View File

@ -37,8 +37,8 @@ const {
const { Buffer } = require('buffer');
const TTYWrap = process.binding('tty_wrap');
const { TCP } = process.binding('tcp_wrap');
const { Pipe } = process.binding('pipe_wrap');
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
const { TCPConnectWrap } = process.binding('tcp_wrap');
const { PipeConnectWrap } = process.binding('pipe_wrap');
const { ShutdownWrap, WriteWrap } = process.binding('stream_wrap');
@ -57,10 +57,20 @@ const exceptionWithHostPort = util._exceptionWithHostPort;
function noop() {}
function createHandle(fd) {
function createHandle(fd, is_server) {
const type = TTYWrap.guessHandleType(fd);
if (type === 'PIPE') return new Pipe();
if (type === 'TCP') return new TCP();
if (type === 'PIPE') {
return new Pipe(
is_server ? PipeConstants.SERVER : PipeConstants.SOCKET
);
}
if (type === 'TCP') {
return new TCP(
is_server ? TCPConstants.SERVER : TCPConstants.SOCKET
);
}
throw new errors.TypeError('ERR_INVALID_FD_TYPE', type);
}
@ -200,7 +210,7 @@ function Socket(options) {
this._handle = options.handle; // private
this[async_id_symbol] = getNewAsyncId(this._handle);
} else if (options.fd !== undefined) {
this._handle = createHandle(options.fd);
this._handle = createHandle(options.fd, false);
this._handle.open(options.fd);
this[async_id_symbol] = this._handle.getAsyncId();
// options.fd can be string (since it is user-defined),
@ -1009,7 +1019,9 @@ Socket.prototype.connect = function(...args) {
debug('pipe', pipe, path);
if (!this._handle) {
this._handle = pipe ? new Pipe() : new TCP();
this._handle = pipe ?
new Pipe(PipeConstants.SOCKET) :
new TCP(TCPConstants.SOCKET);
initSocketHandle(this);
}
@ -1269,7 +1281,7 @@ function createServerHandle(address, port, addressType, fd) {
var isTCP = false;
if (typeof fd === 'number' && fd >= 0) {
try {
handle = createHandle(fd);
handle = createHandle(fd, true);
} catch (e) {
// Not a fd we can listen on. This will trigger an error.
debug('listen invalid fd=%d:', fd, e.message);
@ -1280,7 +1292,7 @@ function createServerHandle(address, port, addressType, fd) {
handle.writable = true;
assert(!address && !port);
} else if (port === -1 && addressType === -1) {
handle = new Pipe();
handle = new Pipe(PipeConstants.SERVER);
if (process.platform === 'win32') {
var instances = parseInt(process.env.NODE_PENDING_PIPE_INSTANCES);
if (!isNaN(instances)) {
@ -1288,7 +1300,7 @@ function createServerHandle(address, port, addressType, fd) {
}
}
} else {
handle = new TCP();
handle = new TCP(TCPConstants.SERVER);
isTCP = true;
}

View File

@ -46,6 +46,7 @@ namespace node {
V(HTTPPARSER) \
V(JSSTREAM) \
V(PIPECONNECTWRAP) \
V(PIPESERVERWRAP) \
V(PIPEWRAP) \
V(PROCESSWRAP) \
V(PROMISE) \
@ -54,6 +55,7 @@ namespace node {
V(SIGNALWRAP) \
V(STATWATCHER) \
V(TCPCONNECTWRAP) \
V(TCPSERVERWRAP) \
V(TCPWRAP) \
V(TIMERWRAP) \
V(TTYWRAP) \

View File

@ -51,7 +51,9 @@ void ConnectionWrap<WrapType, UVType>::OnConnection(uv_stream_t* handle,
if (status == 0) {
env->set_init_trigger_async_id(wrap_data->get_async_id());
// Instantiate the client javascript object and handle.
Local<Object> client_obj = WrapType::Instantiate(env, wrap_data);
Local<Object> client_obj = WrapType::Instantiate(env,
wrap_data,
WrapType::SOCKET);
// Unwrap the client javascript object.
WrapType* wrap;

View File

@ -40,6 +40,7 @@ using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Int32;
using v8::Local;
using v8::Object;
using v8::String;
@ -48,14 +49,17 @@ using v8::Value;
using AsyncHooks = Environment::AsyncHooks;
Local<Object> PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) {
Local<Object> PipeWrap::Instantiate(Environment* env,
AsyncWrap* parent,
PipeWrap::SocketType type) {
EscapableHandleScope handle_scope(env->isolate());
AsyncHooks::InitScope init_scope(env, parent->get_async_id());
CHECK_EQ(false, env->pipe_constructor_template().IsEmpty());
Local<Function> constructor = env->pipe_constructor_template()->GetFunction();
CHECK_EQ(false, constructor.IsEmpty());
Local<Value> type_value = Int32::New(env->isolate(), type);
Local<Object> instance =
constructor->NewInstance(env->context()).ToLocalChecked();
constructor->NewInstance(env->context(), 1, &type_value).ToLocalChecked();
return handle_scope.Escape(instance);
}
@ -107,6 +111,15 @@ void PipeWrap::Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap");
cwt->SetClassName(wrapString);
target->Set(wrapString, cwt->GetFunction());
// Define constants
Local<Object> constants = Object::New(env->isolate());
NODE_DEFINE_CONSTANT(constants, SOCKET);
NODE_DEFINE_CONSTANT(constants, SERVER);
NODE_DEFINE_CONSTANT(constants, IPC);
target->Set(context,
FIXED_ONE_BYTE_STRING(env->isolate(), "constants"),
constants).FromJust();
}
@ -115,17 +128,40 @@ void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
// Therefore we assert that we are not trying to call this as a
// normal function.
CHECK(args.IsConstructCall());
CHECK(args[0]->IsInt32());
Environment* env = Environment::GetCurrent(args);
new PipeWrap(env, args.This(), args[0]->IsTrue());
int type_value = args[0].As<Int32>()->Value();
PipeWrap::SocketType type = static_cast<PipeWrap::SocketType>(type_value);
bool ipc;
ProviderType provider;
switch (type) {
case SOCKET:
provider = PROVIDER_PIPEWRAP;
ipc = false;
break;
case SERVER:
provider = PROVIDER_PIPESERVERWRAP;
ipc = false;
break;
case IPC:
provider = PROVIDER_PIPEWRAP;
ipc = true;
break;
default:
UNREACHABLE();
}
new PipeWrap(env, args.This(), provider, ipc);
}
PipeWrap::PipeWrap(Environment* env,
Local<Object> object,
ProviderType provider,
bool ipc)
: ConnectionWrap(env,
object,
AsyncWrap::PROVIDER_PIPEWRAP) {
: ConnectionWrap(env, object, provider) {
int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
CHECK_EQ(r, 0); // How do we proxy this error up to javascript?
// Suggestion: uv_pipe_init() returns void.

View File

@ -32,7 +32,15 @@ namespace node {
class PipeWrap : public ConnectionWrap<PipeWrap, uv_pipe_t> {
public:
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
enum SocketType {
SOCKET,
SERVER,
IPC
};
static v8::Local<v8::Object> Instantiate(Environment* env,
AsyncWrap* parent,
SocketType type);
static void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context);
@ -42,6 +50,7 @@ class PipeWrap : public ConnectionWrap<PipeWrap, uv_pipe_t> {
private:
PipeWrap(Environment* env,
v8::Local<v8::Object> object,
ProviderType provider,
bool ipc);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);

View File

@ -187,7 +187,7 @@ static Local<Object> AcceptHandle(Environment* env, LibuvStreamWrap* parent) {
Local<Object> wrap_obj;
UVType* handle;
wrap_obj = WrapType::Instantiate(env, parent);
wrap_obj = WrapType::Instantiate(env, parent, WrapType::SOCKET);
if (wrap_obj.IsEmpty())
return Local<Object>();

View File

@ -42,6 +42,7 @@ using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Int32;
using v8::Integer;
using v8::Local;
using v8::Object;
@ -51,14 +52,17 @@ using v8::Value;
using AsyncHooks = Environment::AsyncHooks;
Local<Object> TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
Local<Object> TCPWrap::Instantiate(Environment* env,
AsyncWrap* parent,
TCPWrap::SocketType type) {
EscapableHandleScope handle_scope(env->isolate());
AsyncHooks::InitScope init_scope(env, parent->get_async_id());
CHECK_EQ(env->tcp_constructor_template().IsEmpty(), false);
Local<Function> constructor = env->tcp_constructor_template()->GetFunction();
CHECK_EQ(constructor.IsEmpty(), false);
Local<Value> type_value = Int32::New(env->isolate(), type);
Local<Object> instance =
constructor->NewInstance(env->context()).ToLocalChecked();
constructor->NewInstance(env->context(), 1, &type_value).ToLocalChecked();
return handle_scope.Escape(instance);
}
@ -122,6 +126,14 @@ void TCPWrap::Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap");
cwt->SetClassName(wrapString);
target->Set(wrapString, cwt->GetFunction());
// Define constants
Local<Object> constants = Object::New(env->isolate());
NODE_DEFINE_CONSTANT(constants, SOCKET);
NODE_DEFINE_CONSTANT(constants, SERVER);
target->Set(context,
FIXED_ONE_BYTE_STRING(env->isolate(), "constants"),
constants).FromJust();
}
@ -130,15 +142,30 @@ void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
// Therefore we assert that we are not trying to call this as a
// normal function.
CHECK(args.IsConstructCall());
CHECK(args[0]->IsInt32());
Environment* env = Environment::GetCurrent(args);
new TCPWrap(env, args.This());
int type_value = args[0].As<Int32>()->Value();
TCPWrap::SocketType type = static_cast<TCPWrap::SocketType>(type_value);
ProviderType provider;
switch (type) {
case SOCKET:
provider = PROVIDER_TCPWRAP;
break;
case SERVER:
provider = PROVIDER_TCPSERVERWRAP;
break;
default:
UNREACHABLE();
}
new TCPWrap(env, args.This(), provider);
}
TCPWrap::TCPWrap(Environment* env, Local<Object> object)
: ConnectionWrap(env,
object,
AsyncWrap::PROVIDER_TCPWRAP) {
TCPWrap::TCPWrap(Environment* env, Local<Object> object, ProviderType provider)
: ConnectionWrap(env, object, provider) {
int r = uv_tcp_init(env->event_loop(), &handle_);
CHECK_EQ(r, 0); // How do we proxy this error up to javascript?
// Suggestion: uv_tcp_init() returns void.

View File

@ -32,7 +32,14 @@ namespace node {
class TCPWrap : public ConnectionWrap<TCPWrap, uv_tcp_t> {
public:
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
enum SocketType {
SOCKET,
SERVER
};
static v8::Local<v8::Object> Instantiate(Environment* env,
AsyncWrap* parent,
SocketType type);
static void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context);
@ -46,7 +53,8 @@ class TCPWrap : public ConnectionWrap<TCPWrap, uv_tcp_t> {
int (*F)(const typename T::HandleType*, sockaddr*, int*)>
friend void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>&);
TCPWrap(Environment* env, v8::Local<v8::Object> object);
TCPWrap(Environment* env, v8::Local<v8::Object> object,
ProviderType provider);
~TCPWrap();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);

View File

@ -496,7 +496,9 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
}
Local<Object> UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
Local<Object> UDPWrap::Instantiate(Environment* env,
AsyncWrap* parent,
UDPWrap::SocketType type) {
EscapableHandleScope scope(env->isolate());
AsyncHooks::InitScope init_scope(env, parent->get_async_id());
// If this assert fires then Initialize hasn't been called yet.

View File

@ -35,6 +35,9 @@ namespace node {
class UDPWrap: public HandleWrap {
public:
enum SocketType {
SOCKET
};
static void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context);
@ -58,7 +61,9 @@ class UDPWrap: public HandleWrap {
static void SetTTL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void BufferSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
static v8::Local<v8::Object> Instantiate(Environment* env,
AsyncWrap* parent,
SocketType type);
uv_udp_t* UVHandle();
size_t self_size() const override { return sizeof(*this); }

View File

@ -28,11 +28,11 @@ function onexit() {
hooks.disable();
verifyGraph(
hooks,
[ { type: 'PIPEWRAP', id: 'pipe:1', triggerAsyncId: null },
{ type: 'PIPEWRAP', id: 'pipe:2', triggerAsyncId: 'pipe:1' },
[ { type: 'PIPESERVERWRAP', id: 'pipeserver:1', triggerAsyncId: null },
{ type: 'PIPEWRAP', id: 'pipe:1', triggerAsyncId: 'pipeserver:1' },
{ type: 'PIPECONNECTWRAP', id: 'pipeconnect:1',
triggerAsyncId: 'pipe:2' },
{ type: 'PIPEWRAP', id: 'pipe:3', triggerAsyncId: 'pipe:1' },
{ type: 'SHUTDOWNWRAP', id: 'shutdown:1', triggerAsyncId: 'pipe:3' } ]
triggerAsyncId: 'pipe:1' },
{ type: 'PIPEWRAP', id: 'pipe:2', triggerAsyncId: 'pipeserver:1' },
{ type: 'SHUTDOWNWRAP', id: 'shutdown:1', triggerAsyncId: 'pipe:2' } ]
);
}

View File

@ -34,13 +34,13 @@ function onexit() {
hooks.disable();
verifyGraph(
hooks,
[ { type: 'TCPWRAP', id: 'tcp:1', triggerAsyncId: null },
{ type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: 'tcp:1' },
[ { type: 'TCPSERVERWRAP', id: 'tcpserver:1', triggerAsyncId: null },
{ type: 'TCPWRAP', id: 'tcp:1', triggerAsyncId: 'tcpserver:1' },
{ type: 'GETADDRINFOREQWRAP',
id: 'getaddrinforeq:1', triggerAsyncId: 'tcp:2' },
id: 'getaddrinforeq:1', triggerAsyncId: 'tcp:1' },
{ type: 'TCPCONNECTWRAP',
id: 'tcpconnect:1', triggerAsyncId: 'tcp:2' },
{ type: 'TCPWRAP', id: 'tcp:3', triggerAsyncId: 'tcp:1' },
{ type: 'SHUTDOWNWRAP', id: 'shutdown:1', triggerAsyncId: 'tcp:3' } ]
id: 'tcpconnect:1', triggerAsyncId: 'tcp:1' },
{ type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: 'tcpserver:1' },
{ type: 'SHUTDOWNWRAP', id: 'shutdown:1', triggerAsyncId: 'tcp:2' } ]
);
}

View File

@ -38,11 +38,11 @@ function onexit() {
verifyGraph(
hooks,
[ { type: 'TCPWRAP', id: 'tcp:1', triggerAsyncId: null },
{ type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: null },
[ { type: 'TCPSERVERWRAP', id: 'tcpserver:1', triggerAsyncId: null },
{ type: 'TCPWRAP', id: 'tcp:1', triggerAsyncId: null },
{ type: 'TCPCONNECTWRAP',
id: 'tcpconnect:1', triggerAsyncId: 'tcp:2' },
{ type: 'TCPWRAP', id: 'tcp:3', triggerAsyncId: 'tcp:1' },
{ type: 'SHUTDOWNWRAP', id: 'shutdown:1', triggerAsyncId: 'tcp:3' } ]
id: 'tcpconnect:1', triggerAsyncId: 'tcp:1' },
{ type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: 'tcpserver:1' },
{ type: 'SHUTDOWNWRAP', id: 'shutdown:1', triggerAsyncId: 'tcp:2' } ]
);
}

View File

@ -55,21 +55,21 @@ function onexit() {
verifyGraph(
hooks,
[ { type: 'TCPWRAP', id: 'tcp:1', triggerAsyncId: null },
{ type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: 'tcp:1' },
{ type: 'TLSWRAP', id: 'tls:1', triggerAsyncId: 'tcp:1' },
[ { type: 'TCPSERVERWRAP', id: 'tcpserver:1', triggerAsyncId: null },
{ type: 'TCPWRAP', id: 'tcp:1', triggerAsyncId: 'tcpserver:1' },
{ type: 'TLSWRAP', id: 'tls:1', triggerAsyncId: 'tcpserver:1' },
{ type: 'GETADDRINFOREQWRAP',
id: 'getaddrinforeq:1', triggerAsyncId: 'tls:1' },
{ type: 'TCPCONNECTWRAP',
id: 'tcpconnect:1', triggerAsyncId: 'tcp:2' },
id: 'tcpconnect:1', triggerAsyncId: 'tcp:1' },
{ type: 'WRITEWRAP', id: 'write:1', triggerAsyncId: 'tcpconnect:1' },
{ type: 'TCPWRAP', id: 'tcp:3', triggerAsyncId: 'tcp:1' },
{ type: 'TLSWRAP', id: 'tls:2', triggerAsyncId: 'tcp:1' },
{ type: 'TIMERWRAP', id: 'timer:1', triggerAsyncId: 'tcp:1' },
{ type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: 'tcpserver:1' },
{ type: 'TLSWRAP', id: 'tls:2', triggerAsyncId: 'tcpserver:1' },
{ type: 'TIMERWRAP', id: 'timer:1', triggerAsyncId: 'tcpserver:1' },
{ type: 'WRITEWRAP', id: 'write:2', triggerAsyncId: null },
{ type: 'WRITEWRAP', id: 'write:3', triggerAsyncId: null },
{ type: 'WRITEWRAP', id: 'write:4', triggerAsyncId: null },
{ type: 'Immediate', id: 'immediate:1', triggerAsyncId: 'tcp:2' },
{ type: 'Immediate', id: 'immediate:2', triggerAsyncId: 'tcp:3' } ]
{ type: 'Immediate', id: 'immediate:1', triggerAsyncId: 'tcp:1' },
{ type: 'Immediate', id: 'immediate:2', triggerAsyncId: 'tcp:2' } ]
);
}

View File

@ -12,7 +12,8 @@ common.refreshTmpDir();
const hooks = initHooks();
hooks.enable();
let pipe1, pipe2, pipe3;
let pipe1, pipe2;
let pipeserver;
let pipeconnect;
net.createServer(common.mustCall(function(c) {
@ -22,27 +23,27 @@ net.createServer(common.mustCall(function(c) {
})).listen(common.PIPE, common.mustCall(onlisten));
function onlisten() {
let pipes = hooks.activitiesOfTypes('PIPEWRAP');
const pipeservers = hooks.activitiesOfTypes('PIPESERVERWRAP');
let pipeconnects = hooks.activitiesOfTypes('PIPECONNECTWRAP');
assert.strictEqual(pipes.length, 1);
assert.strictEqual(pipeservers.length, 1);
assert.strictEqual(pipeconnects.length, 0);
net.connect(common.PIPE,
common.mustCall(maybeOnconnect.bind(null, 'client')));
pipes = hooks.activitiesOfTypes('PIPEWRAP');
const pipes = hooks.activitiesOfTypes('PIPEWRAP');
pipeconnects = hooks.activitiesOfTypes('PIPECONNECTWRAP');
assert.strictEqual(pipes.length, 2);
assert.strictEqual(pipes.length, 1);
assert.strictEqual(pipeconnects.length, 1);
pipeserver = pipeservers[0];
pipe1 = pipes[0];
pipe2 = pipes[1];
pipeconnect = pipeconnects[0];
assert.strictEqual(pipeserver.type, 'PIPESERVERWRAP');
assert.strictEqual(pipe1.type, 'PIPEWRAP');
assert.strictEqual(pipe2.type, 'PIPEWRAP');
assert.strictEqual(pipeconnect.type, 'PIPECONNECTWRAP');
for (const a of [ pipe1, pipe2, pipeconnect ]) {
for (const a of [ pipeserver, pipe1, pipeconnect ]) {
assert.strictEqual(typeof a.uid, 'number');
assert.strictEqual(typeof a.triggerAsyncId, 'number');
checkInvocations(a, { init: 1 }, 'after net.connect');
@ -60,18 +61,18 @@ function maybeOnconnect(source) {
const pipes = hooks.activitiesOfTypes('PIPEWRAP');
const pipeconnects = hooks.activitiesOfTypes('PIPECONNECTWRAP');
assert.strictEqual(pipes.length, 3);
assert.strictEqual(pipes.length, 2);
assert.strictEqual(pipeconnects.length, 1);
pipe3 = pipes[2];
assert.strictEqual(typeof pipe3.uid, 'number');
assert.strictEqual(typeof pipe3.triggerAsyncId, 'number');
pipe2 = pipes[1];
assert.strictEqual(typeof pipe2.uid, 'number');
assert.strictEqual(typeof pipe2.triggerAsyncId, 'number');
checkInvocations(pipe1, { init: 1, before: 1, after: 1 },
'pipe1, client connected');
checkInvocations(pipe2, { init: 1 }, 'pipe2, client connected');
checkInvocations(pipeserver, { init: 1, before: 1, after: 1 },
'pipeserver, client connected');
checkInvocations(pipe1, { init: 1 }, 'pipe1, client connected');
checkInvocations(pipeconnect, { init: 1, before: 1 },
'pipeconnect, client connected');
checkInvocations(pipe3, { init: 1 }, 'pipe3, client connected');
checkInvocations(pipe2, { init: 1 }, 'pipe2, client connected');
tick(5);
}
@ -80,14 +81,15 @@ process.on('exit', onexit);
function onexit() {
hooks.disable();
hooks.sanityCheck('PIPEWRAP');
hooks.sanityCheck('PIPESERVERWRAP');
hooks.sanityCheck('PIPECONNECTWRAP');
// TODO(thlorenz) why have some of those 'before' and 'after' called twice
checkInvocations(pipe1, { init: 1, before: 1, after: 1, destroy: 1 },
checkInvocations(pipeserver, { init: 1, before: 1, after: 1, destroy: 1 },
'pipeserver, process exiting');
checkInvocations(pipe1, { init: 1, before: 2, after: 2, destroy: 1 },
'pipe1, process exiting');
checkInvocations(pipe2, { init: 1, before: 2, after: 2, destroy: 1 },
'pipe2, process exiting');
checkInvocations(pipeconnect, { init: 1, before: 1, after: 1, destroy: 1 },
'pipeconnect, process exiting');
checkInvocations(pipe3, { init: 1, before: 2, after: 2, destroy: 1 },
'pipe3, process exiting');
checkInvocations(pipe2, { init: 1, before: 2, after: 2, destroy: 1 },
'pipe2, process exiting');
}

View File

@ -11,7 +11,8 @@ const initHooks = require('./init-hooks');
const { checkInvocations } = require('./hook-checks');
const net = require('net');
let tcp1, tcp2, tcp3;
let tcp1, tcp2;
let tcpserver;
let tcpconnect;
const hooks = initHooks();
@ -24,15 +25,15 @@ const server = net
// Calling server.listen creates a TCPWRAP synchronously
{
server.listen(common.PORT);
const tcps = hooks.activitiesOfTypes('TCPWRAP');
const tcpsservers = hooks.activitiesOfTypes('TCPSERVERWRAP');
const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
assert.strictEqual(tcps.length, 1);
assert.strictEqual(tcpsservers.length, 1);
assert.strictEqual(tcpconnects.length, 0);
tcp1 = tcps[0];
assert.strictEqual(tcp1.type, 'TCPWRAP');
assert.strictEqual(typeof tcp1.uid, 'number');
assert.strictEqual(typeof tcp1.triggerAsyncId, 'number');
checkInvocations(tcp1, { init: 1 }, 'when calling server.listen');
tcpserver = tcpsservers[0];
assert.strictEqual(tcpserver.type, 'TCPSERVERWRAP');
assert.strictEqual(typeof tcpserver.uid, 'number');
assert.strictEqual(typeof tcpserver.triggerAsyncId, 'number');
checkInvocations(tcpserver, { init: 1 }, 'when calling server.listen');
}
// Calling net.connect creates another TCPWRAP synchronously
@ -41,24 +42,25 @@ const server = net
{ port: server.address().port, host: '::1' },
common.mustCall(onconnected));
const tcps = hooks.activitiesOfTypes('TCPWRAP');
assert.strictEqual(tcps.length, 2);
assert.strictEqual(tcps.length, 1);
process.nextTick(() => {
const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
assert.strictEqual(tcpconnects.length, 1);
});
tcp2 = tcps[1];
assert.strictEqual(tcps.length, 2);
assert.strictEqual(tcp2.type, 'TCPWRAP');
assert.strictEqual(typeof tcp2.uid, 'number');
assert.strictEqual(typeof tcp2.triggerAsyncId, 'number');
tcp1 = tcps[0];
assert.strictEqual(tcps.length, 1);
assert.strictEqual(tcp1.type, 'TCPWRAP');
assert.strictEqual(typeof tcp1.uid, 'number');
assert.strictEqual(typeof tcp1.triggerAsyncId, 'number');
checkInvocations(tcpserver, { init: 1 },
'tcpserver when client is connecting');
checkInvocations(tcp1, { init: 1 }, 'tcp1 when client is connecting');
checkInvocations(tcp2, { init: 1 }, 'tcp2 when client is connecting');
}
function onlistening() {
assert.strictEqual(hooks.activitiesOfTypes('TCPWRAP').length, 2);
assert.strictEqual(hooks.activitiesOfTypes('TCPWRAP').length, 1);
}
// Depending on timing we see client: onconnected or server: onconnection first
@ -99,8 +101,8 @@ function onconnected() {
const expected = serverConnected ?
{ init: 1, before: 1, after: 1 } :
{ init: 1 };
checkInvocations(tcp1, expected, 'tcp1 when client connects');
checkInvocations(tcp2, { init: 1 }, 'tcp2 when client connects');
checkInvocations(tcpserver, expected, 'tcpserver when client connects');
checkInvocations(tcp1, { init: 1 }, 'tcp1 when client connects');
}
function onconnection(c) {
@ -109,34 +111,35 @@ function onconnection(c) {
const tcps = hooks.activitiesOfTypes([ 'TCPWRAP' ]);
const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
assert.strictEqual(tcps.length, 3);
assert.strictEqual(tcps.length, 2);
assert.strictEqual(tcpconnects.length, 1);
tcp3 = tcps[2];
assert.strictEqual(tcp3.type, 'TCPWRAP');
assert.strictEqual(typeof tcp3.uid, 'number');
assert.strictEqual(typeof tcp3.triggerAsyncId, 'number');
tcp2 = tcps[1];
assert.strictEqual(tcp2.type, 'TCPWRAP');
assert.strictEqual(typeof tcp2.uid, 'number');
assert.strictEqual(typeof tcp2.triggerAsyncId, 'number');
checkInvocations(tcp1, { init: 1, before: 1 },
'tcp1 when server receives connection');
checkInvocations(tcpserver, { init: 1, before: 1 },
'tcpserver when server receives connection');
checkInvocations(tcp1, { init: 1 }, 'tcp1 when server receives connection');
checkInvocations(tcp2, { init: 1 }, 'tcp2 when server receives connection');
checkInvocations(tcp3, { init: 1 }, 'tcp3 when server receives connection');
c.end();
this.close(common.mustCall(onserverClosed));
}
function onserverClosed() {
checkInvocations(tcp1, { init: 1, before: 1, after: 1, destroy: 1 },
'tcp1 when server is closed');
checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 },
'tcpserver when server is closed');
setImmediate(() => {
checkInvocations(tcp2, { init: 1, before: 2, after: 2, destroy: 1 },
'tcp2 after server is closed');
checkInvocations(tcp1, { init: 1, before: 2, after: 2, destroy: 1 },
'tcp1 after server is closed');
});
checkInvocations(tcp3, { init: 1, before: 1, after: 1 },
'tcp3 synchronously when server is closed');
checkInvocations(tcp2, { init: 1, before: 1, after: 1 },
'tcp2 synchronously when server is closed');
tick(2, () => {
checkInvocations(tcp3, { init: 1, before: 2, after: 2, destroy: 1 },
'tcp3 when server is closed');
checkInvocations(tcp2, { init: 1, before: 2, after: 2, destroy: 1 },
'tcp2 when server is closed');
checkInvocations(tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 },
'tcpconnect when server is closed');
});
@ -146,16 +149,16 @@ process.on('exit', onexit);
function onexit() {
hooks.disable();
hooks.sanityCheck([ 'TCPWRAP', 'TCPCONNECTWRAP' ]);
hooks.sanityCheck([ 'TCPWRAP', 'TCPSERVERWRAP', 'TCPCONNECTWRAP' ]);
checkInvocations(tcp1, { init: 1, before: 1, after: 1, destroy: 1 },
'tcp1 when process exits');
checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 },
'tcpserver when process exits');
checkInvocations(
tcp1, { init: 1, before: 2, after: 2, destroy: 1 },
'tcp1 when process exits');
checkInvocations(
tcp2, { init: 1, before: 2, after: 2, destroy: 1 },
'tcp2 when process exits');
checkInvocations(
tcp3, { init: 1, before: 2, after: 2, destroy: 1 },
'tcp3 when process exits');
checkInvocations(
tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 },
'tcpconnect when process exits');

View File

@ -524,8 +524,8 @@ function _mustCallInner(fn, criteria = 1, field) {
}
exports.hasMultiLocalhost = function hasMultiLocalhost() {
const TCP = process.binding('tcp_wrap').TCP;
const t = new TCP();
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const t = new TCP(TCPConstants.SOCKET);
const ret = t.bind('127.0.0.2', exports.PORT);
t.close();
return ret === 0;

View File

@ -66,8 +66,8 @@ const dgram = require('dgram');
// pipe
{
const Pipe = process.binding('pipe_wrap').Pipe;
const handle = new Pipe();
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
const handle = new Pipe(PipeConstants.SOCKET);
strictEqual(Object.getPrototypeOf(handle).hasOwnProperty('hasRef'),
true, 'pipe_wrap: hasRef() missing');
strictEqual(handle.hasRef(),

View File

@ -6,7 +6,7 @@ if (common.isWindows)
const assert = require('assert');
const net = require('net');
const path = require('path');
const Pipe = process.binding('pipe_wrap').Pipe;
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
common.refreshTmpDir();
@ -71,7 +71,7 @@ const forAllClients = (cb) => common.mustCall(cb, CLIENT_VARIANTS);
})
.listen({ path: serverPath }, common.mustCall(function serverOnListen() {
const getSocketOpt = (index) => {
const handle = new Pipe();
const handle = new Pipe(PipeConstants.SOCKET);
const err = handle.bind(`${prefix}-client-${socketCounter++}`);
assert(err >= 0, String(err));
assert.notStrictEqual(handle.fd, -1);

View File

@ -5,8 +5,8 @@ const assert = require('assert');
const net = require('net');
const fs = require('fs');
const uv = process.binding('uv');
const TCP = process.binding('tcp_wrap').TCP;
const Pipe = process.binding('pipe_wrap').Pipe;
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
common.refreshTmpDir();
@ -36,12 +36,12 @@ function randomPipePath() {
function randomHandle(type) {
let handle, errno, handleName;
if (type === 'tcp') {
handle = new TCP();
handle = new TCP(TCPConstants.SOCKET);
errno = handle.bind('0.0.0.0', 0);
handleName = 'arbitrary tcp port';
} else {
const path = randomPipePath();
handle = new Pipe();
handle = new Pipe(PipeConstants.SOCKET);
errno = handle.bind(path);
handleName = `pipe ${path}`;
}

View File

@ -23,8 +23,8 @@
require('../common');
const assert = require('assert');
const Process = process.binding('process_wrap').Process;
const Pipe = process.binding('pipe_wrap').Pipe;
const pipe = new Pipe();
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
const pipe = new Pipe(PipeConstants.SOCKET);
const p = new Process();
let processExited = false;

View File

@ -1,12 +1,12 @@
'use strict';
require('../common');
const assert = require('assert');
const TCP = process.binding('tcp_wrap').TCP;
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
const ShutdownWrap = process.binding('stream_wrap').ShutdownWrap;
function makeConnection() {
const client = new TCP();
const client = new TCP(TCPConstants.SOCKET);
const req = new TCPConnectWrap();
const err = client.connect(req, '127.0.0.1', this.address().port);

View File

@ -2,10 +2,10 @@
const common = require('../common');
const assert = require('assert');
const TCP = process.binding('tcp_wrap').TCP;
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const WriteWrap = process.binding('stream_wrap').WriteWrap;
const server = new TCP();
const server = new TCP(TCPConstants.SOCKET);
const r = server.bind('0.0.0.0', 0);
assert.strictEqual(0, r);

View File

@ -23,10 +23,10 @@
require('../common');
const assert = require('assert');
const TCP = process.binding('tcp_wrap').TCP;
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const uv = process.binding('uv');
const handle = new TCP();
const handle = new TCP(TCPConstants.SOCKET);
// Should be able to bind to the port
let err = handle.bind('0.0.0.0', 0);

View File

@ -138,19 +138,27 @@ if (common.hasCrypto) { // eslint-disable-line crypto-check
testInitialized(new Gzip()._handle, 'Zlib');
}
{
const binding = process.binding('pipe_wrap');
const handle = new binding.Pipe();
const handle = new binding.Pipe(binding.constants.IPC);
testInitialized(handle, 'Pipe');
const req = new binding.PipeConnectWrap();
testUninitialized(req, 'PipeConnectWrap');
req.address = common.PIPE;
req.oncomplete = common.mustCall(() => handle.close());
handle.connect(req, req.address, req.oncomplete);
testInitialized(req, 'PipeConnectWrap');
}
{
const server = net.createServer(common.mustCall((socket) => {
server.close();
})).listen(common.PIPE, common.mustCall(() => {
const binding = process.binding('pipe_wrap');
const handle = new binding.Pipe(binding.constants.SOCKET);
testInitialized(handle, 'Pipe');
const req = new binding.PipeConnectWrap();
testUninitialized(req, 'PipeConnectWrap');
req.address = common.PIPE;
req.oncomplete = common.mustCall(() => handle.close());
handle.connect(req, req.address, req.oncomplete);
testInitialized(req, 'PipeConnectWrap');
}));
}
{
const Process = process.binding('process_wrap').Process;
@ -179,7 +187,7 @@ if (common.hasCrypto) { // eslint-disable-line crypto-check
});
socket.resume();
})).listen(0, common.localhostIPv4, common.mustCall(() => {
const handle = new tcp_wrap.TCP();
const handle = new tcp_wrap.TCP(tcp_wrap.constants.SOCKET);
const req = new tcp_wrap.TCPConnectWrap();
const sreq = new stream_wrap.ShutdownWrap();
const wreq = new stream_wrap.WriteWrap();
@ -221,8 +229,8 @@ if (common.hasCrypto) { // eslint-disable-line crypto-check
if (common.hasCrypto) { // eslint-disable-line crypto-check
const TCP = process.binding('tcp_wrap').TCP;
const tcp = new TCP();
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
const tcp = new TCP(TCPConstants.SOCKET);
const ca = fixtures.readSync('test_ca.pem', 'ascii');
const cert = fixtures.readSync('test_cert.pem', 'ascii');