blob: 104ae74f5e8c662fd92c229c53ca84bebb6125e1 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'sl4f_client.dart';
/// `TcpProxyController` is a utility for host-driven tests that need to access ports on a DUT that
/// only permit localhost connections.
///
/// `TcpProxyController` opens ports that are accessible from the host and tunnels connections from
/// the open ports to the restricted ports. Example use cases include access to Webdriver and
/// Flutter debug ports.
///
/// Note that unlike ssh port forwarding, the accessible ports are located on the DUT, rather than
/// on the host.
class TcpProxyController {
final Sl4f _sl4f;
int _nextPortIndex = 0;
/// The pool of ports to use that are explicitly forwarded by the user. These
/// are drained in FIFO order for every [openProxy] call.
final List<int> proxyPorts;
TcpProxyController(this._sl4f, {this.proxyPorts = const <int>[]});
/// Open a tunnel to [targetPort] on the DUT.
///
/// Returns the port on the DUT through which the tunnel is accessible.
Future<int> openProxy(int targetPort) async => await _sl4f
.request('proxy_facade.OpenProxy', [targetPort, _nextProxyPort()]);
/// Stop a tunnel to [targetPort] on the DUT.
///
/// In case that n requests were made to open the proxy, the proxy is closed only after n calls
/// to dropProxy with [targetPort] are made.
Future<void> dropProxy(int targetPort) async =>
await _sl4f.request('proxy_facade.DropProxy', targetPort);
/// Forcibly terminate all proxies.
///
/// Terminates all proxies, ignoring the number of clients that requested proxies.
/// This method is intended for cleanup after a test only.
Future<void> stopAllProxies() async =>
await _sl4f.request('proxy_facade.StopAllProxies');
// Returns the next proxy port from the list of ports provided during
// construction. If no ports where provided, or `_nextPortIndex` is out of
// range, it returns 0.
int _nextProxyPort() {
if (_nextPortIndex < proxyPorts.length) {
return proxyPorts[_nextPortIndex++];
} else {
if (proxyPorts.isNotEmpty) {
// Halt the test and notify the user that they ran out of proxy ports.
throw SocketException('Tcp proxy ran out of ports.');
}
return 0;
}
}
}