AdcNetServiceASIO/AdcNetServiceASIOTLS: new implementation

This commit is contained in:
Timur A. Fatkhullin
2024-10-26 20:56:05 +03:00
parent 062c26537d
commit a496758ca4
4 changed files with 1071 additions and 327 deletions

View File

@@ -1,5 +1,6 @@
#pragma once
#include <asio/any_completion_handler.hpp>
#include <asio/basic_datagram_socket.hpp>
#include <asio/basic_seq_packet_socket.hpp>
#include <asio/basic_stream_socket.hpp>
@@ -33,7 +34,6 @@
#include "../../common/adc_traits.h"
#include "../adc_net_concepts.h"
#include "../adc_netproto.h"
namespace adc::traits
{
@@ -66,15 +66,10 @@ struct adc_func_traits<asio::deferred_t> {
} // namespace adc::traits
namespace adc::impl
{
// typedef for ASIO streambuf iterators
using asio_streambuff_iter_t = asio::buffers_iterator<asio::streambuf::const_buffers_type>;
// ASIO match condition result typedef
using asio_matchcond_result_t = std::pair<asio_streambuff_iter_t, bool>;
template <typename T>
concept adc_asio_transport_proto_c =
std::derived_from<T, asio::ip::tcp> || std::derived_from<T, asio::ip::udp> ||
@@ -112,16 +107,27 @@ concept adc_asio_special_comp_token_c =
template <adc_asio_transport_proto_c TRANSPORT_PROTOT,
interfaces::adc_netsession_proto_c<std::string_view> SESSION_PROTOT,
traits::adc_output_char_range RMSGT =
std::vector<char>> // used only for inner storing of message byte sequence
class AdcNetServiceASIOBase : public SESSION_PROTOT
template <
bool USE_TLS, // true - use of asio::ssl::stream<TRANSPORT_PROTOT>
adc_asio_transport_proto_c TRANSPORT_PROTOT, // transport-level proto (e.g. asio::ip::tcp)
interfaces::adc_netsession_proto_c<std::string_view> SESSION_PROTOT, // session-level proto (see ../adc_netproto.h)
traits::adc_output_char_range RMSGT = std::vector<char>> // used only for inner storing of message byte sequence
class AdcBaseNetServiceASIO : public SESSION_PROTOT
{
public:
#ifdef USE_OPENSSL_WITH_ASIO
static_assert(!(USE_TLS && adc_asio_tls_transport_proto_c<TRANSPORT_PROTOT>),
"INVALID 'TRANSPORT_PROTOT' TEMPLATE ARGUMENT!");
static constexpr bool isTLS = USE_TLS;
#else // ignore USE_TLS
static constexpr bool isTLS = false;
#endif
// typedefs to satisfy 'adc_netservice_c' concept
typedef std::string_view netservice_ident_t;
typedef std::vector<char> send_msg_t; // in general, only one of several possible
typedef RMSGT recv_msg_t; // in general, only one of several possible (see class template arguments declaration)
typedef traits::adc_common_duration_t timeout_t;
@@ -134,103 +140,102 @@ public:
// typedefs from transport protocol
using socket_t = typename TRANSPORT_PROTOT::socket;
using tls_stream_t = std::nullptr_t;
using socket_t = typename TRANSPORT_PROTOT::socket; // low-level socket type
#ifdef USE_OPENSSL_WITH_ASIO
using session_level_socket_t = std::conditional_t<isTLS, asio::ssl::stream<socket_t>, std::nullptr_t>;
// TLS certificate attributes comparison function:
// 'serial' - as returned by OpenSSL BN_bn2hex
// 'fingerprint' - as returned by OpenSSL X509_digest
// 'depth' - depth in chain
// the function must return 0 - if comparison failed; otherwise - something != 0
typedef std::function<int(const std::string& serial, const std::vector<unsigned char>& fingerprint, int depth)>
cert_comp_func_t;
#else
using session_level_socket_t = socket_t;
#endif
struct acceptor_t {
using srv_acceptor_t = std::conditional_t<
std::derived_from<socket_t, asio::basic_datagram_socket<typename socket_t::protocol_type>>,
std::nullptr_t, // there is no acceptor
typename TRANSPORT_PROTOT::acceptor>;
// acceptor
class acceptor_t
{
public:
static constexpr std::chrono::duration DEFAULT_ACCEPT_TIMEOUT = std::chrono::seconds::max();
acceptor_t(asio::io_context& io_ctx)
: _ioContext(io_ctx), _endpoint(), _socket(_ioContext), _acceptor(_ioContext)
{
}
acceptor_t(asio::io_context& io_ctx, const AdcNetServiceASIOBase::endpoint_t& endpoint)
: _ioContext(io_ctx), _endpoint(endpoint), _socket(_ioContext), _acceptor(_ioContext, endpoint)
{
}
virtual ~acceptor_t() = default;
typedef AdcNetServiceASIOBase netservice_t;
typedef std::shared_ptr<netservice_t> sptr_netservice_t;
typedef AdcBaseNetServiceASIO netservice_t;
typedef std::function<void(std::error_code, netservice_t)> async_accept_callback_t;
// typedef std::function<void(std::error_code, sptr_netservice_t)> async_accept_callback_t;
// template <asio::completion_token_for<void(std::error_code, sptr_netservice_t)> TokenT,
acceptor_t(asio::io_context& io_context) : _ioContext(io_context), _acceptor(io_context) {}
acceptor_t(asio::io_context& io_context, const netservice_t::endpoint_t& endpoint)
: _ioContext(io_context), _acceptor(io_context, endpoint)
{
}
template <asio::completion_token_for<void(std::error_code, netservice_t)> TokenT,
traits::adc_time_duration_c DT = decltype(DEFAULT_ACCEPT_TIMEOUT)>
auto asyncAccept(TokenT&& token, const DT& timeout = DEFAULT_ACCEPT_TIMEOUT)
{
enum { start_state, handshake_state, stop_state };
enum { sock_accept, handshake, done };
// no acceptor for UDP-sockets
if constexpr (std::is_null_pointer_v<_acceptor_t>) {
static_assert(false, "INVALID TRANSPORT PROTOCOL TYPE!");
}
auto timer = netservice_t::getDeadlineTimer(_acceptor, timeout);
netservice_t srv{_ioContext};
auto srv = std::make_unique<netservice_t>(_ioContext);
_socket = AdcNetServiceASIOBase::socket_t{_ioContext};
auto timer = getDeadlineTimer(_acceptor, timeout);
// return asio::async_compose<TokenT, void(std::error_code, sptr_netservice_t)>(
return asio::async_compose<TokenT, void(std::error_code, netservice_t)>(
[timer = std::move(timer), srv = std::move(srv), state = start_state, this](
[timer = std::move(timer), srv = std::move(srv), state = sock_accept, this](
auto& self, std::error_code ec = {}) mutable {
if (!ec) {
switch (state) {
case start_state:
state = handshake_state;
try {
if (!_acceptor.is_open() || (_acceptor.local_endpoint() != _endpoint)) {
_acceptor = _acceptor_t(_ioContext, _endpoint);
}
} catch (std::system_error err) {
timer->cancel();
self.complete(err.code(), netservice_t{_ioContext});
// self.complete(err.code(), std::make_shared<netservice_t>(_ioContext));
return;
case sock_accept:
if constexpr (netservice_t::isTLS) {
state = handshake;
} else {
state = done;
}
return _acceptor.async_accept(_socket, std::move(self));
return _acceptor.async_accept(srv->_socket, std::move(self));
break;
case handshake_state:
state = stop_state;
case handshake:
state = done;
#ifdef USE_OPENSSL_WITH_ASIO
if constexpr (netservice_t::isTLS) {
srv->_sessSocket =
netservice_t::session_level_socket_t(srv->_socket, srv->_tlsContext);
return srv->_sessSocket.async_handshake(asio::ssl::stream_base::server,
std::move(self));
}
#endif
break;
case stop_state:
finalize();
case done:
break;
default:
break;
}
}
if (isTimeout(timer, ec)) {
if (netservice_t::isTimeout(timer, ec)) {
ec = std::make_error_code(std::errc::timed_out);
} else { // an error occured in async_accept
} else { // an error occured in async_accept od async_handshake
timer->cancel();
}
self.complete(ec, netservice_t(std::move(_socket)));
// self.complete(ec, std::make_shared<netservice_t>(std::move(_socket)));
self.complete(ec, std::move(*srv));
srv.reset();
},
token, _ioContext);
}
template <asio::completion_token_for<void(std::error_code, netservice_t)> TokenT,
traits::adc_time_duration_c DT = decltype(DEFAULT_ACCEPT_TIMEOUT)>
auto asyncAccept(const AdcNetServiceASIOBase::endpoint_t& endpoint,
auto asyncAccept(const netservice_t::endpoint_t& endpoint,
TokenT&& token,
const DT& timeout = DEFAULT_ACCEPT_TIMEOUT)
{
_endpoint = endpoint;
_acceptor = srv_acceptor_t(_ioContext, endpoint);
return asyncAccept(std::forward<TokenT>(token), timeout);
}
@@ -248,35 +253,26 @@ public:
return accept(endpoint, timeout);
}
protected:
private:
asio::io_context& _ioContext;
AdcNetServiceASIOBase::endpoint_t _endpoint;
AdcNetServiceASIOBase::socket_t _socket;
using _acceptor_t = std::conditional_t<
std::derived_from<socket_t, asio::basic_datagram_socket<typename socket_t::protocol_type>>,
std::nullptr_t, // there is no acceptor
typename TRANSPORT_PROTOT::acceptor>;
_acceptor_t _acceptor;
virtual void handshake() {}
virtual void finalize() {}
srv_acceptor_t _acceptor;
};
static constexpr std::chrono::duration DEFAULT_CONNECT_TIMEOUT = std::chrono::seconds(10);
static constexpr std::chrono::duration DEFAULT_SEND_TIMEOUT = std::chrono::seconds(5);
static constexpr std::chrono::duration DEFAULT_RECEIVE_TIMEOUT = std::chrono::seconds(5);
AdcNetServiceASIOBase(asio::io_context& ctx)
/* CONSTRUCTORS AND DESTRUCTOR */
AdcBaseNetServiceASIO(asio::io_context& ctx)
requires(!isTLS)
: SESSION_PROTOT(), _ioContext(ctx), _receiveStrand(_ioContext), _socket(_ioContext), _receiveQueue()
{
}
AdcNetServiceASIOBase(socket_t socket)
AdcBaseNetServiceASIO(socket_t socket)
: SESSION_PROTOT(),
_ioContext(static_cast<asio::io_context&>(socket.get_executor().context())),
_socket(std::move(socket)),
@@ -285,13 +281,28 @@ public:
{
}
#ifdef USE_OPENSSL_WITH_ASIO
AdcBaseNetServiceASIO(asio::io_context& ctx,
const asio::ssl::context& tls_context,
const asio::ssl::verify_mode& tls_peer_verify_mode = asio::ssl::verify_peer)
requires isTLS
: SESSION_PROTOT(),
_ioContext(ctx),
_receiveStrand(_ioContext),
_socket(_ioContext),
_receiveQueue(),
_tlsContext(tls_context),
_tlsPeerVerifyMode(tls_peer_verify_mode)
{
}
#endif
// NOTE: CANNOT MOVE asio::streambuf CORRECTLY?!!!
// AdcNetServiceASIOBase(AdcNetServiceASIOBase&& other) = default;
AdcNetServiceASIOBase(AdcNetServiceASIOBase&& other)
AdcBaseNetServiceASIO(AdcBaseNetServiceASIO&& other)
: _ioContext(other._ioContext),
_receiveStrand(std::move(other._receiveStrand)),
_socket(std::move(other._socket)),
_sessSocket(std::move(other._sessSocket)),
_streamBuffer(),
_receiveQueue(std::move(other._receiveQueue))
@@ -301,17 +312,14 @@ public:
}
// AdcNetServiceASIOBase(AdcNetServiceASIOBase&& other) = delete;
AdcNetServiceASIOBase(const AdcNetServiceASIOBase&) = delete; // no copy constructor!
AdcBaseNetServiceASIO(const AdcBaseNetServiceASIO&) = delete; // no copy constructor!
virtual ~AdcNetServiceASIOBase() {}
virtual ~AdcBaseNetServiceASIO() {}
AdcNetServiceASIOBase& operator=(const AdcNetServiceASIOBase&) = delete;
AdcBaseNetServiceASIO& operator=(const AdcBaseNetServiceASIO&) = delete;
// AdcNetServiceASIOBase& operator=(AdcNetServiceASIOBase&& other) = delete;
// AdcNetServiceASIOBase& operator=(AdcNetServiceASIOBase&& other) = default;
AdcNetServiceASIOBase& operator=(AdcNetServiceASIOBase&& other)
AdcBaseNetServiceASIO& operator=(AdcBaseNetServiceASIO&& other)
{
_ioContext = other._ioContext;
_receiveStrand = std::move(other._receiveStrand);
@@ -335,25 +343,47 @@ public:
/* asynchronuos methods */
template <asio::completion_token_for<void(std::error_code)> TokenT,
traits::adc_time_duration_c TimeoutT = decltype(DEFAULT_CONNECT_TIMEOUT)>
auto asyncConnect(const endpoint_t& endpoint, TokenT&& token, const TimeoutT& timeout = DEFAULT_CONNECT_TIMEOUT)
{
enum { sock_connect, handshake, done };
auto timer = getDeadlineTimer(_socket, timeout);
return asio::async_compose<TokenT, void(std::error_code)>(
[start = true, endpoint, timer = std::move(timer), this](auto& self, std::error_code ec = {}) mutable {
[state = sock_connect, endpoint, timer = std::move(timer), this](auto& self,
std::error_code ec = {}) mutable {
if (!ec) {
if (start) {
start = false;
return _socket.async_connect(endpoint, std::move(self));
switch (state) {
case sock_connect:
if constexpr (isTLS) {
state = handshake;
} else {
state = done;
}
return _socket.async_connect(endpoint, std::move(self));
break;
case handshake:
state = done;
#ifdef USE_OPENSSL_WITH_ASIO
if constexpr (isTLS) {
_sessSocket = session_level_socket_t(_socket, _tlsContext);
return _sessSocket.async_handshake(session_level_socket_t::client, std::move(self));
}
#endif
break;
case done:
break;
default:
break;
}
}
if (isTimeout(timer, ec)) {
ec = std::make_error_code(std::errc::timed_out);
} else { // an error occured in async_connect
} else { // an error occured in async_connect or async_handshake
timer->cancel();
}
@@ -382,17 +412,21 @@ public:
if (!ec) {
if (start) {
start = false;
if constexpr (std::derived_from<socket_t,
asio::basic_stream_socket<typename socket_t::protocol_type>>) {
return asio::async_write(_socket, buff_seq, 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_seq, 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_seq, std::move(self));
if constexpr (isTLS) {
return asio::async_write(_sessSocket, buff_seq, std::move(self));
} else {
static_assert(false, "UNKNOWN ASIO-LIBRARY SOCKET TYPE!!!");
if constexpr (std::derived_from<
socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
return asio::async_write(_socket, buff_seq, 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_seq, 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_seq, std::move(self));
} else {
static_assert(false, "UNKNOWN ASIO-LIBRARY SOCKET TYPE!!!");
}
}
}
}
@@ -455,22 +489,30 @@ public:
}
auto n_avail = _socket.available();
if (!n_avail) {
return _socket.async_wait(asio::ip::tcp::socket::wait_read, std::move(self));
}
auto buff = _streamBuffer.prepare(n_avail ? n_avail : 1);
if constexpr (std::derived_from<socket_t,
asio::basic_stream_socket<typename socket_t::protocol_type>>) {
return asio::async_read(_socket, std::move(buff), asio::transfer_at_least(1),
if constexpr (isTLS) {
return asio::async_read(_sessSocket, std::move(buff), asio::transfer_at_least(1),
std::move(self));
} else if constexpr (std::derived_from<socket_t, asio::basic_datagram_socket<
typename socket_t::protocol_type>>) {
// datagram, so it should be received at once
return _socket.async_receive(std::move(buff), std::move(self));
} else if constexpr (std::derived_from<socket_t, asio::basic_seq_packet_socket<
typename socket_t::protocol_type>>) {
// datagram, so it should be received at once
return _socket.async_receive(std::move(buff), *out_flags, std::move(self));
} else {
static_assert(false, "UNKNOWN ASIO-LIBRARY SOCKET TYPE!!!");
if constexpr (std::derived_from<
socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
return asio::async_read(_socket, std::move(buff), asio::transfer_at_least(1),
std::move(self));
} else if constexpr (std::derived_from<socket_t, asio::basic_datagram_socket<
typename socket_t::protocol_type>>) {
// datagram, so it should be received at once
return _socket.async_receive(std::move(buff), std::move(self));
} else if constexpr (std::derived_from<socket_t, asio::basic_seq_packet_socket<
typename socket_t::protocol_type>>) {
// datagram, so it should be received at once
return _socket.async_receive(std::move(buff), *out_flags, std::move(self));
} else {
static_assert(false, "UNKNOWN ASIO-LIBRARY SOCKET TYPE!!!");
}
}
}
@@ -573,6 +615,12 @@ public:
{
std::error_code ec;
#ifdef USE_OPENSSL_WITH_ASIO
if constexpr (isTLS) {
_sessSocket.shutdown(_shutdownType, ec);
}
#endif
_socket.shutdown(_shutdownType, ec);
if (!ec) {
_socket.close(ec);
@@ -633,7 +681,6 @@ protected:
asio::io_context::strand _receiveStrand;
socket_t _socket;
tls_stream_t _tlsStream;
asio::streambuf _streamBuffer;
@@ -641,195 +688,14 @@ protected:
asio::socket_base::shutdown_type _shutdownType = asio::socket_base::shutdown_both;
template <typename CancelableT, traits::adc_time_duration_c TimeoutT>
static std::unique_ptr<asio::steady_timer> getDeadlineTimer(CancelableT& obj,
const TimeoutT& timeout,
bool arm = true)
{
auto timer = std::make_unique<asio::steady_timer>(obj.get_executor());
// if (timeout == std::chrono::duration<typename TimeoutT::rep, typename TimeoutT::period>::max()) {
// return timer; // do not arm the timer if MAX duration are given
// }
if (arm) {
std::chrono::seconds max_d = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::steady_clock::time_point::max() - std::chrono::steady_clock::now() -
std::chrono::seconds(1));
timer->expires_after(timeout < max_d ? timeout : max_d); // to avoid overflow!
// timer->expires_after(timeout);
timer->async_wait([&obj](const std::error_code& ec) mutable {
if (!ec) {
obj.cancel();
}
});
}
return timer;
}
template <typename TimerT>
static bool isTimeout(const std::unique_ptr<TimerT>& timer, const std::error_code& ec)
{
auto exp_time = timer->expiry();
return (exp_time < std::chrono::steady_clock::now()) && (ec == asio::error::operation_aborted);
}
};
#ifdef USE_OPENSSL_WITH_ASIO
/*
template <adc_asio_tls_transport_proto_c TRANSPORT_PROTOT,
interfaces::adc_netsession_proto_c<std::string_view> SESSION_PROTOT,
traits::adc_output_char_range RMSGT =
std::vector<char>> // used only for inner storing of message byte sequence
class AdcNetServiceASIOTLS : public AdcNetServiceASIOBase<TRANSPORT_PROTOT, SESSION_PROTOT, RMSGT>
{
typedef AdcNetServiceASIOBase<TRANSPORT_PROTOT, SESSION_PROTOT, RMSGT> service_base_t;
public:
using typename service_base_t::socket_t;
typedef asio::ssl::stream<socket_t> tls_stream_t;
// TLS certificate attributes comparison function:
// 'serial' - as returned by OpenSSL BN_bn2hex
// 'fingerprint' - as returned by OpenSSL X509_digest
// 'depth' - depth in chain
// the function must return 0 - if comparison failed; otherwise - something != 0
typedef std::function<int(const std::string& serial, const std::vector<unsigned char>& fingerprint, int depth)>
cert_comp_func_t;
// reimplement acceptor class
class acceptor_t
{
public:
static constexpr std::chrono::duration DEFAULT_ACCEPT_TIMEOUT = std::chrono::seconds::max();
typedef AdcNetServiceASIOTLS netservice_t;
typedef std::shared_ptr<netservice_t> sptr_netservice_t;
acceptor_t(asio::io_context& io_ctx, asio::ssl::context tls_context)
: _ioContext(io_ctx), _endpoint(), _socket(_ioContext), _acceptor(_ioContext)
{
}
acceptor_t(asio::io_context& io_ctx, const service_base_t::endpoint_t& endpoint, asio::ssl::context tls_context)
: _ioContext(io_ctx), _endpoint(endpoint), _socket(_ioContext), _acceptor(_ioContext, endpoint)
{
}
typedef std::function<void(std::error_code, netservice_t)> async_accept_callback_t;
template <asio::completion_token_for<void(std::error_code, netservice_t)> TokenT,
traits::adc_time_duration_c DT = decltype(DEFAULT_ACCEPT_TIMEOUT)>
auto asyncAccept(TokenT&& token, const DT& timeout = DEFAULT_ACCEPT_TIMEOUT)
{
enum { start, handshake, stop };
this->_socket = AdcNetServiceASIOTLS::socket_t(this->_ioContext);
auto timer = getDeadlineTimer(this->_acceptor, timeout);
netservice_t srv(_ioContext);
return asio::async_compose<TokenT, void(std::error_code, netservice_t)>(
[timer = std::move(timer), srv = std::move(srv), state = start, this](auto& self,
std::error_code ec = {}) mutable {
if (!ec) {
switch (state) {
case start:
state = handshake;
try {
if (!_acceptor.is_open() || (_acceptor.local_endpoint() != _endpoint)) {
_acceptor = _acceptor_t(_ioContext, _endpoint);
}
} catch (std::system_error err) {
timer->cancel();
self.complete(err.code(), netservice_t{_ioContext});
// self.complete(err.code(), std::make_shared<netservice_t>(_ioContext));
return;
}
return _acceptor.async_accept(_socket, std::move(self));
break;
case handshake:
state = stop;
srv._socket = std::move(_socket);
srv._tlsStream = asio::ssl::stream(srv._socket, _tlsContext);
return srv._tlsStream.async_handshake(asio::ssl::stream_base::server, std::move(self));
default:
break;
}
}
if (isTimeout(timer, ec)) {
ec = std::make_error_code(std::errc::timed_out);
} else { // an error occured in async_accept od async_handshake
timer->cancel();
}
self.complete(ec, std::move(srv));
},
token, this->_ioContext);
}
template <asio::completion_token_for<void(std::error_code, netservice_t)> TokenT,
traits::adc_time_duration_c DT = decltype(DEFAULT_ACCEPT_TIMEOUT)>
auto asyncAccept(const AdcNetServiceASIOTLS::endpoint_t& endpoint,
TokenT&& token,
const DT& timeout = DEFAULT_ACCEPT_TIMEOUT)
{
this->_endpoint = endpoint;
return asyncAccept(std::forward<TokenT>(token), timeout);
}
protected:
asio::io_context& _ioContext;
AdcNetServiceASIOTLS::endpoint_t _endpoint;
AdcNetServiceASIOTLS::socket_t _socket;
asio::ssl::context& _tlsContext;
using _acceptor_t = std::conditional_t<
std::derived_from<socket_t, asio::basic_datagram_socket<typename socket_t::protocol_type>>,
std::nullptr_t, // there is no acceptor
typename TRANSPORT_PROTOT::acceptor>;
_acceptor_t _acceptor;
};
std::error_code close()
{
std::error_code ec;
this->_sock_stream.shutdown(ec); // shutdown OpenSSL stream
if (!ec) {
this->_sock_stream.lowest_layer().shutdown(this->_shutdownType, ec);
if (!ec) {
this->_sock_stream.lowest_layer().close(ec);
}
}
return ec;
}
protected:
tls_stream_t _tlsStream;
asio::ssl::context _tlsContext;
session_level_socket_t _sessSocket;
std::conditional_t<isTLS, asio::ssl::context, std::nullptr_t> _tlsContext;
asio::ssl::verify_mode _tlsPeerVerifyMode;
std::string _tlsCertFingerprintDigest;
cert_comp_func_t _tlsCertCompFunc;
std::string _tlsCertFingerprintDigest;
asio::streambuf _streamBuffer;
// reference implementation
// reference implementation fo certificate verification function
virtual bool verifyCertificate(int preverified_ok, X509_STORE_CTX* store)
{
if (preverified_ok == 0) {
@@ -885,16 +751,72 @@ protected:
return preverified_ok;
}
};
*/
#endif
static_assert(adc::interfaces::adc_netservice_c<AdcNetServiceASIOBase<asio::ip::tcp, adc::AdcStopSeqSessionProto<>>>,
"");
template <typename CancelableT, traits::adc_time_duration_c TimeoutT>
static std::unique_ptr<asio::steady_timer> getDeadlineTimer(CancelableT& obj,
const TimeoutT& timeout,
bool arm = true)
{
auto timer = std::make_unique<asio::steady_timer>(obj.get_executor());
static_assert(adc::interfaces::adc_netsession_proto_c<adc::AdcStopSeqSessionProto<>>, "");
// if (timeout == std::chrono::duration<typename TimeoutT::rep, typename TimeoutT::period>::max()) {
// return timer; // do not arm the timer if MAX duration are given
// }
if (arm) {
std::chrono::seconds max_d = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::steady_clock::time_point::max() - std::chrono::steady_clock::now() -
std::chrono::seconds(1));
timer->expires_after(timeout < max_d ? timeout : max_d); // to avoid overflow!
// timer->expires_after(timeout);
timer->async_wait([&obj](const std::error_code& ec) mutable {
if (!ec) {
obj.cancel();
}
});
}
return timer;
}
template <typename TimerT>
static bool isTimeout(const std::unique_ptr<TimerT>& timer, const std::error_code& ec)
{
auto exp_time = timer->expiry();
return (exp_time < std::chrono::steady_clock::now()) && (ec == asio::error::operation_aborted);
}
template <typename TimerT>
static bool isTimeout(const std::shared_ptr<TimerT>& timer, const std::error_code& ec)
{
auto exp_time = timer->expiry();
return (exp_time < std::chrono::steady_clock::now()) && (ec == asio::error::operation_aborted);
}
};
/* */
template <
adc_asio_transport_proto_c TRANSPORT_PROTOT, // transport-level proto (e.g. asio::ip::tcp)
interfaces::adc_netsession_proto_c<std::string_view> SESSION_PROTOT, // session-level proto (see ../adc_netproto.h)
traits::adc_output_char_range RMSGT = std::vector<char>> // used only for inner storing of message byte sequence
using AdcNetServiceASIO = AdcBaseNetServiceASIO<false, TRANSPORT_PROTOT, SESSION_PROTOT, RMSGT>;
#ifdef USE_OPENSSL_WITH_ASIO
template <
adc_asio_transport_proto_c TRANSPORT_PROTOT, // transport-level proto (e.g. asio::ip::tcp)
interfaces::adc_netsession_proto_c<std::string_view> SESSION_PROTOT, // session-level proto (see ../adc_netproto.h)
traits::adc_output_char_range RMSGT = std::vector<char>> // used only for inner storing of message byte sequence
using AdcNetServiceASIOTLS = AdcBaseNetServiceASIO<true, TRANSPORT_PROTOT, SESSION_PROTOT, RMSGT>;
#endif
} // namespace adc::impl