[cdc_rsync] Detect remote architecture (#86)

Improves ServerArch so that it can detect the remote architecture by
running uname and checking %PROCESSOR_ARCHITECTURE%. So far, only
x64 Linux and x64 Windows are supported, but in the future it is easy
to add support for others, e.g. aarch64, as well.

Before the detection is run, the remote architecture is guessed first
based on the destination. For instance, if the destination directory
starts with "C:\", it pretty much means Windows. If cdc_rsync_server
exists and runs fine, there's no need for detection.

Since also PortManager depends on the remote architecture, it has to
be adjusted as well. So far, PortManager assumeed that "local" means
Windows and "remote" means Linux. This is no longer the case for
syncing to Windows devices, so this CL adds the necessary abstractions
to PortManager.

Also refactors ArchType into a separate class in common, since it is
used now from several places. It is also expanded to handle future
changes that add support for different processor architectures, e.g.
aarch64.
This commit is contained in:
Lutz Justen
2023-02-01 11:51:20 +01:00
committed by GitHub
parent 3194678007
commit ee4118c6bf
19 changed files with 696 additions and 228 deletions
+45 -9
View File
@@ -127,16 +127,35 @@ CdcRsyncClient::~CdcRsyncClient() {
}
absl::Status CdcRsyncClient::Run() {
int port;
ASSIGN_OR_RETURN(port, FindAvailablePort(), "Failed to find available port");
// If |remote_util_| is not set, it's a local sync. Otherwise, guess the
// architecture of the device that runs cdc_rsync_server from the destination
// path, e.g. "C:\path\to\dest" strongly indicates Windows.
ServerArch server_arch = !remote_util_
? ServerArch::DetectFromLocalDevice()
: ServerArch::GuessFromDestination(destination_);
// If |remote_util_| is not set, it's a local sync.
ServerArch::Type arch_type =
remote_util_ ? ServerArch::Detect(destination_) : ServerArch::LocalType();
ServerArch server_arch(arch_type);
int port;
ASSIGN_OR_RETURN(port, FindAvailablePort(&server_arch),
"Failed to find available port");
// Start the server process.
absl::Status status = StartServer(port, server_arch);
if (HasTag(status, Tag::kDeployServer) && server_arch.IsGuess() &&
server_exit_code_ != kServerExitCodeOutOfDate) {
// Server couldn't be run, e.g. not found or failed to start.
// Check whether we guessed the arch type wrong and try again.
// Note that in case of a local sync, or if the server actively reported
// that it's out-dated, there's no need to detect the arch.
const ArchType old_type = server_arch.GetType();
ASSIGN_OR_RETURN(server_arch,
ServerArch::DetectFromRemoteDevice(remote_util_.get()));
if (server_arch.GetType() != old_type) {
LOG_DEBUG("Guessed server arch type wrong, guessed %s, actual %s.",
GetArchTypeStr(old_type), server_arch.GetTypeStr());
status = StartServer(port, server_arch);
}
}
if (HasTag(status, Tag::kDeployServer)) {
// Gamelet components are not deployed or out-dated. Deploy and retry.
status = DeployServer(server_arch);
@@ -176,15 +195,17 @@ absl::Status CdcRsyncClient::Run() {
return status;
}
absl::StatusOr<int> CdcRsyncClient::FindAvailablePort() {
absl::StatusOr<int> CdcRsyncClient::FindAvailablePort(ServerArch* server_arch) {
// Find available local and remote ports for port forwarding.
// If only one port is in the given range, try that without checking.
if (options_.forward_port_first >= options_.forward_port_last) {
return options_.forward_port_first;
}
absl::StatusOr<int> port =
port_manager_->ReservePort(options_.connection_timeout_sec);
assert(server_arch);
absl::StatusOr<int> port = port_manager_->ReservePort(
options_.connection_timeout_sec, server_arch->GetType());
if (absl::IsDeadlineExceeded(port.status())) {
// Server didn't respond in time.
return SetTag(port.status(), Tag::kConnectionTimeout);
@@ -193,6 +214,21 @@ absl::StatusOr<int> CdcRsyncClient::FindAvailablePort() {
// Port in use.
return SetTag(port.status(), Tag::kAddressInUse);
}
// If |server_arch| was guessed, calling netstat might have failed because
// the arch was wrong. Properly detect it and try again if it changed.
if (!port.ok() && server_arch->IsGuess()) {
const ArchType old_type = server_arch->GetType();
ASSIGN_OR_RETURN(*server_arch,
ServerArch::DetectFromRemoteDevice(remote_util_.get()));
assert(!server_arch->IsGuess());
if (server_arch->GetType() != old_type) {
LOG_DEBUG("Guessed server arch type wrong, guessed %s, actual %s.",
GetArchTypeStr(old_type), server_arch->GetTypeStr());
return FindAvailablePort(server_arch);
}
}
return port;
}