Skip to content

Commit e0ce7cf

Browse files
AndreasMadsenMylesBorins
authored andcommitted
async_wrap: add provider types for net server
Adds `TCPSERVERWRAP` and `PIPESERVERWRAP` as provider types. This makes it possible to distinguish servers from connections. Backport-PR-URL: #17621 PR-URL: #17157 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent f1b26be commit e0ce7cf

32 files changed

+288
-168
lines changed

benchmark/net/tcp-raw-c2s.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const bench = common.createBenchmark(main, {
1414
dur: [5]
1515
});
1616

17-
const TCP = process.binding('tcp_wrap').TCP;
17+
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
1818
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
1919
const WriteWrap = process.binding('stream_wrap').WriteWrap;
2020
const PORT = common.PORT;
@@ -36,7 +36,7 @@ function fail(err, syscall) {
3636
}
3737

3838
function server() {
39-
const serverHandle = new TCP();
39+
const serverHandle = new TCP(TCPConstants.SERVER);
4040
var err = serverHandle.bind('127.0.0.1', PORT);
4141
if (err)
4242
fail(err, 'bind');
@@ -92,7 +92,7 @@ function client() {
9292
throw new Error(`invalid type: ${type}`);
9393
}
9494

95-
const clientHandle = new TCP();
95+
const clientHandle = new TCP(TCPConstants.SOCKET);
9696
const connectReq = new TCPConnectWrap();
9797
const err = clientHandle.connect(connectReq, '127.0.0.1', PORT);
9898

benchmark/net/tcp-raw-pipe.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const bench = common.createBenchmark(main, {
1414
dur: [5]
1515
});
1616

17-
const TCP = process.binding('tcp_wrap').TCP;
17+
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
1818
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
1919
const WriteWrap = process.binding('stream_wrap').WriteWrap;
2020
const PORT = common.PORT;
@@ -35,7 +35,7 @@ function fail(err, syscall) {
3535
}
3636

3737
function server() {
38-
const serverHandle = new TCP();
38+
const serverHandle = new TCP(TCPConstants.SERVER);
3939
var err = serverHandle.bind('127.0.0.1', PORT);
4040
if (err)
4141
fail(err, 'bind');
@@ -89,7 +89,7 @@ function client() {
8989
throw new Error(`invalid type: ${type}`);
9090
}
9191

92-
const clientHandle = new TCP();
92+
const clientHandle = new TCP(TCPConstants.SOCKET);
9393
const connectReq = new TCPConnectWrap();
9494
const err = clientHandle.connect(connectReq, '127.0.0.1', PORT);
9595
var bytes = 0;

benchmark/net/tcp-raw-s2c.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const bench = common.createBenchmark(main, {
1414
dur: [5]
1515
});
1616

17-
const TCP = process.binding('tcp_wrap').TCP;
17+
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
1818
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
1919
const WriteWrap = process.binding('stream_wrap').WriteWrap;
2020
const PORT = common.PORT;
@@ -35,7 +35,7 @@ function fail(err, syscall) {
3535
}
3636

3737
function server() {
38-
const serverHandle = new TCP();
38+
const serverHandle = new TCP(TCPConstants.SERVER);
3939
var err = serverHandle.bind('127.0.0.1', PORT);
4040
if (err)
4141
fail(err, 'bind');
@@ -107,7 +107,7 @@ function server() {
107107
}
108108

109109
function client() {
110-
const clientHandle = new TCP();
110+
const clientHandle = new TCP(TCPConstants.SOCKET);
111111
const connectReq = new TCPConnectWrap();
112112
const err = clientHandle.connect(connectReq, '127.0.0.1', PORT);
113113

doc/api/async_hooks.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ resource's constructor.
236236
```text
237237
FSEVENTWRAP, FSREQWRAP, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPPARSER,
238238
JSSTREAM, PIPECONNECTWRAP, PIPEWRAP, PROCESSWRAP, QUERYWRAP, SHUTDOWNWRAP,
239-
SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPWRAP, TIMERWRAP, TTYWRAP,
239+
SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVER, TCPWRAP, TIMERWRAP, TTYWRAP,
240240
UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST,
241241
RANDOMBYTESREQUEST, TLSWRAP, Timeout, Immediate, TickObject
242242
```
@@ -275,13 +275,13 @@ require('net').createServer((conn) => {}).listen(8080);
275275
Output when hitting the server with `nc localhost 8080`:
276276

277277
```console
278-
TCPWRAP(2): trigger: 1 execution: 1
278+
TCPSERVERWRAP(2): trigger: 1 execution: 1
279279
TCPWRAP(4): trigger: 2 execution: 0
280280
```
281281

282-
The first `TCPWRAP` is the server which receives the connections.
282+
The `TCPSERVERWRAP` is the server which receives the connections.
283283

284-
The second `TCPWRAP` is the new connection from the client. When a new
284+
The `TCPWRAP` is the new connection from the client. When a new
285285
connection is made the `TCPWrap` instance is immediately constructed. This
286286
happens outside of any JavaScript stack (side note: a `executionAsyncId()` of `0`
287287
means it's being executed from C++, with no JavaScript stack above it).
@@ -354,7 +354,7 @@ require('net').createServer(() => {}).listen(8080, () => {
354354
Output from only starting the server:
355355

356356
```console
357-
TCPWRAP(2): trigger: 1 execution: 1
357+
TCPSERVERWRAP(2): trigger: 1 execution: 1
358358
TickObject(3): trigger: 2 execution: 1
359359
before: 3
360360
Timeout(4): trigger: 3 execution: 3
@@ -387,7 +387,7 @@ Only using `execution` to graph resource allocation results in the following:
387387
TTYWRAP(6) -> Timeout(4) -> TIMERWRAP(5) -> TickObject(3) -> root(1)
388388
```
389389

390-
The `TCPWRAP` is not part of this graph, even though it was the reason for
390+
The `TCPSERVERWRAP` is not part of this graph, even though it was the reason for
391391
`console.log()` being called. This is because binding to a port without a
392392
hostname is a *synchronous* operation, but to maintain a completely asynchronous
393393
API the user's callback is placed in a `process.nextTick()`.

lib/_tls_wrap.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ const { Buffer } = require('buffer');
3434
const debug = util.debuglog('tls');
3535
const { Timer } = process.binding('timer_wrap');
3636
const tls_wrap = process.binding('tls_wrap');
37-
const { TCP } = process.binding('tcp_wrap');
38-
const { Pipe } = process.binding('pipe_wrap');
37+
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
38+
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
3939
const errors = require('internal/errors');
4040
const kConnectOptions = Symbol('connect-options');
4141
const kDisableRenegotiation = Symbol('disable-renegotiation');
@@ -398,7 +398,9 @@ TLSSocket.prototype._wrapHandle = function(wrap) {
398398

399399
var options = this._tlsOptions;
400400
if (!handle) {
401-
handle = options.pipe ? new Pipe() : new TCP();
401+
handle = options.pipe ?
402+
new Pipe(PipeConstants.SOCKET) :
403+
new TCP(TCPConstants.SOCKET);
402404
handle.owner = this;
403405
}
404406

lib/child_process.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const { createPromise,
2828
promiseResolve, promiseReject } = process.binding('util');
2929
const debug = util.debuglog('child_process');
3030
const { Buffer } = require('buffer');
31-
const { Pipe } = process.binding('pipe_wrap');
31+
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
3232
const { errname } = process.binding('uv');
3333
const child_process = require('internal/child_process');
3434
const {
@@ -103,7 +103,7 @@ exports.fork = function(modulePath /*, args, options*/) {
103103

104104
exports._forkChild = function(fd) {
105105
// set process.send()
106-
var p = new Pipe(true);
106+
var p = new Pipe(PipeConstants.IPC);
107107
p.open(fd);
108108
p.unref();
109109
const control = setupChannel(process, p);

lib/internal/child_process.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const assert = require('assert');
1010

1111
const { Process } = process.binding('process_wrap');
1212
const { WriteWrap } = process.binding('stream_wrap');
13-
const { Pipe } = process.binding('pipe_wrap');
13+
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
1414
const { TTY } = process.binding('tty_wrap');
1515
const { TCP } = process.binding('tcp_wrap');
1616
const { UDP } = process.binding('udp_wrap');
@@ -863,7 +863,7 @@ function _validateStdio(stdio, sync) {
863863
};
864864

865865
if (!sync)
866-
a.handle = new Pipe();
866+
a.handle = new Pipe(PipeConstants.SOCKET);
867867

868868
acc.push(a);
869869
} else if (stdio === 'ipc') {
@@ -876,7 +876,7 @@ function _validateStdio(stdio, sync) {
876876
throw new errors.Error('ERR_IPC_SYNC_FORK');
877877
}
878878

879-
ipc = new Pipe(true);
879+
ipc = new Pipe(PipeConstants.IPC);
880880
ipcFd = i;
881881

882882
acc.push({

lib/net.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ const {
3737

3838
const { Buffer } = require('buffer');
3939
const TTYWrap = process.binding('tty_wrap');
40-
const { TCP } = process.binding('tcp_wrap');
41-
const { Pipe } = process.binding('pipe_wrap');
40+
const { TCP, constants: TCPConstants } = process.binding('tcp_wrap');
41+
const { Pipe, constants: PipeConstants } = process.binding('pipe_wrap');
4242
const { TCPConnectWrap } = process.binding('tcp_wrap');
4343
const { PipeConnectWrap } = process.binding('pipe_wrap');
4444
const { ShutdownWrap, WriteWrap } = process.binding('stream_wrap');
@@ -57,10 +57,20 @@ const exceptionWithHostPort = util._exceptionWithHostPort;
5757

5858
function noop() {}
5959

60-
function createHandle(fd) {
60+
function createHandle(fd, is_server) {
6161
const type = TTYWrap.guessHandleType(fd);
62-
if (type === 'PIPE') return new Pipe();
63-
if (type === 'TCP') return new TCP();
62+
if (type === 'PIPE') {
63+
return new Pipe(
64+
is_server ? PipeConstants.SERVER : PipeConstants.SOCKET
65+
);
66+
}
67+
68+
if (type === 'TCP') {
69+
return new TCP(
70+
is_server ? TCPConstants.SERVER : TCPConstants.SOCKET
71+
);
72+
}
73+
6474
throw new errors.TypeError('ERR_INVALID_FD_TYPE', type);
6575
}
6676

@@ -200,7 +210,7 @@ function Socket(options) {
200210
this._handle = options.handle; // private
201211
this[async_id_symbol] = getNewAsyncId(this._handle);
202212
} else if (options.fd !== undefined) {
203-
this._handle = createHandle(options.fd);
213+
this._handle = createHandle(options.fd, false);
204214
this._handle.open(options.fd);
205215
this[async_id_symbol] = this._handle.getAsyncId();
206216
// options.fd can be string (since it is user-defined),
@@ -1009,7 +1019,9 @@ Socket.prototype.connect = function(...args) {
10091019
debug('pipe', pipe, path);
10101020

10111021
if (!this._handle) {
1012-
this._handle = pipe ? new Pipe() : new TCP();
1022+
this._handle = pipe ?
1023+
new Pipe(PipeConstants.SOCKET) :
1024+
new TCP(TCPConstants.SOCKET);
10131025
initSocketHandle(this);
10141026
}
10151027

@@ -1269,7 +1281,7 @@ function createServerHandle(address, port, addressType, fd) {
12691281
var isTCP = false;
12701282
if (typeof fd === 'number' && fd >= 0) {
12711283
try {
1272-
handle = createHandle(fd);
1284+
handle = createHandle(fd, true);
12731285
} catch (e) {
12741286
// Not a fd we can listen on. This will trigger an error.
12751287
debug('listen invalid fd=%d:', fd, e.message);
@@ -1280,15 +1292,15 @@ function createServerHandle(address, port, addressType, fd) {
12801292
handle.writable = true;
12811293
assert(!address && !port);
12821294
} else if (port === -1 && addressType === -1) {
1283-
handle = new Pipe();
1295+
handle = new Pipe(PipeConstants.SERVER);
12841296
if (process.platform === 'win32') {
12851297
var instances = parseInt(process.env.NODE_PENDING_PIPE_INSTANCES);
12861298
if (!isNaN(instances)) {
12871299
handle.setPendingInstances(instances);
12881300
}
12891301
}
12901302
} else {
1291-
handle = new TCP();
1303+
handle = new TCP(TCPConstants.SERVER);
12921304
isTCP = true;
12931305
}
12941306

src/async_wrap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace node {
4646
V(HTTPPARSER) \
4747
V(JSSTREAM) \
4848
V(PIPECONNECTWRAP) \
49+
V(PIPESERVERWRAP) \
4950
V(PIPEWRAP) \
5051
V(PROCESSWRAP) \
5152
V(PROMISE) \
@@ -54,6 +55,7 @@ namespace node {
5455
V(SIGNALWRAP) \
5556
V(STATWATCHER) \
5657
V(TCPCONNECTWRAP) \
58+
V(TCPSERVERWRAP) \
5759
V(TCPWRAP) \
5860
V(TIMERWRAP) \
5961
V(TTYWRAP) \

src/connection_wrap.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ void ConnectionWrap<WrapType, UVType>::OnConnection(uv_stream_t* handle,
5151
if (status == 0) {
5252
env->set_init_trigger_async_id(wrap_data->get_async_id());
5353
// Instantiate the client javascript object and handle.
54-
Local<Object> client_obj = WrapType::Instantiate(env, wrap_data);
54+
Local<Object> client_obj = WrapType::Instantiate(env,
55+
wrap_data,
56+
WrapType::SOCKET);
5557

5658
// Unwrap the client javascript object.
5759
WrapType* wrap;

src/pipe_wrap.cc

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ using v8::Function;
4040
using v8::FunctionCallbackInfo;
4141
using v8::FunctionTemplate;
4242
using v8::HandleScope;
43+
using v8::Int32;
4344
using v8::Local;
4445
using v8::Object;
4546
using v8::String;
@@ -48,14 +49,17 @@ using v8::Value;
4849
using AsyncHooks = Environment::AsyncHooks;
4950

5051

51-
Local<Object> PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) {
52+
Local<Object> PipeWrap::Instantiate(Environment* env,
53+
AsyncWrap* parent,
54+
PipeWrap::SocketType type) {
5255
EscapableHandleScope handle_scope(env->isolate());
5356
AsyncHooks::InitScope init_scope(env, parent->get_async_id());
5457
CHECK_EQ(false, env->pipe_constructor_template().IsEmpty());
5558
Local<Function> constructor = env->pipe_constructor_template()->GetFunction();
5659
CHECK_EQ(false, constructor.IsEmpty());
60+
Local<Value> type_value = Int32::New(env->isolate(), type);
5761
Local<Object> instance =
58-
constructor->NewInstance(env->context()).ToLocalChecked();
62+
constructor->NewInstance(env->context(), 1, &type_value).ToLocalChecked();
5963
return handle_scope.Escape(instance);
6064
}
6165

@@ -107,6 +111,15 @@ void PipeWrap::Initialize(Local<Object> target,
107111
FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap");
108112
cwt->SetClassName(wrapString);
109113
target->Set(wrapString, cwt->GetFunction());
114+
115+
// Define constants
116+
Local<Object> constants = Object::New(env->isolate());
117+
NODE_DEFINE_CONSTANT(constants, SOCKET);
118+
NODE_DEFINE_CONSTANT(constants, SERVER);
119+
NODE_DEFINE_CONSTANT(constants, IPC);
120+
target->Set(context,
121+
FIXED_ONE_BYTE_STRING(env->isolate(), "constants"),
122+
constants).FromJust();
110123
}
111124

112125

@@ -115,17 +128,40 @@ void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
115128
// Therefore we assert that we are not trying to call this as a
116129
// normal function.
117130
CHECK(args.IsConstructCall());
131+
CHECK(args[0]->IsInt32());
118132
Environment* env = Environment::GetCurrent(args);
119-
new PipeWrap(env, args.This(), args[0]->IsTrue());
133+
134+
int type_value = args[0].As<Int32>()->Value();
135+
PipeWrap::SocketType type = static_cast<PipeWrap::SocketType>(type_value);
136+
137+
bool ipc;
138+
ProviderType provider;
139+
switch (type) {
140+
case SOCKET:
141+
provider = PROVIDER_PIPEWRAP;
142+
ipc = false;
143+
break;
144+
case SERVER:
145+
provider = PROVIDER_PIPESERVERWRAP;
146+
ipc = false;
147+
break;
148+
case IPC:
149+
provider = PROVIDER_PIPEWRAP;
150+
ipc = true;
151+
break;
152+
default:
153+
UNREACHABLE();
154+
}
155+
156+
new PipeWrap(env, args.This(), provider, ipc);
120157
}
121158

122159

123160
PipeWrap::PipeWrap(Environment* env,
124161
Local<Object> object,
162+
ProviderType provider,
125163
bool ipc)
126-
: ConnectionWrap(env,
127-
object,
128-
AsyncWrap::PROVIDER_PIPEWRAP) {
164+
: ConnectionWrap(env, object, provider) {
129165
int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
130166
CHECK_EQ(r, 0); // How do we proxy this error up to javascript?
131167
// Suggestion: uv_pipe_init() returns void.

0 commit comments

Comments
 (0)