mirror of
https://github.com/nestriness/cdc-file-transfer.git
synced 2026-05-01 17:03:07 +03:00
[cdc_rsync] Use ephemeral port on client (#96)
Instead of calling netstat locally to find out available ports in a tight range, call bind() with port zero to find an available ephemeral port. This is faster and much simpler, and will eventually help getting rid of PortManager. Also fixes issues with running SSH commands on Windows when the remote shell is Powershell (aka Backslash Bingo).
This commit is contained in:
@@ -71,9 +71,9 @@ cc_library(
|
||||
"//common:path",
|
||||
"//common:path_filter",
|
||||
"//common:platform",
|
||||
"//common:port_manager",
|
||||
"//common:process",
|
||||
"//common:remote_util",
|
||||
"//common:server_socket",
|
||||
"//common:socket",
|
||||
"//common:status",
|
||||
"//common:status_macros",
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include "common/gamelet_component.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
#include "common/port_manager.h"
|
||||
#include "common/process.h"
|
||||
#include "common/remote_util.h"
|
||||
#include "common/server_socket.h"
|
||||
#include "common/status.h"
|
||||
#include "common/status_macros.h"
|
||||
#include "common/stopwatch.h"
|
||||
@@ -113,12 +113,6 @@ CdcRsyncClient::CdcRsyncClient(const Options& options,
|
||||
remote_util_->SetSftpCommand(options_.sftp_command);
|
||||
}
|
||||
}
|
||||
|
||||
// Note that remote_util_.get() may be null.
|
||||
port_manager_ = std::make_unique<PortManager>(
|
||||
"cdc_rsync_ports_f77bcdfe-368c-4c45-9f01-230c5e7e2132",
|
||||
options.forward_port_first, options.forward_port_last, &process_factory_,
|
||||
nullptr /* never reserve remote ports */);
|
||||
}
|
||||
|
||||
CdcRsyncClient::~CdcRsyncClient() {
|
||||
@@ -288,22 +282,15 @@ absl::Status CdcRsyncClient::StartServer(const ServerArch& arch) {
|
||||
return SetTag(MakeStatus("Redeploy server"), Tag::kDeployServer);
|
||||
}
|
||||
|
||||
// Start up sockets.
|
||||
RETURN_IF_ERROR(Socket::Initialize(), "Failed to initialize sockets");
|
||||
socket_finalizer_ = std::make_unique<SocketFinalizer>();
|
||||
|
||||
// Now that we know which port the server is using, set up port forwarding.
|
||||
std::unique_ptr<Process> fwd_process;
|
||||
int local_port = server_listen_port_;
|
||||
if (IsRemoteConnection()) {
|
||||
absl::StatusOr<int> local_port_or = port_manager_->ReservePort(
|
||||
options_.connection_timeout_sec, arch.GetType());
|
||||
|
||||
if (absl::IsResourceExhausted(local_port_or.status())) {
|
||||
// Port in use.
|
||||
return SetTag(local_port_or.status(), Tag::kAddressInUse);
|
||||
}
|
||||
if (!local_port_or.ok()) {
|
||||
return local_port_or.status();
|
||||
}
|
||||
|
||||
local_port = *local_port_or;
|
||||
ASSIGN_OR_RETURN(local_port, ServerSocket::FindAvailablePort());
|
||||
ProcessStartInfo start_info =
|
||||
remote_util_->BuildProcessStartInfoForSshPortForward(
|
||||
local_port, server_listen_port_, /*reverse=*/false);
|
||||
@@ -313,14 +300,8 @@ absl::Status CdcRsyncClient::StartServer(const ServerArch& arch) {
|
||||
"Failed to start cdc_rsync_server process");
|
||||
}
|
||||
|
||||
// Connect to the socket with port |local_port|.
|
||||
status = Socket::Initialize();
|
||||
if (!status.ok()) {
|
||||
return WrapStatus(status, "Failed to initialize sockets");
|
||||
}
|
||||
socket_finalizer_ = std::make_unique<SocketFinalizer>();
|
||||
|
||||
// Poll until the port forwarding connection is set up.
|
||||
// Poll the connection to the socket with port |local_port| until the port
|
||||
// forwarding connection is set up.
|
||||
timeout_timer.Reset();
|
||||
for (;;) {
|
||||
assert(local_port != 0);
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
namespace cdc_ft {
|
||||
|
||||
class PortManager;
|
||||
class Process;
|
||||
class RemoteUtil;
|
||||
class ServerArch;
|
||||
@@ -53,8 +52,6 @@ class CdcRsyncClient {
|
||||
std::string copy_dest;
|
||||
int compress_level = 6;
|
||||
int connection_timeout_sec = 10;
|
||||
int forward_port_first = 44450;
|
||||
int forward_port_last = 44459;
|
||||
std::string ssh_command;
|
||||
std::string sftp_command;
|
||||
std::string sources_dir; // Base dir for files loaded for --files-from.
|
||||
@@ -132,7 +129,6 @@ class CdcRsyncClient {
|
||||
const std::string destination_;
|
||||
WinProcessFactory process_factory_;
|
||||
std::unique_ptr<RemoteUtil> remote_util_;
|
||||
std::unique_ptr<PortManager> port_manager_;
|
||||
std::unique_ptr<SocketFinalizer> socket_finalizer_;
|
||||
ClientSocket socket_;
|
||||
MessagePump message_pump_{&socket_, MessagePump::PacketReceivedDelegate()};
|
||||
|
||||
@@ -80,8 +80,6 @@ Options:
|
||||
--sftp-command <cmd> Path and arguments of sftp command to use, e.g.
|
||||
"C:\path\to\sftp.exe -P 12345 -i id_rsa -oUserKnownHostsFile=known_hosts"
|
||||
Can also be specified by the CDC_SFTP_COMMAND environment variable.
|
||||
--forward-port <port> TCP port or range used for SSH port forwarding (default: 44450-44459).
|
||||
If a range is specified, searches for available ports (slower).
|
||||
-h, --help Help for cdc_rsync
|
||||
)";
|
||||
|
||||
@@ -305,15 +303,9 @@ OptionResult HandleParameter(const std::string& key, const char* value,
|
||||
}
|
||||
|
||||
if (key == "forward-port") {
|
||||
if (!ValidateValue(key, value)) return OptionResult::kError;
|
||||
uint16_t first, last;
|
||||
if (!port_range::Parse(value, &first, &last)) {
|
||||
PrintError("Failed to parse %s=%s, expected <port> or <port1>-<port2>",
|
||||
key, value);
|
||||
return OptionResult::kError;
|
||||
}
|
||||
params->options.forward_port_first = first;
|
||||
params->options.forward_port_last = last;
|
||||
// This param is no longer needed. Just print a warning for backwards
|
||||
// compatibility.
|
||||
std::cout << "--forward-port argument no longer needed" << std::endl;
|
||||
return OptionResult::kConsumedKeyValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -585,40 +585,6 @@ TEST_F(ParamsTest, IncludeExcludeMixed_ProperOrder) {
|
||||
ExpectNoError();
|
||||
}
|
||||
|
||||
TEST_F(ParamsTest, ForwardPort_Single) {
|
||||
const char* argv[] = {"cdc_rsync.exe", "--forward-port=65535", kSrc,
|
||||
kUserHostDst, NULL};
|
||||
EXPECT_TRUE(Parse(static_cast<int>(std::size(argv)) - 1, argv, ¶meters_));
|
||||
EXPECT_EQ(parameters_.options.forward_port_first, 65535);
|
||||
EXPECT_EQ(parameters_.options.forward_port_last, 65535);
|
||||
ExpectNoError();
|
||||
}
|
||||
|
||||
TEST_F(ParamsTest, ForwardPort_Range) {
|
||||
const char* argv[] = {
|
||||
"cdc_rsync.exe", "--forward-port", "1-2", kSrc, kUserHostDst, NULL};
|
||||
EXPECT_TRUE(Parse(static_cast<int>(std::size(argv)) - 1, argv, ¶meters_));
|
||||
EXPECT_EQ(parameters_.options.forward_port_first, 1);
|
||||
EXPECT_EQ(parameters_.options.forward_port_last, 2);
|
||||
ExpectNoError();
|
||||
}
|
||||
|
||||
TEST_F(ParamsTest, ForwardPort_NoValue) {
|
||||
const char* argv[] = {"cdc_rsync.exe", "--forward-port=", kSrc, kUserHostDst,
|
||||
NULL};
|
||||
EXPECT_FALSE(
|
||||
Parse(static_cast<int>(std::size(argv)) - 1, argv, ¶meters_));
|
||||
ExpectError(NeedsValueError("forward-port"));
|
||||
}
|
||||
|
||||
TEST_F(ParamsTest, ForwardPort_BadValueTooSmall) {
|
||||
const char* argv[] = {"cdc_rsync.exe", "--forward-port=0", kSrc, kUserHostDst,
|
||||
NULL};
|
||||
EXPECT_FALSE(
|
||||
Parse(static_cast<int>(std::size(argv)) - 1, argv, ¶meters_));
|
||||
ExpectError("Failed to parse");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace params
|
||||
} // namespace cdc_ft
|
||||
|
||||
@@ -147,8 +147,7 @@ absl::StatusOr<ServerArch> ServerArch::DetectFromRemoteDevice(
|
||||
// Note: That space after PROCESSOR_ARCHITECTURE is important or else Windows
|
||||
// command magic interprets quotes as part of the string.
|
||||
std::string arch_out;
|
||||
std::string windows_cmd =
|
||||
RemoteUtil::QuoteForSsh("cmd /C set PROCESSOR_ARCHITECTURE ");
|
||||
std::string windows_cmd = "\"cmd /C set PROCESSOR_ARCHITECTURE \"";
|
||||
status = remote_util->RunWithCapture(windows_cmd,
|
||||
"set PROCESSOR_ARCHITECTURE", &arch_out,
|
||||
nullptr, ArchType::kWindows_x86_64);
|
||||
@@ -223,14 +222,13 @@ std::string ServerArch::GetStartServerCommand(int exit_code_not_found,
|
||||
// a minor issue and means we display "Deploying server..." instead of
|
||||
// "Server not deployed. Deploying...";
|
||||
return RemoteUtil::QuoteForWindows(
|
||||
absl::StrFormat("powershell -Command \" "
|
||||
absl::StrFormat("powershell -Command "
|
||||
"Set-StrictMode -Version 2; "
|
||||
"$ErrorActionPreference = 'Stop'; "
|
||||
"if (-not (Test-Path -Path '%s')) { "
|
||||
" exit %i; "
|
||||
"} "
|
||||
"%s %s "
|
||||
"\"",
|
||||
"%s %s",
|
||||
server_path, exit_code_not_found, server_path, args));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user