...
This commit is contained in:
parent
e730b85714
commit
849c68a060
@ -34,7 +34,7 @@ struct AdcNetProtoStopSeq : InetT {
|
||||
|
||||
static_assert(stopSeqSize, "STOP BYTE SEQUENCE MUST NOT BE AN EMPTY ONE!!!");
|
||||
|
||||
using typename InetT::socket;
|
||||
using socket_t = typename InetT::socket;
|
||||
|
||||
template <std::input_iterator IT>
|
||||
std::pair<IT, bool> matchCondition(IT begin, IT end)
|
||||
@ -50,7 +50,7 @@ struct AdcNetProtoStopSeq : InetT {
|
||||
std::advance(res.first, stopSeqSize); // move iterator to the one-past-the-end position
|
||||
res.second = true;
|
||||
} else {
|
||||
// may be only a part of message was received,
|
||||
// may be only a part of valid byte sequence was received,
|
||||
// so start next matching from previous begin-iterator
|
||||
res.first = begin;
|
||||
}
|
||||
|
||||
@ -29,58 +29,116 @@ namespace adc::impl
|
||||
|
||||
|
||||
template <typename NetMessageT, typename InetProtoT>
|
||||
class AdcNetServiceASIOStream
|
||||
class AdcNetServiceASIO : public InetProtoT
|
||||
{
|
||||
public:
|
||||
using socket_t = typename InetProtoT::socket;
|
||||
|
||||
AdcNetServiceASIOStream(socket_t& sock) : _socket(sock) {}
|
||||
using streambuff_iter_t = asio::buffers_iterator<asio::streambuf::const_buffers_type>;
|
||||
|
||||
virtual ~AdcNetServiceASIOStream() = default;
|
||||
template <typename... CtorArgTs>
|
||||
AdcNetServiceASIO(socket_t& sock, CtorArgTs&&... ctor_args)
|
||||
: InetProtoT(std::forward<CtorArgTs>(ctor_args)...), _socket(sock)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~AdcNetServiceASIO() = default;
|
||||
|
||||
|
||||
template <typename TimeoutT, asio::completion_token_for<void(std::error_code, size_t)> CompletionTokenT>
|
||||
auto asynSend(const NetMessageT& msg, const TimeoutT& timeout, CompletionTokenT&& token)
|
||||
{
|
||||
// using namespace asio::experimental::awaitable_operators;
|
||||
// create buffer sequence
|
||||
std::vector<asio::const_buffer> buff;
|
||||
std::ranges::for_each(msg.template bytesView<std::vector<std::string_view>>(),
|
||||
[&buff](const auto& el) { buff.emplace_back(el); });
|
||||
|
||||
// auto deadline = std::chrono::steady_clock::now() + timeout;
|
||||
auto timer = getDeadlineTimer(timeout);
|
||||
|
||||
std::unique_ptr<asio::steady_timer> timer(_socket.get_executor());
|
||||
// wrapper
|
||||
return asio::async_compose<CompletionTokenT, void(std::error_code)>(
|
||||
[buff = std::move(buff), timer = std::move(timer), this](auto& self, const std::error_code& ec = {},
|
||||
size_t sz = 0) {
|
||||
if (!ec) {
|
||||
if constexpr (std::derived_from<socket_t,
|
||||
asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
||||
return asio::async_write(_socket, buff, std::move(self));
|
||||
} else if constexpr (std::derived_from<
|
||||
socket_t, asio::basic_datagram_socket<typename socket_t::protocol_type>>) {
|
||||
return _socket.async_send(buff, std::move(self));
|
||||
} else if constexpr (std::derived_from<socket_t, asio::basic_seq_packet_socket<
|
||||
typename socket_t::protocol_type>>) {
|
||||
return _socket.async_send(buff, std::move(self));
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN ASIO-LIBRARY SOCKET TYPE!!!");
|
||||
}
|
||||
}
|
||||
|
||||
timer->expires_after(timeout);
|
||||
timer->async_wait([this, timer = std::move(timer)](const std::error_code& ec) {
|
||||
if (!ec) {
|
||||
_socket.cancel(std::make_error_code(std::errc::timed_out));
|
||||
}
|
||||
});
|
||||
timer->cancel();
|
||||
|
||||
|
||||
if constexpr (std::derived_from<socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
||||
return asio::async_write(_socket, createConstBufferSequence(msg), std::forward<CompletionTokenT>(token));
|
||||
} else if constexpr (std::derived_from<socket_t,
|
||||
asio::basic_datagram_socket<typename socket_t::protocol_type>>) {
|
||||
return _socket.async_send(createConstBufferSequence(msg), std::forward<CompletionTokenT>(token));
|
||||
} else if constexpr (std::derived_from<socket_t,
|
||||
asio::basic_seq_packet_socket<typename socket_t::protocol_type>>) {
|
||||
return _socket.async_send(createConstBufferSequence(msg), std::forward<CompletionTokenT>(token));
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN ASIO-LIBRARY SOCKET TYPE!!!");
|
||||
}
|
||||
|
||||
// std::error_code ec;
|
||||
|
||||
// co_await (asyncSendImpl(msg) && watchdog(deadline, ec));
|
||||
|
||||
// std::forward<CompletionTokenT>(token)(ec);
|
||||
// co_return asio::async_compose<CompletionTokenT, void(std::error_code)>(
|
||||
// [ec](auto& self, const std::error_code& = {}) { self.complete(ec); }, token, _socket);
|
||||
self.complete(ec);
|
||||
},
|
||||
token, _socket);
|
||||
}
|
||||
|
||||
|
||||
template <typename TimeoutT, typename CompletionTokenT>
|
||||
auto asyncReceive(const TimeoutT& timeout, CompletionTokenT&& token)
|
||||
{
|
||||
std::shared_ptr<asio::socket_base::message_flags> out_flags;
|
||||
|
||||
auto timer = getDeadlineTimer(timeout); // armed timer
|
||||
|
||||
return asio::async_compose<CompletionTokenT, void(const std::error_code&, const NetMessageT&)>(
|
||||
[timer = std::move(timer), out_flags, this](auto& self, const std::error_code& ec = {}, size_t sz = 0) {
|
||||
if (!ec) {
|
||||
if constexpr (std::derived_from<socket_t,
|
||||
asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
||||
return asio::async_read_until(
|
||||
_socket, _streamBuffer, [this](auto begin, auto end) { this->matchCondition(begin, end); },
|
||||
std::move(self));
|
||||
} else if constexpr (std::derived_from<
|
||||
socket_t, asio::basic_datagram_socket<typename socket_t::protocol_type>>) {
|
||||
return _socket.receive(_streamBuffer,
|
||||
std::move(self)); // datagram, so it should be received at once
|
||||
} else if constexpr (std::derived_from<socket_t, asio::basic_seq_packet_socket<
|
||||
typename socket_t::protocol_type>>) {
|
||||
return _socket.receive(_streamBuffer, *out_flags,
|
||||
std::move(self)); // datagram, so it should be received at once
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN ASIO-LIBRARY SOCKET TYPE!!!");
|
||||
}
|
||||
}
|
||||
|
||||
timer->cancel();
|
||||
|
||||
if (ec) {
|
||||
self.complete(ec, NetMessageT()); // return an empty message
|
||||
} else {
|
||||
auto begin_it = streambuff_iter_t::begin(_streamBuffer.data());
|
||||
auto end_it = begin_it + _streamBuffer.data().size();
|
||||
|
||||
// check for byte sequence is valid byte sequence and find the limits
|
||||
// (stream buffer may contain number of bytes more than requred by protocol)
|
||||
auto res = this->matchCondition(begin_it, end_it);
|
||||
|
||||
if (!res.second) {
|
||||
self.complete(std::make_error_code(std::errc::protocol_error),
|
||||
NetMessageT()); // return an empty message
|
||||
} else {
|
||||
auto nbytes = std::distance(begin_it, res.first);
|
||||
NetMessageT msg;
|
||||
|
||||
auto msg_it = this->fromLowLevel(begin_it, res.first);
|
||||
msg.setFromBytes(msg_it.first, msg_it.second);
|
||||
|
||||
_streamBuffer.consume(nbytes);
|
||||
|
||||
self.complete(ec, msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
token, _socket);
|
||||
}
|
||||
|
||||
|
||||
@ -89,6 +147,24 @@ protected:
|
||||
|
||||
asio::streambuf _streamBuffer;
|
||||
|
||||
template <typename TimeoutT>
|
||||
std::unique_ptr<asio::steady_timer> getDeadlineTimer(const TimeoutT& timeout, bool arm = true)
|
||||
{
|
||||
std::unique_ptr<asio::steady_timer> timer(_socket.get_executor());
|
||||
|
||||
if (arm) {
|
||||
timer->expires_after(timeout);
|
||||
|
||||
timer->async_wait([this](const std::error_code& ec) {
|
||||
if (!ec) {
|
||||
_socket.cancel(std::make_error_code(std::errc::timed_out));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
std::vector<asio::const_buffer> createConstBufferSequence(const NetMessageT& msg)
|
||||
{
|
||||
std::vector<asio::const_buffer> buff;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user