Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/util/vs/base/node/ports.ts
13405 views
1
//!!! DO NOT modify, this file was COPIED from 'microsoft/vscode'
2
3
/*---------------------------------------------------------------------------------------------
4
* Copyright (c) Microsoft Corporation. All rights reserved.
5
* Licensed under the MIT License. See License.txt in the project root for license information.
6
*--------------------------------------------------------------------------------------------*/
7
8
import * as net from 'net';
9
10
/**
11
* Given a start point and a max number of retries, will find a port that
12
* is openable. Will return 0 in case no free port can be found.
13
*/
14
export function findFreePort(startPort: number, giveUpAfter: number, timeout: number, stride = 1): Promise<number> {
15
let done = false;
16
17
return new Promise(resolve => {
18
const timeoutHandle = setTimeout(() => {
19
if (!done) {
20
done = true;
21
return resolve(0);
22
}
23
}, timeout);
24
25
doFindFreePort(startPort, giveUpAfter, stride, (port) => {
26
if (!done) {
27
done = true;
28
clearTimeout(timeoutHandle);
29
return resolve(port);
30
}
31
});
32
});
33
}
34
35
function doFindFreePort(startPort: number, giveUpAfter: number, stride: number, clb: (port: number) => void): void {
36
if (giveUpAfter === 0) {
37
return clb(0);
38
}
39
40
const client = new net.Socket();
41
42
// If we can connect to the port it means the port is already taken so we continue searching
43
client.once('connect', () => {
44
dispose(client);
45
46
return doFindFreePort(startPort + stride, giveUpAfter - 1, stride, clb);
47
});
48
49
client.once('data', () => {
50
// this listener is required since node.js 8.x
51
});
52
53
client.once('error', (err: Error & { code?: string }) => {
54
dispose(client);
55
56
// If we receive any non ECONNREFUSED error, it means the port is used but we cannot connect
57
if (err.code !== 'ECONNREFUSED') {
58
return doFindFreePort(startPort + stride, giveUpAfter - 1, stride, clb);
59
}
60
61
// Otherwise it means the port is free to use!
62
return clb(startPort);
63
});
64
65
client.connect(startPort, '127.0.0.1');
66
}
67
68
// Reference: https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/net/base/port_util.cc#56
69
export const BROWSER_RESTRICTED_PORTS: Record<number, boolean> = {
70
1: true, // tcpmux
71
7: true, // echo
72
9: true, // discard
73
11: true, // systat
74
13: true, // daytime
75
15: true, // netstat
76
17: true, // qotd
77
19: true, // chargen
78
20: true, // ftp data
79
21: true, // ftp access
80
22: true, // ssh
81
23: true, // telnet
82
25: true, // smtp
83
37: true, // time
84
42: true, // name
85
43: true, // nicname
86
53: true, // domain
87
69: true, // tftp
88
77: true, // priv-rjs
89
79: true, // finger
90
87: true, // ttylink
91
95: true, // supdup
92
101: true, // hostriame
93
102: true, // iso-tsap
94
103: true, // gppitnp
95
104: true, // acr-nema
96
109: true, // pop2
97
110: true, // pop3
98
111: true, // sunrpc
99
113: true, // auth
100
115: true, // sftp
101
117: true, // uucp-path
102
119: true, // nntp
103
123: true, // NTP
104
135: true, // loc-srv /epmap
105
137: true, // netbios
106
139: true, // netbios
107
143: true, // imap2
108
161: true, // snmp
109
179: true, // BGP
110
389: true, // ldap
111
427: true, // SLP (Also used by Apple Filing Protocol)
112
465: true, // smtp+ssl
113
512: true, // print / exec
114
513: true, // login
115
514: true, // shell
116
515: true, // printer
117
526: true, // tempo
118
530: true, // courier
119
531: true, // chat
120
532: true, // netnews
121
540: true, // uucp
122
548: true, // AFP (Apple Filing Protocol)
123
554: true, // rtsp
124
556: true, // remotefs
125
563: true, // nntp+ssl
126
587: true, // smtp (rfc6409)
127
601: true, // syslog-conn (rfc3195)
128
636: true, // ldap+ssl
129
989: true, // ftps-data
130
990: true, // ftps
131
993: true, // ldap+ssl
132
995: true, // pop3+ssl
133
1719: true, // h323gatestat
134
1720: true, // h323hostcall
135
1723: true, // pptp
136
2049: true, // nfs
137
3659: true, // apple-sasl / PasswordServer
138
4045: true, // lockd
139
5060: true, // sip
140
5061: true, // sips
141
6000: true, // X11
142
6566: true, // sane-port
143
6665: true, // Alternate IRC [Apple addition]
144
6666: true, // Alternate IRC [Apple addition]
145
6667: true, // Standard IRC [Apple addition]
146
6668: true, // Alternate IRC [Apple addition]
147
6669: true, // Alternate IRC [Apple addition]
148
6697: true, // IRC + TLS
149
10080: true // Amanda
150
};
151
152
export function isPortFree(port: number, timeout: number): Promise<boolean> {
153
return findFreePortFaster(port, 0, timeout).then(port => port !== 0);
154
}
155
156
interface ServerError {
157
code?: string;
158
}
159
160
/**
161
* Uses listen instead of connect. Is faster, but if there is another listener on 0.0.0.0 then this will take 127.0.0.1 from that listener.
162
*/
163
export function findFreePortFaster(startPort: number, giveUpAfter: number, timeout: number, hostname: string = '127.0.0.1'): Promise<number> {
164
let resolved: boolean = false;
165
let timeoutHandle: Timeout | undefined = undefined;
166
let countTried: number = 1;
167
const server = net.createServer({ pauseOnConnect: true });
168
function doResolve(port: number, resolve: (port: number) => void) {
169
if (!resolved) {
170
resolved = true;
171
server.removeAllListeners();
172
server.close();
173
if (timeoutHandle) {
174
clearTimeout(timeoutHandle);
175
}
176
resolve(port);
177
}
178
}
179
return new Promise<number>(resolve => {
180
timeoutHandle = setTimeout(() => {
181
doResolve(0, resolve);
182
}, timeout);
183
184
server.on('listening', () => {
185
doResolve(startPort, resolve);
186
});
187
server.on('error', (err: ServerError) => {
188
if (err && (err.code === 'EADDRINUSE' || err.code === 'EACCES') && (countTried < giveUpAfter)) {
189
startPort++;
190
countTried++;
191
server.listen(startPort, hostname);
192
} else {
193
doResolve(0, resolve);
194
}
195
});
196
server.on('close', () => {
197
doResolve(0, resolve);
198
});
199
server.listen(startPort, hostname);
200
});
201
}
202
203
function dispose(socket: net.Socket): void {
204
try {
205
socket.removeAllListeners('connect');
206
socket.removeAllListeners('error');
207
socket.end();
208
socket.destroy();
209
socket.unref();
210
} catch (error) {
211
console.error(error); // otherwise this error would get lost in the callback chain
212
}
213
}
214
215