[cdc_rsync] Move sockets to common (#95)

There are no real changes, just moving files around. Sockets will be
used in the future to find available ports in cdc_stream. Therefore,
they need to be in common.
This commit is contained in:
Lutz Justen
2023-03-10 09:17:27 +01:00
committed by GitHub
parent c481b6a27f
commit 09cee120b2
25 changed files with 124 additions and 124 deletions

View File

@@ -18,19 +18,6 @@ cc_library(
hdrs = ["client_file_info.h"],
)
cc_library(
name = "client_socket",
srcs = ["client_socket.cc"],
hdrs = ["client_socket.h"],
target_compatible_with = ["@platforms//os:windows"],
deps = [
"//cdc_rsync/base:socket",
"//common:log",
"//common:status",
"//common:util",
],
)
cc_library(
name = "file_finder_and_sender",
srcs = ["file_finder_and_sender.cc"],
@@ -54,8 +41,8 @@ cc_test(
data = ["testdata/root.txt"] + glob(["testdata/file_finder_and_sender/**"]),
deps = [
":file_finder_and_sender",
"//cdc_rsync/base:fake_socket",
"//cdc_rsync/protos:messages_cc_proto",
"//common:fake_socket",
"//common:status_test_macros",
"//common:test_main",
"@com_google_googletest//:gtest",
@@ -67,15 +54,8 @@ cc_library(
name = "cdc_rsync_client",
srcs = ["cdc_rsync_client.cc"],
hdrs = ["cdc_rsync_client.h"],
linkopts = select({
"//tools:windows": [
"/DEFAULTLIB:Ws2_32.lib", # Sockets, e.g. recv, send, WSA*.
],
"//conditions:default": [],
}),
target_compatible_with = ["@platforms//os:windows"],
deps = [
":client_socket",
":file_finder_and_sender",
":parallel_file_opener",
":progress_tracker",
@@ -84,8 +64,8 @@ cc_library(
"//cdc_rsync/base:cdc_interface",
"//cdc_rsync/base:message_pump",
"//cdc_rsync/base:server_exit_code",
"//cdc_rsync/base:socket",
"//cdc_rsync/protos:messages_cc_proto",
"//common:client_socket",
"//common:gamelet_component",
"//common:log",
"//common:path",
@@ -94,6 +74,7 @@ cc_library(
"//common:port_manager",
"//common:process",
"//common:remote_util",
"//common:socket",
"//common:status",
"//common:status_macros",
"//common:threadpool",
@@ -203,8 +184,8 @@ cc_library(
srcs = ["zstd_stream.cc"],
hdrs = ["zstd_stream.h"],
deps = [
":client_socket",
"//common:buffer",
"//common:client_socket",
"//common:status",
"//common:status_macros",
"//common:stopwatch",
@@ -217,8 +198,8 @@ cc_test(
srcs = ["zstd_stream_test.cc"],
deps = [
":zstd_stream",
"//cdc_rsync/base:fake_socket",
"//cdc_rsync_server:unzstd_stream",
"//common:fake_socket",
"//common:status_test_macros",
"//common:test_main",
"@com_github_zstd//:zstd",

View File

@@ -28,31 +28,21 @@ cc_test(
data = ["testdata/root.txt"] + glob(["testdata/cdc_interface/**"]),
deps = [
":cdc_interface",
":fake_socket",
"//common:fake_socket",
"//common:status_test_macros",
"//common:test_main",
"@com_google_googletest//:gtest",
],
)
cc_library(
name = "fake_socket",
srcs = ["fake_socket.cc"],
hdrs = ["fake_socket.h"],
deps = [
"//cdc_rsync/base:socket",
"@com_google_absl//absl/status",
],
)
cc_library(
name = "message_pump",
srcs = ["message_pump.cc"],
hdrs = ["message_pump.h"],
deps = [
":socket",
"//common:buffer",
"//common:log",
"//common:socket",
"//common:status",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:str_format",
@@ -64,9 +54,9 @@ cc_test(
name = "message_pump_test",
srcs = ["message_pump_test.cc"],
deps = [
":fake_socket",
":message_pump",
"//cdc_rsync/protos:messages_cc_proto",
"//common:fake_socket",
"//common:status_test_macros",
"//common:test_main",
"@com_google_googletest//:gtest",
@@ -78,19 +68,6 @@ cc_library(
hdrs = ["server_exit_code.h"],
)
cc_library(
name = "socket",
srcs = ["socket.cc"],
hdrs = ["socket.h"],
deps = [
"//common:log",
"//common:platform",
"//common:status",
"//common:util",
"@com_google_absl//absl/status",
],
)
filegroup(
name = "all_test_sources",
srcs = glob(["*_test.cc"]),

View File

@@ -17,8 +17,8 @@
#include <cstdio>
#include <fstream>
#include "cdc_rsync/base/fake_socket.h"
#include "cdc_rsync/base/message_pump.h"
#include "common/fake_socket.h"
#include "common/log.h"
#include "common/path.h"
#include "common/status_test_macros.h"

View File

@@ -1,71 +0,0 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cdc_rsync/base/fake_socket.h"
namespace cdc_ft {
FakeSocket::FakeSocket() = default;
FakeSocket::~FakeSocket() = default;
absl::Status FakeSocket::Send(const void* buffer, size_t size) {
// Wait until we can send again.
std::unique_lock<std::mutex> suspend_lock(suspend_mutex_);
suspend_cv_.wait(suspend_lock, [this]() { return !sending_suspended_; });
suspend_lock.unlock();
std::unique_lock<std::mutex> lock(data_mutex_);
data_.append(static_cast<const char*>(buffer), size);
lock.unlock();
data_cv_.notify_all();
return absl::OkStatus();
}
absl::Status FakeSocket::Receive(void* buffer, size_t size,
bool allow_partial_read,
size_t* bytes_received) {
*bytes_received = 0;
std::unique_lock<std::mutex> lock(data_mutex_);
data_cv_.wait(lock, [this, size, allow_partial_read]() {
size_t min_size = allow_partial_read ? 1 : size;
return data_.size() >= min_size || shutdown_;
});
if (shutdown_) {
return absl::UnavailableError("Pipe is shut down");
}
size_t to_copy = std::min(size, data_.size());
memcpy(buffer, data_.data(), to_copy);
*bytes_received = to_copy;
// This is horribly inefficent, but should be OK in a fake.
data_.erase(0, to_copy);
return absl::OkStatus();
}
void FakeSocket::ShutdownSendingEnd() {
std::unique_lock<std::mutex> lock(data_mutex_);
shutdown_ = true;
lock.unlock();
data_cv_.notify_all();
}
void FakeSocket::SuspendSending(bool suspended) {
std::unique_lock<std::mutex> lock(suspend_mutex_);
sending_suspended_ = suspended;
lock.unlock();
suspend_cv_.notify_all();
}
} // namespace cdc_ft

View File

@@ -1,57 +0,0 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CDC_RSYNC_BASE_FAKE_SOCKET_H_
#define CDC_RSYNC_BASE_FAKE_SOCKET_H_
#include <condition_variable>
#include <mutex>
#include "absl/status/status.h"
#include "cdc_rsync/base/socket.h"
namespace cdc_ft {
// Fake socket that receives the same data it sends.
class FakeSocket : public Socket {
public:
FakeSocket();
~FakeSocket();
// Socket:
absl::Status Send(const void* buffer, size_t size) override; // thread-safe
absl::Status Receive(void* buffer, size_t size, bool allow_partial_read,
size_t* bytes_received) override; // thread-safe
void ShutdownSendingEnd();
// If set to true, blocks on Send() until it is set to false again.
void SuspendSending(bool suspended);
private:
std::mutex data_mutex_;
std::condition_variable data_cv_;
std::string data_;
bool shutdown_ = false;
bool sending_suspended_ = false;
std::mutex suspend_mutex_;
std::condition_variable suspend_cv_;
};
} // namespace cdc_ft
#endif // CDC_RSYNC_BASE_FAKE_SOCKET_H_

View File

@@ -16,9 +16,9 @@
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "cdc_rsync/base/socket.h"
#include "common/buffer.h"
#include "common/log.h"
#include "common/socket.h"
#include "common/status.h"
#include "google/protobuf/message_lite.h"

View File

@@ -14,8 +14,8 @@
#include "cdc_rsync/base/message_pump.h"
#include "cdc_rsync/base/fake_socket.h"
#include "cdc_rsync/protos/messages.pb.h"
#include "common/fake_socket.h"
#include "common/log.h"
#include "common/status.h"
#include "common/status_test_macros.h"

View File

@@ -1,65 +0,0 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cdc_rsync/base/socket.h"
#include "common/log.h"
#include "common/platform.h"
#include "common/status.h"
#include "common/util.h"
#if PLATFORM_WINDOWS
#include <winsock2.h>
#endif
namespace cdc_ft {
// static
absl::Status Socket::Initialize() {
#if PLATFORM_WINDOWS
WSADATA wsaData;
const int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
return MakeStatus("WSAStartup() failed: %s", Util::GetWin32Error(result));
}
return absl::OkStatus();
#elif PLATFORM_LINUX
return absl::OkStatus();
#endif
}
// static
absl::Status Socket::Shutdown() {
#if PLATFORM_WINDOWS
const int result = WSACleanup();
if (result == SOCKET_ERROR) {
return MakeStatus("WSACleanup() failed: %s",
Util::GetWin32Error(WSAGetLastError()));
}
return absl::OkStatus();
#elif PLATFORM_LINUX
return absl::OkStatus();
#endif
}
SocketFinalizer::~SocketFinalizer() {
absl::Status status = Socket::Shutdown();
if (!status.ok()) {
LOG_ERROR("Socket shutdown failed: %s", status.message())
}
};
} // namespace cdc_ft

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CDC_RSYNC_BASE_SOCKET_H_
#define CDC_RSYNC_BASE_SOCKET_H_
#include "absl/status/status.h"
namespace cdc_ft {
class Socket {
public:
Socket() = default;
virtual ~Socket() = default;
// Calls WSAStartup() on Windows, no-op on Linux.
// Must be called before using sockets.
static absl::Status Initialize();
// Calls WSACleanup() on Windows, no-op on Linux.
// Must be called after using sockets.
static absl::Status Shutdown();
// Send data to the socket.
virtual absl::Status Send(const void* buffer, size_t size) = 0;
// Receives data from the socket. Blocks until data is available or the
// sending end of the socket gets shut down by the sender.
// If |allow_partial_read| is false, blocks until |size| bytes are available.
// If |allow_partial_read| is true, may return with success if less than
// |size| (but more than 0) bytes were received.
// The number of bytes written to |buffer| is returned in |bytes_received|.
virtual absl::Status Receive(void* buffer, size_t size,
bool allow_partial_read,
size_t* bytes_received) = 0;
};
// Convenience class that calls Shutdown() on destruction. Logs on errors.
class SocketFinalizer {
public:
~SocketFinalizer();
};
} // namespace cdc_ft
#endif // CDC_RSYNC_BASE_SOCKET_H_

View File

@@ -20,13 +20,13 @@
#include "cdc_rsync/base/message_pump.h"
#include "cdc_rsync/base/server_exit_code.h"
#include "cdc_rsync/client_file_info.h"
#include "cdc_rsync/client_socket.h"
#include "cdc_rsync/file_finder_and_sender.h"
#include "cdc_rsync/parallel_file_opener.h"
#include "cdc_rsync/progress_tracker.h"
#include "cdc_rsync/protos/messages.pb.h"
#include "cdc_rsync/server_arch.h"
#include "cdc_rsync/zstd_stream.h"
#include "common/client_socket.h"
#include "common/gamelet_component.h"
#include "common/log.h"
#include "common/path.h"

View File

@@ -23,8 +23,8 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "cdc_rsync/base/message_pump.h"
#include "cdc_rsync/client_socket.h"
#include "cdc_rsync/progress_tracker.h"
#include "common/client_socket.h"
#include "common/path_filter.h"
#include "common/process.h"

View File

@@ -1,165 +0,0 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cdc_rsync/client_socket.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <cassert>
#include "common/log.h"
#include "common/status.h"
#include "common/util.h"
namespace cdc_ft {
namespace {
// Creates a status with the given |message| and the last WSA error.
// Assigns Tag::kSocketEof for WSAECONNRESET errors.
absl::Status MakeSocketStatus(const char* message) {
const int err = WSAGetLastError();
absl::Status status = MakeStatus("%s: %s", message, Util::GetWin32Error(err));
if (err == WSAECONNRESET) {
status = SetTag(status, Tag::kSocketEof);
}
return status;
}
} // namespace
struct ClientSocketInfo {
SOCKET socket;
ClientSocketInfo() : socket(INVALID_SOCKET) {}
};
ClientSocket::ClientSocket() = default;
ClientSocket::~ClientSocket() { Disconnect(); }
absl::Status ClientSocket::Connect(int port) {
addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port.
addrinfo* addr_infos = nullptr;
int result = getaddrinfo("localhost", std::to_string(port).c_str(), &hints,
&addr_infos);
if (result != 0) {
return MakeStatus("getaddrinfo() failed: %i", result);
}
socket_info_ = std::make_unique<ClientSocketInfo>();
int count = 0;
for (addrinfo* curr = addr_infos; curr; curr = curr->ai_next, count++) {
socket_info_->socket =
socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
if (socket_info_->socket == INVALID_SOCKET) {
LOG_DEBUG("socket() failed for addr_info %i: %s", count,
Util::GetWin32Error(WSAGetLastError()));
continue;
}
// Connect to server.
result = connect(socket_info_->socket, curr->ai_addr,
static_cast<int>(curr->ai_addrlen));
if (result == SOCKET_ERROR) {
LOG_DEBUG("connect() failed for addr_info %i: %s", count,
Util::GetWin32Error(WSAGetLastError()));
closesocket(socket_info_->socket);
socket_info_->socket = INVALID_SOCKET;
continue;
}
// Success!
break;
}
freeaddrinfo(addr_infos);
if (socket_info_->socket == INVALID_SOCKET) {
socket_info_.reset();
return MakeStatus("Unable to connect to port %i", port);
}
LOG_INFO("Client socket connected to port %i", port);
return absl::OkStatus();
}
void ClientSocket::Disconnect() {
if (!socket_info_) {
return;
}
if (socket_info_->socket != INVALID_SOCKET) {
closesocket(socket_info_->socket);
socket_info_->socket = INVALID_SOCKET;
}
socket_info_.reset();
}
absl::Status ClientSocket::Send(const void* buffer, size_t size) {
int result = send(socket_info_->socket, static_cast<const char*>(buffer),
static_cast<int>(size), /*flags */ 0);
if (result == SOCKET_ERROR) {
return MakeSocketStatus("send() failed");
}
return absl::OkStatus();
}
absl::Status ClientSocket::Receive(void* buffer, size_t size,
bool allow_partial_read,
size_t* bytes_received) {
*bytes_received = 0;
if (size == 0) {
return absl::OkStatus();
}
int flags = allow_partial_read ? 0 : MSG_WAITALL;
int bytes_read = recv(socket_info_->socket, static_cast<char*>(buffer),
static_cast<int>(size), flags);
if (bytes_read == SOCKET_ERROR) {
return MakeSocketStatus("recv() failed");
}
if (bytes_read == 0) {
// EOF
return SetTag(MakeStatus("EOF detected"), Tag::kSocketEof);
}
if (bytes_read != size && !allow_partial_read) {
// Can this happen?
return MakeStatus("Partial read");
}
*bytes_received = bytes_read;
return absl::OkStatus();
}
absl::Status ClientSocket::ShutdownSendingEnd() {
int result = shutdown(socket_info_->socket, SD_SEND);
if (result == SOCKET_ERROR) {
return MakeSocketStatus("shutdown() failed");
}
return absl::OkStatus();
}
} // namespace cdc_ft

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CDC_RSYNC_CLIENT_SOCKET_H_
#define CDC_RSYNC_CLIENT_SOCKET_H_
#include <memory>
#include "absl/status/status.h"
#include "cdc_rsync/base/socket.h"
namespace cdc_ft {
class ClientSocket : public Socket {
public:
ClientSocket();
~ClientSocket();
// Connects to localhost on |port|.
absl::Status Connect(int port);
// Disconnects again. No-op if not connected.
void Disconnect();
// Shuts down the sending end of the socket. This will interrupt any receive
// calls on the server and shut it down.
absl::Status ShutdownSendingEnd();
// Socket:
absl::Status Send(const void* buffer, size_t size) override;
absl::Status Receive(void* buffer, size_t size, bool allow_partial_read,
size_t* bytes_received) override;
private:
std::unique_ptr<struct ClientSocketInfo> socket_info_;
};
} // namespace cdc_ft
#endif // CDC_RSYNC_CLIENT_SOCKET_H_

View File

@@ -18,8 +18,8 @@
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "cdc_rsync/base/fake_socket.h"
#include "cdc_rsync/base/message_pump.h"
#include "common/fake_socket.h"
#include "common/log.h"
#include "common/path.h"
#include "common/path_filter.h"

View File

@@ -21,8 +21,8 @@
#include "absl/status/status.h"
#include "absl/synchronization/mutex.h"
#include "cdc_rsync/base/socket.h"
#include "common/buffer.h"
#include "common/socket.h"
#include "lib/zstd.h"
namespace cdc_ft {

View File

@@ -14,8 +14,8 @@
#include "cdc_rsync/zstd_stream.h"
#include "cdc_rsync/base/fake_socket.h"
#include "cdc_rsync_server/unzstd_stream.h"
#include "common/fake_socket.h"
#include "common/status_test_macros.h"
#include "gtest/gtest.h"