Skip to content

Commit 0c46676

Browse files
committed
net: throw on multiple listen calls
Signed-off-by: Matteo Collina <hello@matteocollina.com>
1 parent 29d183d commit 0c46676

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
@@ -2189,6 +2189,7 @@ function Server(options, connectionListener) {
21892189

21902190
this[async_id_symbol] = -1;
21912191
this._handle = null;
2192+
this._listening = false;
21922193
this._usingWorkers = false;
21932194
this._workers = [];
21942195
this._unref = false;
@@ -2389,6 +2390,7 @@ Server.prototype[kTransfer] = function() {
23892390
};
23902391
// Detach so the source server no longer references the handle being moved.
23912392
this._handle = null;
2393+
this._listening = false;
23922394
return {
23932395
data,
23942396
deserializeInfo: 'net:Server',
@@ -2412,6 +2414,7 @@ Server.prototype[kDeserialize] = function(data) {
24122414
};
24132415

24142416
function emitErrorNT(self, err) {
2417+
self._listening = false;
24152418
self.emit('error', err);
24162419
}
24172420

@@ -2458,6 +2461,7 @@ function listenInCluster(server, address, port, addressType,
24582461

24592462
if (err) {
24602463
const ex = new ExceptionWithHostPort(err, 'bind', address, port);
2464+
server._listening = false;
24612465
return server.emit('error', ex);
24622466
}
24632467
// If there was a handle, just close it to avoid fd leak
@@ -2479,7 +2483,7 @@ Server.prototype.listen = function(...args) {
24792483
let options = normalized[0];
24802484
const cb = normalized[1];
24812485

2482-
if (this._handle) {
2486+
if (this._handle || this._listening) {
24832487
throw new ERR_SERVER_ALREADY_LISTEN();
24842488
}
24852489

@@ -2511,6 +2515,7 @@ Server.prototype.listen = function(...args) {
25112515
this._pipeName = boundPath;
25122516
}
25132517
this[async_id_symbol] = this._handle.getAsyncId();
2518+
this._listening = true;
25142519
this._listeningId++;
25152520
listenInCluster(this, null, -1, -1, backlogFromArgs, undefined, true);
25162521
return this;
@@ -2523,12 +2528,14 @@ Server.prototype.listen = function(...args) {
25232528
if (options instanceof TCP) {
25242529
this._handle = options;
25252530
this[async_id_symbol] = this._handle.getAsyncId();
2531+
this._listening = true;
25262532
listenInCluster(this, null, -1, -1, backlogFromArgs, undefined, true);
25272533
return this;
25282534
}
25292535
addServerAbortSignalOption(this, options);
25302536
// (handle[, backlog][, cb]) where handle is an object with a fd
25312537
if (typeof options.fd === 'number' && options.fd >= 0) {
2538+
this._listening = true;
25322539
listenInCluster(this, null, null, null, backlogFromArgs, options.fd);
25332540
return this;
25342541
}
@@ -2553,6 +2560,7 @@ Server.prototype.listen = function(...args) {
25532560
options.exclusive = true;
25542561
}
25552562
// start TCP server listening on host:port
2563+
this._listening = true;
25562564
if (options.host) {
25572565
lookupAndListen(this, options.port | 0, options.host, backlog,
25582566
options.exclusive, flags);
@@ -2575,6 +2583,7 @@ Server.prototype.listen = function(...args) {
25752583
}
25762584
const pipeName = this._pipeName = options.path;
25772585
backlog = options.backlog || backlogFromArgs;
2586+
this._listening = true;
25782587
listenInCluster(this,
25792588
pipeName,
25802589
-1,
@@ -2604,6 +2613,7 @@ Server.prototype.listen = function(...args) {
26042613
if (err) {
26052614
this._handle.close();
26062615
this._handle = null;
2616+
this._listening = false;
26072617
throw new ErrnoException(err, 'uv_pipe_chmod');
26082618
}
26092619
}
@@ -2657,6 +2667,7 @@ function lookupAndListen(self, port, address, backlog,
26572667
return;
26582668
}
26592669
if (err) {
2670+
self._listening = false;
26602671
self.emit('error', err);
26612672
} else {
26622673
const validAddress = filterOnlyValidAddress(addresses);
@@ -2811,6 +2822,7 @@ Server.prototype.getConnections = function(cb) {
28112822

28122823

28132824
Server.prototype.close = function(cb) {
2825+
this._listening = false;
28142826
this._listeningId++;
28152827
if (typeof cb === 'function') {
28162828
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)