提交 0de77399 编写于 作者: B Benjamin Pasero

find free ports: make it work, add timeout and tests

上级 9b1e364f
......@@ -11,23 +11,60 @@ import net = require('net');
* Given a start point and a max number of retries, will find a port that
* is openable. Will return 0 in case no free port can be found.
*/
export function findFreePort(startPort: number, giveUpAfter:number, clb: (port: number) => void): void {
export function findFreePort(startPort: number, giveUpAfter: number, timeout: number, clb: (port: number) => void): void {
let done = false;
const timeoutHandle = setTimeout(() =>  {
if (!done) {
done = true;
return clb(0);
}
}, timeout);
doFindFreePort(startPort, giveUpAfter, (port) => {
if (!done) {
done = true;
window.clearInterval(timeoutHandle);
return clb(port);
}
});
}
function doFindFreePort(startPort: number, giveUpAfter: number, clb: (port: number) => void): void {
if (giveUpAfter === 0) {
return clb(0);
}
let tryPort = startPort;
const client = new net.Socket();
let server = net.createServer();
server.listen(tryPort, (err) => {
server.once('close', () => {
return clb(tryPort);
});
// If we can connect to the port it means the port is already taken so we continue searching
client.once('connect', () => {
dispose(client);
server.close();
return doFindFreePort(startPort + 1, giveUpAfter - 1, clb);
});
server.on('error', (err) => {
findFreePort(startPort + 1, giveUpAfter - 1, clb);
client.once('error', (err) => {
dispose(client);
// If we receive any non ECONNREFUSED error, it means the port is used but we cannot connect
if (err.code !== 'ECONNREFUSED') {
return doFindFreePort(startPort + 1, giveUpAfter - 1, clb);
}
// Otherwise it means the port is free to use!
return clb(startPort);
});
client.connect(startPort);
}
function dispose(socket: net.Socket): void {
socket.removeAllListeners('connect');
socket.removeAllListeners('error');
socket.end();
socket.destroy();
socket.unref();
}
\ No newline at end of file
......@@ -10,18 +10,18 @@ import * as net from 'net';
import ports = require('vs/base/node/ports');
suite('Ports', () => {
test('Finds a free port', function (done: () => void) {
test('Finds a free port (no timeout)', function (done: () => void) {
// get an initial freeport >= 7000
ports.findFreePort(7000, 100, (initialPort) => {
ports.findFreePort(7000, 100, 300000, (initialPort) => {
assert.ok(initialPort >= 7000);
// create a server to block this port
const server = net.createServer();
server.listen(initialPort, null, null, () => {
server.listen(initialPort, null, null, () =>  {
// once listening, find another free port and assert that the port is different from the opened one
ports.findFreePort(7000, 50, (freePort) => {
ports.findFreePort(7000, 50, 300000, (freePort) => {
assert.ok(freePort >= 7000 && freePort !== initialPort);
server.close();
......@@ -30,4 +30,25 @@ suite('Ports', () => {
});
});
});
test('Finds a free port (with timeout)', function (done: () => void) {
// get an initial freeport >= 7000
ports.findFreePort(7000, 100, 300000, (initialPort) => {
assert.ok(initialPort >= 7000);
// create a server to block this port
const server = net.createServer();
server.listen(initialPort, null, null, () =>  {
// once listening, find another free port and assert that the port is different from the opened one
ports.findFreePort(7000, 50, 0, (freePort) => {
assert.equal(freePort, 0);
server.close();
done();
});
});
});
});
});
\ No newline at end of file
......@@ -275,7 +275,7 @@ class ExtensionHostProcessManager {
// Check for a free debugging port
if (typeof config.env.debugExtensionHostPort === 'number') {
return findFreePort(config.env.debugExtensionHostPort, 10 /* try 10 ports */, (port) => {
return findFreePort(config.env.debugExtensionHostPort, 10 /* try 10 ports */, 5000 /* try up to 5 seconds */, (port) => {
if (!port) {
console.warn('%c[Extension Host] %cCould not find a free port for debugging', 'color: blue', 'color: black');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册