Skip to content

Commit a949bf8

Browse files
committed
Fix crash when trying to forward two ports to the same port
Also change error to warn so that it doesn't show in the console Fixes microsoft#89419
1 parent fecf73f commit a949bf8

2 files changed

Lines changed: 23 additions & 5 deletions

File tree

src/vs/workbench/contrib/remote/browser/tunnelView.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ namespace ForwardPortAction {
680680

681681
function error(notificationService: INotificationService, tunnel: RemoteTunnel | void, host: string, port: number) {
682682
if (!tunnel) {
683-
notificationService.error(nls.localize('remote.tunnel.forwardError', "Unable to forward {0}:{1}. The host may not be available.", host, port));
683+
notificationService.warn(nls.localize('remote.tunnel.forwardError', "Unable to forward {0}:{1}. The host may not be available or that remote port may already be forwarded", host, port));
684684
}
685685
}
686686

@@ -865,14 +865,19 @@ namespace ChangeLocalPortAction {
865865
export function handler(): ICommandHandler {
866866
return async (accessor, arg) => {
867867
const remoteExplorerService = accessor.get(IRemoteExplorerService);
868+
const notificationService = accessor.get(INotificationService);
868869
const context = (arg !== undefined || arg instanceof TunnelItem) ? arg : accessor.get(IContextKeyService).getContextKeyValue(TunnelViewSelectionKeyName);
869870
if (context instanceof TunnelItem) {
870871
remoteExplorerService.setEditable(context, {
871872
onFinish: async (value, success) => {
872873
remoteExplorerService.setEditable(context, null);
873874
if (success) {
874875
await remoteExplorerService.close({ host: context.remoteHost, port: context.remotePort });
875-
await remoteExplorerService.forward({ host: context.remoteHost, port: context.remotePort }, Number(value));
876+
const numberValue = Number(value);
877+
const newForward = await remoteExplorerService.forward({ host: context.remoteHost, port: context.remotePort }, numberValue);
878+
if (newForward && newForward.tunnelLocalPort !== numberValue) {
879+
notificationService.warn(nls.localize('remote.tunnel.changeLocalPortNumber', "The local port {0} is not available. Port number {1} has been used instead", value, newForward.tunnelLocalPort));
880+
}
876881
}
877882
},
878883
validationMessage: validateInput,

src/vs/workbench/services/remote/node/tunnelService.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel {
3737

3838
private readonly _listeningListener: () => void;
3939
private readonly _connectionListener: (socket: net.Socket) => void;
40+
private readonly _errorListener: () => void;
4041

4142
constructor(options: IConnectionOptions, tunnelRemoteHost: string, tunnelRemotePort: number, private readonly suggestedLocalPort?: number) {
4243
super();
@@ -50,6 +51,10 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel {
5051
this._connectionListener = (socket) => this._onConnection(socket);
5152
this._server.on('connection', this._connectionListener);
5253

54+
// If there is no error listener and there is an error it will crash the whole window
55+
this._errorListener = () => { };
56+
this._server.on('error', this._errorListener);
57+
5358
this.tunnelRemotePort = tunnelRemotePort;
5459
this.tunnelRemoteHost = tunnelRemoteHost;
5560
}
@@ -58,16 +63,24 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel {
5863
super.dispose();
5964
this._server.removeListener('listening', this._listeningListener);
6065
this._server.removeListener('connection', this._connectionListener);
66+
this._server.removeListener('error', this._errorListener);
6167
this._server.close();
6268
}
6369

6470
public async waitForReady(): Promise<this> {
65-
6671
// try to get the same port number as the remote port number...
67-
const localPort = await findFreePortFaster(this.suggestedLocalPort ?? this.tunnelRemotePort, 2, 1000);
72+
let localPort = await findFreePortFaster(this.suggestedLocalPort ?? this.tunnelRemotePort, 2, 1000);
6873

6974
// if that fails, the method above returns 0, which works out fine below...
70-
const address = (<net.AddressInfo>this._server.listen(localPort).address());
75+
let address: string | net.AddressInfo | null = null;
76+
address = (<net.AddressInfo>this._server.listen(localPort).address());
77+
78+
// It is possible for findFreePortFaster to return a port that there is already a server listening on. This causes the previous listen call to error out.
79+
if (!address) {
80+
localPort = 0;
81+
address = (<net.AddressInfo>this._server.listen(localPort).address());
82+
}
83+
7184
this.tunnelLocalPort = address.port;
7285

7386
await this._barrier.wait();

0 commit comments

Comments
 (0)