...
This commit is contained in:
parent
daf4e1eab9
commit
9a2baa702d
@ -45,6 +45,12 @@ if (ASIO_LIBRARY)
|
|||||||
|
|
||||||
add_compile_options(ASIO::ASIO)
|
add_compile_options(ASIO::ASIO)
|
||||||
add_compile_definitions(PUBLIC USE_ASIO_LIBRARY)
|
add_compile_definitions(PUBLIC USE_ASIO_LIBRARY)
|
||||||
|
|
||||||
|
option(OPENSSL_LIBRARY "Use openssl library for related ASIO-based implementation" ON)
|
||||||
|
if (OPENSSL_LIBRARY)
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
add_compile_definitions(PUBLIC USE_OPENSSL_WITH_ASIO)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
ABSTRACT DEVICE COMPONENTS LIBRARY
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "../common/adc_traits.h"
|
#include "../common/adc_traits.h"
|
||||||
|
|
||||||
namespace adc
|
namespace adc
|
||||||
@ -13,20 +20,21 @@ namespace adc
|
|||||||
* endpoint: proto_mark://host_name:port_num/path
|
* endpoint: proto_mark://host_name:port_num/path
|
||||||
* where "part" is optional for all protocol kinds;
|
* where "part" is optional for all protocol kinds;
|
||||||
*
|
*
|
||||||
* for "local" kind protocol the endpoint string must consists of
|
* for the "local" kind protocol the endpoint string must consists of
|
||||||
* only "proto_mark" and "host_name" fields
|
* only "proto_mark" and "host_name" fields
|
||||||
* (e.g.: local://APP_UNIX_SOCKET)
|
* (e.g.: local://APP_UNIX_SOCKET)
|
||||||
*
|
*
|
||||||
|
* NOTE: "proto_mark" field is parsed as case-insensitive string!
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AdcEndpoint
|
class AdcEndpoint
|
||||||
{
|
{
|
||||||
protected:
|
public:
|
||||||
static constexpr std::string_view protoHostDelim = "://";
|
static constexpr std::string_view protoHostDelim = "://";
|
||||||
static constexpr std::string_view hostPortDelim = ":";
|
static constexpr std::string_view hostPortDelim = ":";
|
||||||
static constexpr std::string_view portPathDelim = "/";
|
static constexpr std::string_view portPathDelim = "/";
|
||||||
|
|
||||||
public:
|
|
||||||
enum proto_id_t : uint8_t {
|
enum proto_id_t : uint8_t {
|
||||||
PROTO_ID_LOCAL,
|
PROTO_ID_LOCAL,
|
||||||
PROTO_ID_TCP,
|
PROTO_ID_TCP,
|
||||||
@ -47,6 +55,50 @@ public:
|
|||||||
static constexpr std::array validProtoMarks = {protoMarkLocal, protoMarkTCP, protoMarkTLS,
|
static constexpr std::array validProtoMarks = {protoMarkLocal, protoMarkTCP, protoMarkTLS,
|
||||||
protoMarkUDP, protoMarkWS, protoMarkWSS};
|
protoMarkUDP, protoMarkWS, protoMarkWSS};
|
||||||
|
|
||||||
|
|
||||||
|
// factory methods
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range R>
|
||||||
|
AdcEndpoint createLocal(R&& path)
|
||||||
|
{
|
||||||
|
return AdcEndpoint(PROTO_ID_LOCAL, std::string_view(""), -1, std::forward<R>(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range HT>
|
||||||
|
AdcEndpoint createTCP(HT&& host, int port)
|
||||||
|
{
|
||||||
|
return AdcEndpoint(PROTO_ID_TCP, std::forward<HT>(host), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL_WITH_ASIO
|
||||||
|
template <traits::adc_input_char_range HT>
|
||||||
|
AdcEndpoint createTLS(HT&& host, int port)
|
||||||
|
{
|
||||||
|
return AdcEndpoint(PROTO_ID_TLS, std::forward<HT>(host), port);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range HT>
|
||||||
|
AdcEndpoint createUDP(HT&& host, int port)
|
||||||
|
{
|
||||||
|
return AdcEndpoint(PROTO_ID_UDP, std::forward<HT>(host), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT = std::string_view>
|
||||||
|
AdcEndpoint createWS(HT&& host, int port, PTT&& path = PTT())
|
||||||
|
{
|
||||||
|
return AdcEndpoint(PROTO_ID_WS, std::forward<HT>(host), port, std::forward<PTT>(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT = std::string_view>
|
||||||
|
AdcEndpoint createWSS(HT&& host, int port, PTT&& path = PTT())
|
||||||
|
{
|
||||||
|
return AdcEndpoint(PROTO_ID_WSS, std::forward<HT>(host), port, std::forward<PTT>(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Constructors and destructor */
|
/* Constructors and destructor */
|
||||||
|
|
||||||
AdcEndpoint() = default;
|
AdcEndpoint() = default;
|
||||||
@ -255,8 +307,10 @@ public:
|
|||||||
|
|
||||||
auto sz = std::distance(r.begin(), found.begin());
|
auto sz = std::distance(r.begin(), found.begin());
|
||||||
|
|
||||||
std::string proto;
|
std::string proto; // case-insensitive!
|
||||||
std::ranges::copy(r | std::views::take(sz), std::back_inserter(proto));
|
std::ranges::copy(
|
||||||
|
r | std::views::take(sz) | std::views::transform([](auto ch) -> char { return std::tolower(ch); }),
|
||||||
|
std::back_inserter(proto));
|
||||||
|
|
||||||
std::underlying_type_t<proto_id_t> i = 0;
|
std::underlying_type_t<proto_id_t> i = 0;
|
||||||
proto_id_t id = PROTO_ID_UNKNOWN;
|
proto_id_t id = PROTO_ID_UNKNOWN;
|
||||||
|
|||||||
139
net/adc_netmsg.h
139
net/adc_netmsg.h
@ -43,91 +43,17 @@ void convertToBytes(ByteStorageT& res, const T& v, const Ts&... vs)
|
|||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
||||||
|
|
||||||
namespace traits
|
|
||||||
{
|
|
||||||
|
|
||||||
template <typename T, typename IT>
|
|
||||||
concept adc_netmessage_c = requires(const T t) { // const methods
|
|
||||||
requires std::same_as<std::iter_value_t<IT>, char>;
|
|
||||||
{ t.empty() } -> std::convertible_to<bool>;
|
|
||||||
{ t.byteSize() } -> std::convertible_to<size_t>;
|
|
||||||
{ t.bytes() } -> adc_output_char_range;
|
|
||||||
{ t.byteView() } -> adc_range_of_view_char_range;
|
|
||||||
{ t.setFromBytes(std::input_iterator<IT>) } -> std::same_as<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace traits
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Trivial message interface:
|
*/
|
||||||
byte storage: just a char-range
|
|
||||||
*/
|
|
||||||
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
||||||
class AdcNetMessageTrivialInterface
|
class AdcNetMessageInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~AdcNetMessageTrivialInterface() = default;
|
typedef ByteStorageT byte_storage_t;
|
||||||
|
typedef ByteViewT byte_view_t;
|
||||||
|
|
||||||
bool empty() const { return std::ranges::distance(_bytes.begin(), _bytes.end()) == 0; }
|
virtual ~AdcNetMessageInterface() = default;
|
||||||
|
|
||||||
size_t byteSize() const
|
|
||||||
{
|
|
||||||
//
|
|
||||||
return std::ranges::distance(_bytes.begin(), _bytes.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a copy of message bytes
|
|
||||||
template <traits::adc_output_char_range R>
|
|
||||||
R bytes() const
|
|
||||||
{
|
|
||||||
R r;
|
|
||||||
std::ranges::copy(_bytes, std::back_inserter(r));
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
virtual ByteStorageT bytes() const
|
|
||||||
{
|
|
||||||
//
|
|
||||||
return bytes<ByteStorageT>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a view of message bytes
|
|
||||||
template <traits::adc_range_of_view_char_range R>
|
|
||||||
R bytesView() const
|
|
||||||
{
|
|
||||||
R r;
|
|
||||||
|
|
||||||
r.emplace_back(_bytes.begin(), _bytes.end());
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ByteViewT> bytesView() const
|
|
||||||
{
|
|
||||||
//
|
|
||||||
return bytesView<std::vector<ByteViewT>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ByteStorageT _bytes;
|
|
||||||
|
|
||||||
AdcNetMessageTrivialInterface() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
interface for more complex messages:
|
|
||||||
byte storage: std::vector of char-range (sequence of buffers)
|
|
||||||
*/
|
|
||||||
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
|
||||||
class AdcNetMessageSeqInterface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~AdcNetMessageSeqInterface() = default;
|
|
||||||
|
|
||||||
bool empty() const
|
bool empty() const
|
||||||
{
|
{
|
||||||
@ -201,11 +127,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<ByteStorageT> _bytes;
|
std::vector<ByteStorageT> _bytes; // sequence of byte buffers
|
||||||
size_t _reservedNum;
|
size_t _reservedNum;
|
||||||
|
|
||||||
|
|
||||||
AdcNetMessageSeqInterface(size_t reserved = 0) : _reservedNum(reserved), _bytes()
|
AdcNetMessageInterface(size_t reserved = 0) : _reservedNum(reserved), _bytes()
|
||||||
{
|
{
|
||||||
// reserve the "_reservedNum" first elements
|
// reserve the "_reservedNum" first elements
|
||||||
_bytes.resize(_reservedNum);
|
_bytes.resize(_reservedNum);
|
||||||
@ -220,16 +146,24 @@ protected:
|
|||||||
|
|
||||||
// Generic message class
|
// Generic message class
|
||||||
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
||||||
class AdcGenericNetMessage : public AdcNetMessageTrivialInterface<ByteStorageT, ByteViewT>
|
class AdcGenericNetMessage : public AdcNetMessageInterface<ByteStorageT, ByteViewT>
|
||||||
{
|
{
|
||||||
using base_t = AdcNetMessageTrivialInterface<ByteStorageT, ByteViewT>;
|
using base_t = AdcNetMessageInterface<ByteStorageT, ByteViewT>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using typename base_t::byte_storage_t;
|
||||||
|
using typename base_t::byte_view_t;
|
||||||
|
|
||||||
using base_t::base_t;
|
using base_t::base_t;
|
||||||
using base_t::bytes;
|
using base_t::bytes;
|
||||||
using base_t::bytesView;
|
using base_t::bytesView;
|
||||||
using base_t::empty;
|
using base_t::empty;
|
||||||
|
|
||||||
|
AdcGenericNetMessage() : base_t()
|
||||||
|
{
|
||||||
|
// just the single buffer
|
||||||
|
this->_bytes.resize(1);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
AdcGenericNetMessage(const T& v, const Ts&... vs) : AdcGenericNetMessage()
|
AdcGenericNetMessage(const T& v, const Ts&... vs) : AdcGenericNetMessage()
|
||||||
@ -241,13 +175,13 @@ public:
|
|||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
void appendBytes(const T& v, const Ts&... vs)
|
void appendBytes(const T& v, const Ts&... vs)
|
||||||
{
|
{
|
||||||
utils::convertToBytes(this->_bytes, v, vs...);
|
utils::convertToBytes(this->_bytes[0], v, vs...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
void setBytes(const T& v, const Ts&... vs)
|
void setBytes(const T& v, const Ts&... vs)
|
||||||
{
|
{
|
||||||
this->_bytes = ByteStorageT();
|
this->_bytes[0] = ByteStorageT();
|
||||||
|
|
||||||
appendBytes(v, vs...);
|
appendBytes(v, vs...);
|
||||||
}
|
}
|
||||||
@ -257,7 +191,7 @@ public:
|
|||||||
void appendFromBytes(IT begin, IT end)
|
void appendFromBytes(IT begin, IT end)
|
||||||
requires std::same_as<std::iter_value_t<IT>, char>
|
requires std::same_as<std::iter_value_t<IT>, char>
|
||||||
{
|
{
|
||||||
std::copy(begin, end, std::back_inserter(this->_bytes));
|
std::copy(begin, end, std::back_inserter(this->_bytes[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -265,7 +199,7 @@ public:
|
|||||||
void setFromBytes(IT begin, IT end)
|
void setFromBytes(IT begin, IT end)
|
||||||
requires std::same_as<std::iter_value_t<IT>, char>
|
requires std::same_as<std::iter_value_t<IT>, char>
|
||||||
{
|
{
|
||||||
this->_bytes = ByteStorageT();
|
this->_bytes[0] = ByteStorageT();
|
||||||
|
|
||||||
appendFromBytes(begin, end);
|
appendFromBytes(begin, end);
|
||||||
}
|
}
|
||||||
@ -283,10 +217,10 @@ static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " ";
|
|||||||
template <const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
template <const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
||||||
traits::adc_output_char_range ByteStorageT = std::string,
|
traits::adc_output_char_range ByteStorageT = std::string,
|
||||||
traits::adc_char_view ByteViewT = std::string_view>
|
traits::adc_char_view ByteViewT = std::string_view>
|
||||||
class AdcTokenNetMessage : public AdcNetMessageSeqInterface<ByteStorageT, ByteViewT>
|
class AdcTokenNetMessage : public AdcNetMessageInterface<ByteStorageT, ByteViewT>
|
||||||
{
|
{
|
||||||
// AdcNetMessageSeqInterface<ByteStorageT, ByteViewT>::_bytes - tokens
|
// AdcNetMessageSeqInterface<ByteStorageT, ByteViewT>::_bytes - tokens
|
||||||
using base_t = AdcNetMessageSeqInterface<ByteStorageT, ByteViewT>;
|
using base_t = AdcNetMessageInterface<ByteStorageT, ByteViewT>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
|
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
|
||||||
@ -457,7 +391,7 @@ public:
|
|||||||
using base_t::tokens;
|
using base_t::tokens;
|
||||||
|
|
||||||
|
|
||||||
AdcKeyTokenNetMessage()
|
AdcKeyTokenNetMessage() : base_t()
|
||||||
{
|
{
|
||||||
this->_reservedNum = 1; // reserve the first element for keyword
|
this->_reservedNum = 1; // reserve the first element for keyword
|
||||||
this->_bytes.resize(this->_reservedNum);
|
this->_bytes.resize(this->_reservedNum);
|
||||||
@ -599,4 +533,29 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace traits
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept adc_netmessage_c = requires {
|
||||||
|
typename T::byte_storage_t;
|
||||||
|
typename T::byte_view_t;
|
||||||
|
std::derived_from<T, AdcNetMessageInterface<typename T::byte_storage_t, typename T::byte_view_t>>;
|
||||||
|
};
|
||||||
|
// template <typename T, typename IT>
|
||||||
|
// concept adc_netmessage_c = requires(const T t) { // const methods
|
||||||
|
// requires std::same_as<std::iter_value_t<IT>, char>;
|
||||||
|
// { t.empty() } -> std::convertible_to<bool>;
|
||||||
|
// { t.byteSize() } -> std::convertible_to<size_t>;
|
||||||
|
// { t.bytes() } -> adc_output_char_range;
|
||||||
|
// { t.byteView() } -> adc_range_of_view_char_range;
|
||||||
|
// { t.setFromBytes(std::input_iterator<IT>) } -> std::same_as<void>;
|
||||||
|
// };
|
||||||
|
|
||||||
|
} // namespace traits
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace adc
|
} // namespace adc
|
||||||
|
|||||||
@ -11,12 +11,13 @@ ABSTRACT DEVICE COMPONENTS LIBRARY
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
#include "adc_netmsg.h"
|
||||||
|
|
||||||
namespace adc
|
namespace adc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
template <typename NetMessageT, typename ImplT>
|
template <typename ImplT>
|
||||||
class AdcNetService
|
class AdcNetService
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -56,13 +57,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename... ArgTs>
|
template <traits::adc_netmessage_c NetMessageT, typename... ArgTs>
|
||||||
auto asyncSend(const NetMessageT& msg, const timeout_drtn_t& timeout = defaultSendTimeout, ArgTs&&... args)
|
auto asyncSend(const NetMessageT& msg, const timeout_drtn_t& timeout = defaultSendTimeout, ArgTs&&... args)
|
||||||
{
|
{
|
||||||
return _impl.asyncSend(msg, timeout, std::forward<ArgTs>(args)...);
|
return _impl.asyncSend(msg, timeout, std::forward<ArgTs>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... ArgTs>
|
template <traits::adc_netmessage_c NetMessageT, typename... ArgTs>
|
||||||
auto asyncReceive(const timeout_drtn_t& timeout = defaultRecvTimeout, ArgTs&&... args)
|
auto asyncReceive(const timeout_drtn_t& timeout = defaultRecvTimeout, ArgTs&&... args)
|
||||||
{
|
{
|
||||||
return _impl.asyncReceive(timeout, std::forward<ArgTs>(args)...);
|
return _impl.asyncReceive(timeout, std::forward<ArgTs>(args)...);
|
||||||
@ -78,14 +79,14 @@ public:
|
|||||||
return _impl.connect(endpoint, timeout, std::forward<ArgTs>(args)...);
|
return _impl.connect(endpoint, timeout, std::forward<ArgTs>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... ArgTs>
|
template <traits::adc_netmessage_c NetMessageT, typename... ArgTs>
|
||||||
auto send(const NetMessageT& msg, const timeout_drtn_t& timeout = defaultSendTimeout, ArgTs&&... args)
|
auto send(const NetMessageT& msg, const timeout_drtn_t& timeout = defaultSendTimeout, ArgTs&&... args)
|
||||||
{
|
{
|
||||||
return _impl.send(msg, timeout, std::forward<ArgTs>(args)...);
|
return _impl.send(msg, timeout, std::forward<ArgTs>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename... ArgTs>
|
template <traits::adc_netmessage_c NetMessageT, typename... ArgTs>
|
||||||
NetMessageT receive(const timeout_drtn_t& timeout = defaultRecvTimeout, ArgTs&&... args)
|
NetMessageT receive(const timeout_drtn_t& timeout = defaultRecvTimeout, ArgTs&&... args)
|
||||||
{
|
{
|
||||||
return _impl.receive(timeout, std::forward<ArgTs>(args)...);
|
return _impl.receive(timeout, std::forward<ArgTs>(args)...);
|
||||||
@ -102,11 +103,11 @@ public:
|
|||||||
namespace traits
|
namespace traits
|
||||||
{
|
{
|
||||||
|
|
||||||
// template <typename T>
|
template <typename T>
|
||||||
// concept adc_netservice_c = requires {
|
concept adc_netservice_c = requires {
|
||||||
// typename T::impl_t;
|
typename T::impl_t;
|
||||||
// std::derived_from<AdcNetService<typename T::impl_t>>;
|
std::derived_from<T, AdcNetService<typename T::impl_t>>;
|
||||||
// };
|
};
|
||||||
|
|
||||||
} // namespace traits
|
} // namespace traits
|
||||||
|
|
||||||
|
|||||||
@ -10,15 +10,19 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include "adc_netservice.h"
|
||||||
#ifdef USE_ASIO_LIBRARY
|
#ifdef USE_ASIO_LIBRARY
|
||||||
|
|
||||||
#include <asio/awaitable.hpp>
|
// #include <asio/awaitable.hpp>
|
||||||
#include <asio/basic_datagram_socket.hpp>
|
#include <asio/basic_datagram_socket.hpp>
|
||||||
#include <asio/basic_seq_packet_socket.hpp>
|
#include <asio/basic_seq_packet_socket.hpp>
|
||||||
#include <asio/basic_stream_socket.hpp>
|
#include <asio/basic_stream_socket.hpp>
|
||||||
#include <asio/compose.hpp>
|
#include <asio/compose.hpp>
|
||||||
#include <asio/experimental/awaitable_operators.hpp>
|
// #include <asio/experimental/awaitable_operators.hpp>
|
||||||
|
#include <asio/ip/tcp.hpp>
|
||||||
#include <asio/read_until.hpp>
|
#include <asio/read_until.hpp>
|
||||||
|
#include <asio/ssl.hpp>
|
||||||
|
#include <asio/ssl/stream.hpp>
|
||||||
#include <asio/steady_timer.hpp>
|
#include <asio/steady_timer.hpp>
|
||||||
#include <asio/streambuf.hpp>
|
#include <asio/streambuf.hpp>
|
||||||
#include <asio/use_future.hpp>
|
#include <asio/use_future.hpp>
|
||||||
@ -26,11 +30,14 @@
|
|||||||
|
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
|
||||||
|
|
||||||
|
#include "adc_netmsg.h"
|
||||||
|
|
||||||
namespace adc::impl
|
namespace adc::impl
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
template <typename NetMessageT, typename InetProtoT>
|
template <typename InetProtoT>
|
||||||
class AdcNetServiceASIO : public InetProtoT
|
class AdcNetServiceASIO : public InetProtoT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -63,7 +70,12 @@ public:
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case starting:
|
case starting:
|
||||||
state = cancel_timer;
|
state = cancel_timer;
|
||||||
return _socket.async_connect(endpoint, std::move(self));
|
if constexpr (std::derived_from<socket_t,
|
||||||
|
asio::ssl::stream<typename socket_t::lowest_layer_type>>) {
|
||||||
|
return _socket.lowest_layer().async_connect(endpoint, std::move(self));
|
||||||
|
} else {
|
||||||
|
return _socket.async_connect(endpoint, std::move(self));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case cancel_timer:
|
case cancel_timer:
|
||||||
timer->cancel();
|
timer->cancel();
|
||||||
@ -78,7 +90,9 @@ public:
|
|||||||
token, _socket);
|
token, _socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TimeoutT, asio::completion_token_for<void(std::error_code)> CompletionTokenT>
|
template <traits::adc_netmessage_c NetMessageT,
|
||||||
|
typename TimeoutT,
|
||||||
|
asio::completion_token_for<void(std::error_code)> CompletionTokenT>
|
||||||
auto asynSend(const NetMessageT& msg, const TimeoutT& timeout, CompletionTokenT&& token)
|
auto asynSend(const NetMessageT& msg, const TimeoutT& timeout, CompletionTokenT&& token)
|
||||||
{
|
{
|
||||||
enum { starting, cancel_timer };
|
enum { starting, cancel_timer };
|
||||||
@ -93,10 +107,11 @@ public:
|
|||||||
// wrapper
|
// wrapper
|
||||||
return asio::async_compose<CompletionTokenT, void(std::error_code)>(
|
return asio::async_compose<CompletionTokenT, void(std::error_code)>(
|
||||||
[buff = std::move(buff), timer = std::move(timer), state = starting, this](
|
[buff = std::move(buff), timer = std::move(timer), state = starting, this](
|
||||||
auto& self, const std::error_code& ec = {}, size_t sz = 0) mutable {
|
auto& self, const std::error_code& ec = {}, size_t = 0) mutable {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case starting:
|
case starting:
|
||||||
|
state = cancel_timer;
|
||||||
if constexpr (std::derived_from<
|
if constexpr (std::derived_from<
|
||||||
socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
||||||
return asio::async_write(_socket, buff, std::move(self));
|
return asio::async_write(_socket, buff, std::move(self));
|
||||||
@ -124,7 +139,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename TimeoutT, typename CompletionTokenT>
|
template <traits::adc_netmessage_c NetMessageT, typename TimeoutT, typename CompletionTokenT>
|
||||||
auto asyncReceive(const TimeoutT& timeout, CompletionTokenT&& token)
|
auto asyncReceive(const TimeoutT& timeout, CompletionTokenT&& token)
|
||||||
{
|
{
|
||||||
enum { starting, cancel_timer };
|
enum { starting, cancel_timer };
|
||||||
@ -135,15 +150,16 @@ public:
|
|||||||
|
|
||||||
return asio::async_compose<CompletionTokenT, void(const std::error_code&, const NetMessageT&)>(
|
return asio::async_compose<CompletionTokenT, void(const std::error_code&, const NetMessageT&)>(
|
||||||
[timer = std::move(timer), out_flags = std::move(out_flags), state = starting, this](
|
[timer = std::move(timer), out_flags = std::move(out_flags), state = starting, this](
|
||||||
auto& self, const std::error_code& ec = {}, size_t sz = 0) mutable {
|
auto& self, const std::error_code& ec = {}, size_t = 0) mutable {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case starting:
|
case starting:
|
||||||
|
state = cancel_timer;
|
||||||
if constexpr (std::derived_from<
|
if constexpr (std::derived_from<
|
||||||
socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
||||||
return asio::async_read_until(
|
return asio::async_read_until(
|
||||||
_socket, _streamBuffer,
|
_socket, _streamBuffer,
|
||||||
[this](auto begin, auto end) { this->matchCondition(begin, end); },
|
[this](auto begin, auto end) { return this->matchCondition(begin, end); },
|
||||||
std::move(self));
|
std::move(self));
|
||||||
} else if constexpr (std::derived_from<socket_t, asio::basic_datagram_socket<
|
} else if constexpr (std::derived_from<socket_t, asio::basic_datagram_socket<
|
||||||
typename socket_t::protocol_type>>) {
|
typename socket_t::protocol_type>>) {
|
||||||
@ -200,20 +216,43 @@ public:
|
|||||||
ftr.get();
|
ftr.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TimeoutT>
|
template <traits::adc_netmessage_c NetMessageT, typename TimeoutT>
|
||||||
auto send(const NetMessageT& msg, const TimeoutT& timeout)
|
auto send(const NetMessageT& msg, const TimeoutT& timeout)
|
||||||
{
|
{
|
||||||
std::future<void> ftr = asyncSend(msg, timeout, asio::use_future);
|
std::future<void> ftr = asyncSend(msg, timeout, asio::use_future);
|
||||||
ftr.get();
|
ftr.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TimeoutT>
|
template <traits::adc_netmessage_c NetMessageT, typename TimeoutT>
|
||||||
auto receive(const TimeoutT& timeout)
|
auto receive(const TimeoutT& timeout)
|
||||||
{
|
{
|
||||||
std::future<NetMessageT> ftr = asyncReceive(timeout, asio::use_future);
|
std::future<NetMessageT> ftr = asyncReceive(timeout, asio::use_future);
|
||||||
return ftr.get();
|
return ftr.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::error_code close(asio::socket_base::shutdown_type stype = asio::socket_base::shutdown_both)
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
if constexpr (std::derived_from<socket_t, asio::ssl::stream<typename socket_t::lowest_layer_type>>) {
|
||||||
|
_socket.shutdown(ec); // shutdown OpenSSL stream
|
||||||
|
if (!ec) {
|
||||||
|
_socket.lowest_layer().shutdown(stype, ec);
|
||||||
|
if (!ec) {
|
||||||
|
_socket.lowest_layer().close(ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_socket.shutdown(stype, ec);
|
||||||
|
if (!ec) {
|
||||||
|
_socket.close(ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
socket_t& _socket;
|
socket_t& _socket;
|
||||||
|
|
||||||
@ -242,4 +281,11 @@ protected:
|
|||||||
} // namespace adc::impl
|
} // namespace adc::impl
|
||||||
|
|
||||||
|
|
||||||
|
namespace adc
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef AdcNetService<impl::AdcNetServiceASIO<asio::ip::tcp>> AdcNetServiceAsioTcp;
|
||||||
|
|
||||||
|
} // namespace adc
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user