diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index f73bf4a364..3232289e0b 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -1443,6 +1443,8 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_ILLEGAL_CONSTRUCTOR, "Illegal constructor"_s)); case ErrorCode::ERR_DIR_CLOSED: return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_DIR_CLOSED, "Directory handle was closed"_s)); + case ErrorCode::ERR_SERVER_ALREADY_LISTEN: + return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_SERVER_ALREADY_LISTEN, "Listen method has been called more than once without closing."_s)); default: { break; diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index 44f5bc0fb2..bc10108830 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -83,6 +83,7 @@ const errors: ErrorCodeMapping = [ ["ERR_ZLIB_INITIALIZATION_FAILED", Error], ["ERR_INVALID_CHAR", TypeError], ["MODULE_NOT_FOUND", Error], + ["ERR_SERVER_ALREADY_LISTEN", Error], // Bun-specific ["ERR_FORMDATA_PARSE_ERROR", TypeError], diff --git a/src/js/builtins.d.ts b/src/js/builtins.d.ts index 84fe64551a..5ed0037ed2 100644 --- a/src/js/builtins.d.ts +++ b/src/js/builtins.d.ts @@ -629,6 +629,7 @@ declare function $ERR_STREAM_UNSHIFT_AFTER_END_EVENT(): Error; declare function $ERR_STREAM_PUSH_AFTER_EOF(): Error; declare function $ERR_STREAM_UNABLE_TO_PIPE(): Error; declare function $ERR_ILLEGAL_CONSTRUCTOR(): TypeError; +declare function $ERR_SERVER_ALREADY_LISTEN(): Error; /** * Convert a function to a class-like object. diff --git a/src/js/node/net.ts b/src/js/node/net.ts index 777fb2807d..eb4508c45d 100644 --- a/src/js/node/net.ts +++ b/src/js/node/net.ts @@ -1403,6 +1403,10 @@ Server.prototype.listen = function listen(port, hostname, onListen) { hostname = hostname || "::"; } + if (this._handle) { + throw $ERR_SERVER_ALREADY_LISTEN(); + } + try { var tls = undefined; var TLSSocketClass = undefined; diff --git a/test/js/node/test/parallel/test-net-server-call-listen-multiple-times.js b/test/js/node/test/parallel/test-net-server-call-listen-multiple-times.js new file mode 100644 index 0000000000..e757c6c247 --- /dev/null +++ b/test/js/node/test/parallel/test-net-server-call-listen-multiple-times.js @@ -0,0 +1,47 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +// First test. Check that after error event you can listen right away. +{ + const dummyServer = net.Server(); + const server = 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 = 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 = net.Server(); + + server.listen(common.mustCall(() => { + server.close(); + server.listen(common.mustCall(() => server.close())); + })); +}