Tunnels in shared process should be per remote (#135937)

Fixes microsoft/vscode-remote-release#5706
This commit is contained in:
Alex Ross 2021-10-27 11:56:34 +02:00 committed by GitHub
parent aaa4e0a341
commit ec64531d1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 48 additions and 11 deletions

View file

@ -88,8 +88,8 @@ import { IExtensionHostStarter, ipcExtensionHostStarterChannelName } from 'vs/pl
import { ExtensionHostStarter } from 'vs/platform/extensions/node/extensionHostStarter';
import { ISignService } from 'vs/platform/sign/common/sign';
import { SignService } from 'vs/platform/sign/node/signService';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { TunnelService } from 'vs/platform/remote/node/tunnelService';
import { ISharedTunnelsService } from 'vs/platform/remote/common/tunnel';
import { SharedTunnelsService } from 'vs/platform/remote/node/tunnelService';
import { ipcSharedProcessTunnelChannelName, ISharedProcessTunnelService } from 'vs/platform/remote/common/sharedProcessTunnelService';
import { SharedProcessTunnelService } from 'vs/platform/remote/node/sharedProcessTunnelService';
import { ipcSharedProcessWorkerChannelName, ISharedProcessWorkerConfiguration, ISharedProcessWorkerService } from 'vs/platform/sharedProcess/common/sharedProcessWorkerService';
@ -326,7 +326,7 @@ class SharedProcessMain extends Disposable {
services.set(ISignService, new SyncDescriptor(SignService));
// Tunnel
services.set(ITunnelService, new SyncDescriptor(TunnelService));
services.set(ISharedTunnelsService, new SyncDescriptor(SharedTunnelsService));
services.set(ISharedProcessTunnelService, new SyncDescriptor(SharedProcessTunnelService));
return new InstantiationService(services);

View file

@ -29,7 +29,7 @@ export interface ISharedProcessTunnelService {
* Start a previously created tunnel.
* Can only be called once per created tunnel.
*/
startTunnel(id: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort: number | undefined, elevateIfNeeded: boolean | undefined): Promise<ISharedProcessTunnel>;
startTunnel(authority: string, id: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort: number | undefined, elevateIfNeeded: boolean | undefined): Promise<ISharedProcessTunnel>;
/**
* Set the remote address info for a previously created tunnel.
* Should be called as often as the resolver resolves.

View file

@ -13,6 +13,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IAddressProvider } from 'vs/platform/remote/common/remoteAgentConnection';
export const ITunnelService = createDecorator<ITunnelService>('tunnelService');
export const ISharedTunnelsService = createDecorator<ISharedTunnelsService>('sharedTunnelsService');
export interface RemoteTunnel {
readonly tunnelRemotePort: number;
@ -110,6 +111,12 @@ export interface ITunnel {
dispose(): Promise<void> | void;
}
export interface ISharedTunnelsService {
readonly _serviceBrand: undefined;
openTunnel(authority: string, addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined;
}
export interface ITunnelService {
readonly _serviceBrand: undefined;

View file

@ -5,7 +5,7 @@
import { ILogService } from 'vs/platform/log/common/log';
import { ISharedProcessTunnel, ISharedProcessTunnelService } from 'vs/platform/remote/common/sharedProcessTunnelService';
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
import { ISharedTunnelsService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
import { IAddress, IAddressProvider } from 'vs/platform/remote/common/remoteAgentConnection';
import { Disposable } from 'vs/base/common/lifecycle';
import { canceled } from 'vs/base/common/errors';
@ -55,7 +55,7 @@ export class SharedProcessTunnelService extends Disposable implements ISharedPro
private readonly _disposedTunnels: Set<string> = new Set<string>();
constructor(
@ITunnelService private readonly _tunnelService: ITunnelService,
@ISharedTunnelsService private readonly _tunnelService: ISharedTunnelsService,
@ILogService private readonly _logService: ILogService,
) {
super();
@ -71,10 +71,10 @@ export class SharedProcessTunnelService extends Disposable implements ISharedPro
return { id };
}
async startTunnel(id: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort: number | undefined, elevateIfNeeded: boolean | undefined): Promise<ISharedProcessTunnel> {
async startTunnel(authority: string, id: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort: number | undefined, elevateIfNeeded: boolean | undefined): Promise<ISharedProcessTunnel> {
const tunnelData = new TunnelData();
const tunnel = await Promise.resolve(this._tunnelService.openTunnel(tunnelData, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort, elevateIfNeeded));
const tunnel = await Promise.resolve(this._tunnelService.openTunnel(authority, tunnelData, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort, elevateIfNeeded));
if (!tunnel) {
this._logService.info(`[SharedProcessTunnelService] Could not create a tunnel to ${tunnelRemoteHost}:${tunnelRemotePort} (remote).`);
tunnelData.dispose();

View file

@ -14,7 +14,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { connectRemoteAgentTunnel, IAddressProvider, IConnectionOptions, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection';
import { AbstractTunnelService, isAllInterfaces, isLocalhost, RemoteTunnel, TunnelPrivacyId } from 'vs/platform/remote/common/tunnel';
import { AbstractTunnelService, isAllInterfaces, ISharedTunnelsService as ISharedTunnelsService, isLocalhost, ITunnelService, RemoteTunnel, TunnelPrivacyId } from 'vs/platform/remote/common/tunnel';
import { ISignService } from 'vs/platform/sign/common/sign';
async function createRemoteTunnel(options: IConnectionOptions, defaultTunnelHost: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort?: number): Promise<RemoteTunnel> {
@ -189,3 +189,33 @@ export class TunnelService extends BaseTunnelService {
super(nodeSocketFactory, logService, signService, productService, configurationService);
}
}
export class SharedTunnelsService extends Disposable implements ISharedTunnelsService {
declare readonly _serviceBrand: undefined;
private readonly _tunnelServices: Map<string, ITunnelService> = new Map();
public constructor(
@ILogService protected readonly logService: ILogService,
@IProductService private readonly productService: IProductService,
@ISignService private readonly signService: ISignService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super();
}
async openTunnel(authority: string, addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> {
this.logService.trace(`ForwardedPorts: (SharedTunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`);
if (!this._tunnelServices.has(authority)) {
const tunnelService = new TunnelService(this.logService, this.signService, this.productService, this.configurationService);
this._register(tunnelService);
this._tunnelServices.set(authority, tunnelService);
tunnelService.onTunnelClosed(async () => {
if ((await tunnelService.tunnels).length === 0) {
tunnelService.dispose();
this._tunnelServices.delete(authority);
}
});
}
return this._tunnelServices.get(authority)!.openTunnel(addressProvider, remoteHost, remotePort, localPort, elevateIfNeeded, privacy, protocol);
}
}

View file

@ -92,8 +92,8 @@ export class TunnelService extends AbstractTunnelService {
private async _createSharedProcessTunnel(addressProvider: IAddressProvider, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort: number | undefined, elevateIfNeeded: boolean | undefined): Promise<RemoteTunnel> {
const { id } = await this._sharedProcessTunnelService.createTunnel();
this._activeSharedProcessTunnels.add(id);
const result = await this._sharedProcessTunnelService.startTunnel(id, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort, elevateIfNeeded);
const authority = this._environmentService.remoteAuthority!;
const result = await this._sharedProcessTunnelService.startTunnel(authority, id, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort, elevateIfNeeded);
const tunnel = this._instantiationService.createInstance(SharedProcessTunnel, id, addressProvider, tunnelRemoteHost, tunnelRemotePort, result.tunnelLocalPort, result.localAddress, () => {
this._activeSharedProcessTunnels.delete(id);
});