Skip to content

Commit e03e2f6

Browse files
authored
net: throw on multiple listen calls
Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: #64871 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
1 parent 6b28d88 commit e03e2f6

3 files changed

Lines changed: 35 additions & 25 deletions

File tree

‎lib/net.js‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2256,6 +2256,7 @@ function Server(options, connectionListener) {
22562256

22572257
this[async_id_symbol] = -1;
22582258
this._handle = null;
2259+
this._listening = false;
22592260
this._usingWorkers = false;
22602261
this._workers = [];
22612262
this._unref = false;
@@ -2476,6 +2477,7 @@ Server.prototype[kTransfer] = function() {
24762477
};
24772478
// Detach so the source server no longer references the handle being moved.
24782479
this._handle = null;
2480+
this._listening = false;
24792481
return {
24802482
data,
24812483
deserializeInfo: 'net:Server',
@@ -2499,6 +2501,7 @@ Server.prototype[kDeserialize] = function(data) {
24992501
};
25002502

25012503
function emitErrorNT(self, err) {
2504+
self._listening = false;
25022505
self.emit('error', err);
25032506
}
25042507

@@ -2544,6 +2547,7 @@ function listenInCluster(server, address, port, addressType,
25442547

25452548
if (err) {
25462549
const ex = new ExceptionWithHostPort(err, 'bind', address, port);
2550+
server._listening = false;
25472551
return server.emit('error', ex);
25482552
}
25492553
// If there was a handle, just close it to avoid fd leak
@@ -2564,7 +2568,7 @@ Server.prototype.listen = function(...args) {
25642568
let options = normalized[0];
25652569
const cb = normalized[1];
25662570

2567-
if (this._handle) {
2571+
if (this._handle || this._listening) {
25682572
throw new ERR_SERVER_ALREADY_LISTEN();
25692573
}
25702574

@@ -2596,6 +2600,7 @@ Server.prototype.listen = function(...args) {
25962600
this._pipeName = boundPath;
25972601
}
25982602
this[async_id_symbol] = this._handle.getAsyncId();
2603+
this._listening = true;
25992604
this._listeningId++;
26002605
listenInCluster(this, null, -1, -1, backlogFromArgs, undefined, true);
26012606
return this;
@@ -2608,12 +2613,14 @@ Server.prototype.listen = function(...args) {
26082613
if (options instanceof TCP) {
26092614
this._handle = options;
26102615
this[async_id_symbol] = this._handle.getAsyncId();
2616+
this._listening = true;
26112617
listenInCluster(this, null, -1, -1, backlogFromArgs, undefined, true);
26122618
return this;
26132619
}
26142620
addServerAbortSignalOption(this, options);
26152621
// (handle[, backlog][, cb]) where handle is an object with a fd
26162622
if (typeof options.fd === 'number' && options.fd >= 0) {
2623+
this._listening = true;
26172624
listenInCluster(this, null, null, null, backlogFromArgs, options.fd);
26182625
return this;
26192626
}
@@ -2638,6 +2645,7 @@ Server.prototype.listen = function(...args) {
26382645
options.exclusive = true;
26392646
}
26402647
// start TCP server listening on host:port
2648+
this._listening = true;
26412649
if (options.host) {
26422650
lookupAndListen(this, options.port | 0, options.host, backlog,
26432651
options.exclusive, flags);
@@ -2660,6 +2668,7 @@ Server.prototype.listen = function(...args) {
26602668
}
26612669
const pipeName = this._pipeName = options.path;
26622670
backlog = options.backlog || backlogFromArgs;
2671+
this._listening = true;
26632672
listenInCluster(this,
26642673
pipeName,
26652674
-1,
@@ -2689,6 +2698,7 @@ Server.prototype.listen = function(...args) {
26892698
if (err) {
26902699
this._handle.close();
26912700
this._handle = null;
2701+
this._listening = false;
26922702
throw new ErrnoException(err, 'uv_pipe_chmod');
26932703
}
26942704
}
@@ -2742,6 +2752,7 @@ function lookupAndListen(self, port, address, backlog,
27422752
return;
27432753
}
27442754
if (err) {
2755+
self._listening = false;
27452756
self.emit('error', err);
27462757
} else {
27472758
const validAddress = filterOnlyValidAddress(addresses);
@@ -2896,6 +2907,7 @@ Server.prototype.getConnections = function(cb) {
28962907

28972908

28982909
Server.prototype.close = function(cb) {
2910+
this._listening = false;
28992911
this._listeningId++;
29002912
if (typeof cb === 'function') {
29012913
if (!this._handle) {

‎test/parallel/test-net-listen-twice.js‎

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,12 @@ if (cluster.isPrimary) {
1111
}));
1212
} else {
1313
const server = net.createServer();
14-
server.listen();
15-
try {
16-
// Currently, we can call `listen` twice in cluster worker,
17-
// if we can not call `listen` twice in the future,
18-
// just skip this test.
19-
server.listen();
20-
} catch (e) {
21-
console.error(e);
22-
return;
23-
}
24-
let i = 0;
25-
process.on('internalMessage', (msg) => {
26-
if (msg.cmd === 'NODE_CLUSTER') {
27-
if (++i === 2) {
28-
setImmediate(() => {
29-
server.close(() => {
30-
process.disconnect();
31-
});
32-
});
33-
}
34-
}
14+
server.listen(common.mustCall(() => {
15+
server.close(() => process.disconnect());
16+
}));
17+
18+
assert.throws(() => server.listen(), {
19+
code: 'ERR_SERVER_ALREADY_LISTEN',
20+
name: 'Error'
3521
});
36-
// Must only call once
37-
server.on('listening', common.mustCall());
3822
}

‎test/parallel/test-net-server-call-listen-multiple-times.js‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,21 @@ const net = require('net');
3535
});
3636
}
3737

38-
// Third test.
38+
// Third test. Check that a second listen call throws while the first is pending.
39+
{
40+
const server = net.Server();
41+
42+
server.listen(0, '127.0.0.1');
43+
44+
assert.throws(() => server.listen(), {
45+
code: 'ERR_SERVER_ALREADY_LISTEN',
46+
name: 'Error'
47+
});
48+
49+
server.close();
50+
}
51+
52+
// Fourth test.
3953
// Check that after the close call you can run listen method just fine.
4054
{
4155
const server = net.Server();

0 commit comments

Comments
 (0)