reset timeout on data recv/sent
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
### BREAKING CHANGES
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* Mount state has been moved into the configuration directory
|
||||||
|
* Unmount all active mounts prior to upgrade
|
||||||
* Remote mounts must be upgraded to v2.1.0+ to support new authentication scheme
|
* Remote mounts must be upgraded to v2.1.0+ to support new authentication scheme
|
||||||
* Protocol handshake added for DoS protection
|
* Protocol handshake added for DoS protection
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class timeout final {
|
class timeout final {
|
||||||
|
public:
|
||||||
|
using callback_t = std::function<void()>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
timeout(const timeout &) noexcept = delete;
|
timeout(const timeout &) noexcept = delete;
|
||||||
timeout(timeout &&) noexcept = delete;
|
timeout(timeout &&) noexcept = delete;
|
||||||
@@ -31,19 +34,23 @@ public:
|
|||||||
auto operator=(timeout &&) noexcept -> timeout & = delete;
|
auto operator=(timeout &&) noexcept -> timeout & = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
timeout(std::function<void()> timeout_callback,
|
timeout(callback_t timeout_callback,
|
||||||
std::chrono::system_clock::duration duration);
|
std::chrono::system_clock::duration duration);
|
||||||
|
|
||||||
~timeout() { disable(); }
|
~timeout();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> timeout_killed_;
|
std::chrono::system_clock::duration duration_;
|
||||||
|
callback_t timeout_callback_;
|
||||||
|
std::atomic<bool> timeout_killed_{false};
|
||||||
std::unique_ptr<std::thread> timeout_thread_{nullptr};
|
std::unique_ptr<std::thread> timeout_thread_{nullptr};
|
||||||
std::mutex timeout_mutex_;
|
std::mutex timeout_mutex_;
|
||||||
std::condition_variable timeout_notify_;
|
std::condition_variable timeout_notify_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void disable();
|
void disable();
|
||||||
|
|
||||||
|
void reset();
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
|||||||
@@ -73,11 +73,12 @@ void packet_client::close(client &cli) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void packet_client::close_all() {
|
void packet_client::close_all() {
|
||||||
unique_mutex_lock clients_lock(clients_mutex_);
|
mutex_lock clients_lock(clients_mutex_);
|
||||||
for (auto &cli : clients_) {
|
for (auto &cli : clients_) {
|
||||||
close(*cli);
|
close(*cli);
|
||||||
}
|
}
|
||||||
clients_.clear();
|
clients_.clear();
|
||||||
|
|
||||||
resolve_results_.store({});
|
resolve_results_.store({});
|
||||||
unique_id_ = utils::create_uuid_string();
|
unique_id_ = utils::create_uuid_string();
|
||||||
}
|
}
|
||||||
@@ -90,11 +91,23 @@ auto packet_client::check_version(std::uint32_t client_version,
|
|||||||
min_version = 0U;
|
min_version = 0U;
|
||||||
|
|
||||||
boost::asio::io_context ctx{};
|
boost::asio::io_context ctx{};
|
||||||
auto resolve_results = tcp::resolver(ctx).resolve(
|
|
||||||
cfg_.host_name_or_ip, std::to_string(cfg_.api_port));
|
|
||||||
|
|
||||||
client cli(ctx);
|
client cli(ctx);
|
||||||
boost::asio::connect(cli.socket, resolve_results);
|
|
||||||
|
timeout connect_timeout(
|
||||||
|
[&cli]() {
|
||||||
|
event_system::instance().raise<packet_client_timeout>("connect",
|
||||||
|
function_name);
|
||||||
|
packet_client::close(cli);
|
||||||
|
},
|
||||||
|
std::chrono::milliseconds(cfg_.conn_timeout_ms));
|
||||||
|
|
||||||
|
boost::asio::connect(
|
||||||
|
cli.socket, tcp::resolver(ctx).resolve(cfg_.host_name_or_ip,
|
||||||
|
std::to_string(cfg_.api_port)));
|
||||||
|
connect_timeout.disable();
|
||||||
|
if (not is_socket_still_alive(cli.socket)) {
|
||||||
|
utils::error::raise_error(function_name, e, "failed to connect");
|
||||||
|
}
|
||||||
|
|
||||||
comm::apply_common_socket_properties(cli.socket);
|
comm::apply_common_socket_properties(cli.socket);
|
||||||
|
|
||||||
@@ -116,9 +129,23 @@ auto packet_client::check_version(std::uint32_t client_version,
|
|||||||
|
|
||||||
auto packet_client::connect(client &cli) -> bool {
|
auto packet_client::connect(client &cli) -> bool {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
timeout connect_timeout(
|
||||||
|
[&cli]() {
|
||||||
|
event_system::instance().raise<packet_client_timeout>("connect",
|
||||||
|
function_name);
|
||||||
|
packet_client::close(cli);
|
||||||
|
},
|
||||||
|
std::chrono::milliseconds(cfg_.conn_timeout_ms));
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
|
|
||||||
boost::asio::connect(cli.socket, resolve_results_.load());
|
boost::asio::connect(cli.socket, resolve_results_.load());
|
||||||
|
connect_timeout.disable();
|
||||||
|
|
||||||
|
if (not is_socket_still_alive(cli.socket)) {
|
||||||
|
utils::error::raise_error(function_name, e, "failed to connect");
|
||||||
|
}
|
||||||
|
|
||||||
comm::apply_common_socket_properties(cli.socket);
|
comm::apply_common_socket_properties(cli.socket);
|
||||||
|
|
||||||
@@ -246,6 +273,7 @@ void packet_client::read_data(client &cli, data_buffer &buffer) const {
|
|||||||
throw std::runtime_error("read failed|" + std::to_string(bytes_read));
|
throw std::runtime_error("read failed|" + std::to_string(bytes_read));
|
||||||
}
|
}
|
||||||
offset += static_cast<std::uint32_t>(bytes_read);
|
offset += static_cast<std::uint32_t>(bytes_read);
|
||||||
|
read_timeout.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +366,7 @@ auto packet_client::send(std::string_view method, packet &request,
|
|||||||
current_request.encode_top(current_client->nonce);
|
current_request.encode_top(current_client->nonce);
|
||||||
request = current_request;
|
request = current_request;
|
||||||
|
|
||||||
current_request.encrypt(cfg_.encryption_token);
|
current_request.encrypt(cfg_.encryption_token, true);
|
||||||
write_data(*current_client, current_request);
|
write_data(*current_client, current_request);
|
||||||
|
|
||||||
ret = read_packet(*current_client, response);
|
ret = read_packet(*current_client, response);
|
||||||
@@ -389,6 +417,7 @@ void packet_client::write_data(client &cli, const packet &request) const {
|
|||||||
throw std::runtime_error("write failed|" + std::to_string(bytes_written));
|
throw std::runtime_error("write failed|" + std::to_string(bytes_written));
|
||||||
}
|
}
|
||||||
offset += static_cast<std::uint32_t>(bytes_written);
|
offset += static_cast<std::uint32_t>(bytes_written);
|
||||||
|
read_timeout.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|||||||
@@ -22,36 +22,61 @@
|
|||||||
#include "utils/timeout.hpp"
|
#include "utils/timeout.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
timeout::timeout(std::function<void()> timeout_callback,
|
timeout::timeout(callback_t timeout_callback,
|
||||||
std::chrono::system_clock::duration duration)
|
std::chrono::system_clock::duration duration)
|
||||||
: timeout_killed_(duration == 0s) {
|
: duration_(duration),
|
||||||
|
timeout_callback_(std::move(timeout_callback)),
|
||||||
|
timeout_killed_(duration <= std::chrono::system_clock::duration::zero()) {
|
||||||
if (timeout_killed_) {
|
if (timeout_killed_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout_thread_ =
|
timeout_thread_ = std::make_unique<std::thread>([this]() {
|
||||||
std::make_unique<std::thread>([this, duration, timeout_callback]() {
|
std::unique_lock<std::mutex> loc_lock(timeout_mutex_);
|
||||||
unique_mutex_lock lock(timeout_mutex_);
|
|
||||||
if (not timeout_killed_) {
|
while (not timeout_killed_) {
|
||||||
timeout_notify_.wait_for(lock, duration);
|
auto res = timeout_notify_.wait_for(loc_lock, duration_);
|
||||||
if (not timeout_killed_) {
|
if (res != std::cv_status::timeout) {
|
||||||
timeout_callback();
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void timeout::disable() {
|
|
||||||
if (timeout_killed_) {
|
if (timeout_killed_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout_killed_ = true;
|
timeout_killed_ = true;
|
||||||
|
loc_lock.unlock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
timeout_callback_();
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout::~timeout() { disable(); }
|
||||||
|
|
||||||
|
void timeout::disable() {
|
||||||
unique_mutex_lock lock(timeout_mutex_);
|
unique_mutex_lock lock(timeout_mutex_);
|
||||||
|
std::unique_ptr<std::thread> timeout_thread{nullptr};
|
||||||
|
std::swap(timeout_thread, timeout_thread_);
|
||||||
|
|
||||||
|
if (not timeout_thread) {
|
||||||
|
timeout_notify_.notify_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout_killed_ = true;
|
||||||
timeout_notify_.notify_all();
|
timeout_notify_.notify_all();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
timeout_thread_->join();
|
timeout_thread->join();
|
||||||
timeout_thread_.reset();
|
}
|
||||||
|
|
||||||
|
void timeout::reset() {
|
||||||
|
mutex_lock lock(timeout_mutex_);
|
||||||
|
timeout_notify_.notify_all();
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|||||||
Reference in New Issue
Block a user