...
This commit is contained in:
parent
b8fdae9d16
commit
0d62c9defc
@ -626,6 +626,26 @@ static auto AdcSplitCharRange(R&& r, DR&& delim, size_t start = 0, size_t num =
|
||||
}
|
||||
|
||||
|
||||
static constexpr bool AdcCharRangeCompare(const traits::adc_char_view auto& what,
|
||||
const traits::adc_char_view auto& where,
|
||||
bool case_insensitive = false)
|
||||
{
|
||||
if (std::ranges::size(what) == std::ranges::size(where)) {
|
||||
if (case_insensitive) {
|
||||
auto f = std::ranges::search(where,
|
||||
std::views::transform(what, [](const char& ch) { return std::tolower(ch); }));
|
||||
return !f.empty();
|
||||
} else {
|
||||
auto f = std::ranges::search(where, what);
|
||||
return !f.empty();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FVN-1a hash function
|
||||
template <traits::adc_input_char_range R>
|
||||
static constexpr size_t AdcFNV1aHash(const R& r)
|
||||
|
||||
@ -205,7 +205,7 @@ protected:
|
||||
|
||||
public:
|
||||
template <interfaces::adc_netservice_c NetServiceT>
|
||||
class Session : std::enable_shared_from_this<Session<NetServiceT>>
|
||||
class Session : public std::enable_shared_from_this<Session<NetServiceT>>
|
||||
{
|
||||
public:
|
||||
typedef std::string netsession_ident_t;
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../common/adc_utils.h"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
ABSTRACT DEVICE COMPONENTS LIBRARY
|
||||
@ -19,13 +22,18 @@ namespace adc
|
||||
* Very simple various protocols endpoint parser and holder class
|
||||
*
|
||||
* endpoint: proto_mark://host_name:port_num/path
|
||||
* where "part" is optional for all protocol kinds;
|
||||
* where "part" is optional for all non-local protocol kinds;
|
||||
*
|
||||
* for the "local" kind protocol the endpoint string must consists of
|
||||
* only "proto_mark" and "host_name" fields
|
||||
* (e.g.: local://APP_UNIX_SOCKET)
|
||||
* for local kind of protocols the endpoint must be given as:
|
||||
* local://stream/PATH
|
||||
* local://datagram/PATH
|
||||
* local://seqpacket/PATH
|
||||
* where 'stream', 'datagram' and 'seqpacket' "host_name"-field marks the
|
||||
* stream-type, datagram-type and seqpacket-type UNIX domain sockets protocols.
|
||||
* here, possible "port_num" field is allowed but ignored.
|
||||
*
|
||||
* NOTE: "proto_mark" and "host_name" (for local kind) fields are parsed in case-insensitive manner!
|
||||
*
|
||||
* NOTE: "proto_mark" field is parsed as case-insensitive string!
|
||||
*
|
||||
*/
|
||||
|
||||
@ -39,6 +47,7 @@ public:
|
||||
|
||||
enum proto_id_t : uint8_t {
|
||||
PROTO_ID_LOCAL,
|
||||
PROTO_ID_SEQLOCAL,
|
||||
PROTO_ID_TCP,
|
||||
PROTO_ID_TLS,
|
||||
PROTO_ID_UDP,
|
||||
@ -58,6 +67,14 @@ public:
|
||||
protoMarkUDP, protoMarkWS, protoMarkWSS};
|
||||
|
||||
|
||||
static constexpr std::string_view localProtoTypeStream{"stream"}; // UNIX domain stream
|
||||
static constexpr std::string_view localProtoTypeDatagram{"datagram"}; // UNIX domain datagram
|
||||
static constexpr std::string_view localProtoTypeSeqpacket{"seqpacket"}; // UNIX domain seqpacket
|
||||
|
||||
static constexpr std::array validLocalProtoTypes{localProtoTypeStream, localProtoTypeDatagram,
|
||||
localProtoTypeSeqpacket};
|
||||
|
||||
|
||||
template <traits::adc_input_char_range R>
|
||||
AdcEndpointParser(const R& ept)
|
||||
{
|
||||
@ -81,7 +98,8 @@ public:
|
||||
if constexpr (std::is_array_v<std::remove_cvref_t<R>>) {
|
||||
_endpoint = ept;
|
||||
} else {
|
||||
std::ranges::copy(ept, _endpoint);
|
||||
_endpoint.clear();
|
||||
std::ranges::copy(ept, std::back_inserter(_endpoint));
|
||||
}
|
||||
|
||||
auto found = std::ranges::search(_endpoint, protoHostDelim);
|
||||
@ -90,53 +108,59 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
_proto = std::string_view{_endpoint.begin(), found.begin()};
|
||||
// for (auto& valid_proto : validProtoMarks) {
|
||||
// _isValid = _proto == valid_proto;
|
||||
// if (_isValid) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!_isValid) {
|
||||
// return _isValid;
|
||||
// }
|
||||
|
||||
// _isValid = false;
|
||||
|
||||
if (!checkProtoMark(_proto)) {
|
||||
ssize_t idx;
|
||||
if ((idx = checkProtoMark(std::string_view{_endpoint.begin(), found.begin()})) < 0) {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
_proto = validProtoMarks[idx];
|
||||
|
||||
_host = std::string_view{found.end(), _endpoint.end()};
|
||||
if (_proto == protoMarkLocal) { // local proto allows only hostname
|
||||
_path = std::string_view();
|
||||
_port = -1;
|
||||
|
||||
auto f1 = std::ranges::search(_host, portPathDelim);
|
||||
std::string_view port_sv;
|
||||
if (f1.empty() && isLocal()) { // no path, but it is mandatory for 'local'!
|
||||
return _isValid;
|
||||
} else {
|
||||
auto f1 = std::ranges::search(_host, hostPortDelim);
|
||||
std::string_view port_sv;
|
||||
if (f1.empty()) { // no port, but is must be!
|
||||
_host = std::string_view(_host.begin(), f1.begin());
|
||||
|
||||
_path = std::string_view(f1.end(), &*_endpoint.end());
|
||||
|
||||
f1 = std::ranges::search(_host, hostPortDelim);
|
||||
if (f1.empty() && !isLocal()) { // no port, but it is mandatory for non-local!
|
||||
return _isValid;
|
||||
} else {
|
||||
}
|
||||
|
||||
port_sv = std::string_view(f1.end(), _host.end());
|
||||
if (port_sv.size()) {
|
||||
_host = std::string_view(_host.begin(), f1.begin());
|
||||
// port_sv = std::string_view(f1.end(), _endpoint.end());
|
||||
port_sv = std::string_view(f1.end(), &*_endpoint.end());
|
||||
|
||||
f1 = std::ranges::search(port_sv, portPathDelim);
|
||||
if (f1.empty()) {
|
||||
_path = std::string_view();
|
||||
} else {
|
||||
port_sv = std::string_view(port_sv.begin(), f1.begin());
|
||||
if (!isLocal()) {
|
||||
// convert port string to int
|
||||
auto end_ptr = port_sv.data() + port_sv.size();
|
||||
|
||||
_path = std::string_view(f1.end(), &*_endpoint.end());
|
||||
auto [ptr, ec] = std::from_chars(port_sv.data(), end_ptr, _port);
|
||||
if (ec != std::errc() || ptr != end_ptr) {
|
||||
return _isValid;
|
||||
}
|
||||
} else { // ignore for local
|
||||
_port = -1;
|
||||
}
|
||||
} else {
|
||||
_port = -1;
|
||||
}
|
||||
|
||||
// convert port string to int
|
||||
auto end_ptr = port_sv.data() + port_sv.size();
|
||||
|
||||
auto [ptr, ec] = std::from_chars(port_sv.data(), end_ptr, _port);
|
||||
if (ec != std::errc() || ptr != end_ptr) {
|
||||
if (isLocal()) { // check for special values
|
||||
idx = 0;
|
||||
if (std::ranges::any_of(validLocalProtoTypes, [&idx, this](const auto& el) {
|
||||
bool ok = utils::AdcCharRangeCompare(_host, el, true);
|
||||
if (!ok) {
|
||||
++idx;
|
||||
}
|
||||
return ok;
|
||||
})) {
|
||||
_host = validLocalProtoTypes[idx];
|
||||
} else {
|
||||
return _isValid;
|
||||
}
|
||||
}
|
||||
@ -197,6 +221,22 @@ public:
|
||||
return proto() == protoMarkLocal;
|
||||
}
|
||||
|
||||
bool isLocalStream() const
|
||||
{
|
||||
return host() == localProtoTypeStream;
|
||||
}
|
||||
|
||||
bool isLocalDatagram() const
|
||||
{
|
||||
return host() == localProtoTypeDatagram;
|
||||
}
|
||||
|
||||
bool isLocalSeqpacket() const
|
||||
{
|
||||
return host() == localProtoTypeSeqpacket;
|
||||
}
|
||||
|
||||
|
||||
bool isTCP() const
|
||||
{
|
||||
return proto() == protoMarkTCP;
|
||||
@ -229,10 +269,22 @@ protected:
|
||||
bool _isValid;
|
||||
|
||||
|
||||
virtual bool checkProtoMark(std::string_view proto_mark)
|
||||
virtual ssize_t checkProtoMark(std::string_view proto_mark)
|
||||
{
|
||||
return std::ranges::any_of(AdcEndpointParser::validProtoMarks,
|
||||
[proto_mark](const auto& el) { return el == proto_mark; });
|
||||
ssize_t idx = 0;
|
||||
|
||||
// case-insensitive look-up
|
||||
bool found = std::ranges::any_of(AdcEndpointParser::validProtoMarks, [&idx, &proto_mark, this](const auto& el) {
|
||||
bool ok = utils::AdcCharRangeCompare(proto_mark, el, true);
|
||||
|
||||
if (!ok) {
|
||||
++idx;
|
||||
}
|
||||
|
||||
return ok;
|
||||
});
|
||||
|
||||
return found ? idx : -1;
|
||||
}
|
||||
|
||||
enum EndpointPart { PROTO_PART, HOST_PART, PATH_PART };
|
||||
@ -242,9 +294,9 @@ protected:
|
||||
{
|
||||
R res;
|
||||
|
||||
if (!_isValid) {
|
||||
return res;
|
||||
}
|
||||
// if (!_isValid) {
|
||||
// return res;
|
||||
// }
|
||||
|
||||
auto part = _proto;
|
||||
|
||||
|
||||
@ -169,8 +169,8 @@ concept adc_netsession_c =
|
||||
typename SESST::netsession_ctx_t;
|
||||
|
||||
requires std::constructible_from<SESST, const typename SESST::netsession_ident_t,
|
||||
std::shared_ptr<typename SESST::netservice_t>,
|
||||
typename SESST::netsession_ctx_t>;
|
||||
// std::shared_ptr<typename SESST::netservice_t>,
|
||||
typename SESST::netservice_t, typename SESST::netsession_ctx_t>;
|
||||
|
||||
// netsession_ident_t ident() const
|
||||
{ sess_const.ident() } -> std::same_as<typename SESST::netsession_ident_t>;
|
||||
|
||||
@ -230,7 +230,7 @@ public:
|
||||
typedef std::string server_ident_t;
|
||||
|
||||
template <traits::adc_input_char_range R>
|
||||
AdcGenericNetServer(R&& id) : _serverIdent()
|
||||
AdcGenericNetServer(const R& id) : _serverIdent()
|
||||
{
|
||||
if constexpr (std::is_array_v<std::remove_cvref_t<R>>) {
|
||||
_serverIdent = id;
|
||||
|
||||
85
net/asio/adc_device_netserver_asio.h
Normal file
85
net/asio/adc_device_netserver_asio.h
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/ip/udp.hpp>
|
||||
#include <asio/local/seq_packet_protocol.hpp>
|
||||
#include <asio/local/stream_protocol.hpp>
|
||||
|
||||
#include "../adc_device_netserver.h"
|
||||
#include "../adc_endpoint.h"
|
||||
#include "adc_netservice_asio.h"
|
||||
|
||||
namespace adc::impl
|
||||
{
|
||||
|
||||
class AdcDeviceNetServerASIO : public AdcDeviceNetServer
|
||||
{
|
||||
public:
|
||||
template <traits::adc_input_char_range R>
|
||||
AdcDeviceNetServerASIO(const R& id, asio::io_context& io_context) : AdcDeviceNetServer(id), _ioContext(io_context)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template <interfaces::adc_netsession_proto_c SessProtoT, std::derived_from<AdcEndpointParser> EptT>
|
||||
void start(const EptT& endpoint)
|
||||
{
|
||||
if (!endpoint.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// may thow here!
|
||||
#ifdef USE_OPENSSL_WITH_ASIO
|
||||
if (endpoint.isTCP() || endpoint.isTLS()) {
|
||||
asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port());
|
||||
if (endpoint.isTCP()) {
|
||||
using srv_t = AdcNetServiceASIOBase<asio::ip::tcp, SessProtoT>;
|
||||
AdcDeviceNetServer::start<Session<srv_t>>("TCP", this, _ioContext, ept);
|
||||
} else {
|
||||
}
|
||||
#else
|
||||
if (endpoint.isTCP()) {
|
||||
asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port());
|
||||
using srv_t = AdcNetServiceASIOBase<asio::ip::tcp, AdcStopSeqSessionProto<>>;
|
||||
AdcDeviceNetServer::start<Session<srv_t>>("TCP", this, _ioContext, ept);
|
||||
#endif
|
||||
} else if (endpoint.isLocal()) {
|
||||
if (endpoint.isLocalStream()) {
|
||||
asio::local::stream_protocol::endpoint ept(endpoint.template path<std::string>());
|
||||
using srv_t = AdcNetServiceASIOBase<asio::local::stream_protocol, SessProtoT>;
|
||||
AdcDeviceNetServer::start<Session<srv_t>>("LOCAL STREAM", this, _ioContext, ept);
|
||||
} else if (endpoint.isLocalDatagram()) {
|
||||
asio::local::datagram_protocol::endpoint ept(endpoint.template path<std::string>());
|
||||
using srv_t = AdcNetServiceASIOBase<asio::local::datagram_protocol, SessProtoT>;
|
||||
AdcDeviceNetServer::start<Session<srv_t>>("LOCAL DGRAM", this, _ioContext, ept);
|
||||
} else if (endpoint.isLocalSeqpacket()) {
|
||||
asio::local::seq_packet_protocol::endpoint ept(endpoint.template path<std::string>());
|
||||
using srv_t = AdcNetServiceASIOBase<asio::local::seq_packet_protocol, SessProtoT>;
|
||||
AdcDeviceNetServer::start<Session<srv_t>>("LOCAL SEQPACK", this, _ioContext, ept);
|
||||
}
|
||||
} else {
|
||||
throw std::system_error(std::make_error_code(std::errc::protocol_not_supported));
|
||||
}
|
||||
}
|
||||
|
||||
// some default endpoint?!!
|
||||
void start() {}
|
||||
|
||||
protected:
|
||||
asio::io_context& _ioContext;
|
||||
|
||||
// demonizing ASIO-related methods
|
||||
virtual void daemonizePrepare()
|
||||
{
|
||||
_ioContext.notify_fork(asio::execution_context::fork_prepare);
|
||||
}
|
||||
|
||||
virtual void daemonizeFinalize()
|
||||
{
|
||||
_ioContext.notify_fork(asio::io_context::fork_child);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adc::impl
|
||||
@ -161,9 +161,11 @@ public:
|
||||
typedef AdcNetServiceASIOBase netservice_t;
|
||||
typedef std::shared_ptr<netservice_t> sptr_netservice_t;
|
||||
|
||||
typedef std::function<void(std::error_code, sptr_netservice_t)> async_accept_callback_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,
|
||||
// template <asio::completion_token_for<void(std::error_code, sptr_netservice_t)> TokenT,
|
||||
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)
|
||||
{
|
||||
@ -175,7 +177,8 @@ public:
|
||||
_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, sptr_netservice_t)>(
|
||||
return asio::async_compose<TokenT, void(std::error_code, netservice_t)>(
|
||||
[timer = std::move(timer), start = true, this](auto& self, std::error_code ec = {}) mutable {
|
||||
if (!ec) {
|
||||
if (start) {
|
||||
@ -186,7 +189,8 @@ public:
|
||||
}
|
||||
} catch (std::system_error err) {
|
||||
timer->cancel();
|
||||
self.complete(err.code(), std::make_shared<netservice_t>(_ioContext));
|
||||
self.complete(err.code(), netservice_t{_ioContext});
|
||||
// self.complete(err.code(), std::make_shared<netservice_t>(_ioContext));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -200,13 +204,13 @@ public:
|
||||
timer->cancel();
|
||||
}
|
||||
|
||||
// self.complete(ec, AdcNetServiceASIOBase(std::move(_socket)));
|
||||
self.complete(ec, std::make_shared<netservice_t>(std::move(_socket)));
|
||||
self.complete(ec, netservice_t(std::move(_socket)));
|
||||
// self.complete(ec, std::make_shared<netservice_t>(std::move(_socket)));
|
||||
},
|
||||
token, _ioContext);
|
||||
}
|
||||
|
||||
template <asio::completion_token_for<void(std::error_code, AdcNetServiceASIOBase)> TokenT,
|
||||
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,
|
||||
TokenT&& token,
|
||||
|
||||
@ -73,17 +73,21 @@ TEST_CASE("[ADC NET MESSAGE]")
|
||||
|
||||
// std::cout << "\n\n\n";
|
||||
|
||||
AdcEndpoint ept(AdcEndpoint::PROTO_ID_LOCAL, "SOCK");
|
||||
// AdcEndpoint ept(AdcEndpoint::PROTO_ID_LOCAL, "SOCK");
|
||||
|
||||
std::cout << "EPT: [" << ept.endpoint() << "]\n";
|
||||
std::cout << "EPT SZ: " << ept.endpoint().size() << "\n";
|
||||
// std::cout << "EPT: [" << ept.endpoint() << "]\n";
|
||||
// std::cout << "EPT SZ: " << ept.endpoint().size() << "\n";
|
||||
|
||||
char ee[] = "tls://dewlkj.dwed.dwed:8012/dwelk";
|
||||
ept.setEndpoint(ee);
|
||||
// char ee[] = "tLs://dewlkK.dwed.dwed:8012/dwelk";
|
||||
// ept.setEndpoint(ee);
|
||||
|
||||
std::cout << "EPT: [" << ept.endpoint() << "]\n";
|
||||
// std::cout << "EPT: [" << ept.endpoint() << "]\n";
|
||||
|
||||
char ee[] = "tLs://dewlkK.dwed.dwed:8012/dwelk";
|
||||
std::cout << "EPT CHAR RANGE: " << ee << "\n";
|
||||
AdcEndpointParser prs(ee);
|
||||
|
||||
std::cout << std::boolalpha << "IS VALID: " << prs.isValid() << "\n";
|
||||
std::cout << "PROTO: [" << prs.proto() << "]\n";
|
||||
std::cout << "HOST: [" << prs.host() << "]\n";
|
||||
std::cout << "PORT: [" << prs.port() << "]\n";
|
||||
@ -91,9 +95,21 @@ TEST_CASE("[ADC NET MESSAGE]")
|
||||
std::cout << std::boolalpha << "IS TLS: " << prs.isTLS() << "\n";
|
||||
std::cout << std::boolalpha << "IS UDP: " << prs.isUDP() << "\n";
|
||||
|
||||
std::cout << "\n\n";
|
||||
std::string bs;
|
||||
std::cout << "\n";
|
||||
std::string bs = "local://seqpaCKet:dwe/tmp.dev/213";
|
||||
std::cout << "EPT CHAR RANGE: " << bs << "\n";
|
||||
prs = AdcEndpointParser(bs);
|
||||
std::cout << std::boolalpha << "IS VALID: " << prs.isValid() << "\n";
|
||||
std::cout << "PROTO: [" << prs.proto() << "]\n";
|
||||
std::cout << "HOST: [" << prs.host() << "]\n";
|
||||
std::cout << "PORT: [" << prs.port() << "]\n";
|
||||
std::cout << "PATH: [" << prs.path() << "]\n";
|
||||
std::cout << std::boolalpha << "IS LOCAL STREAM: " << prs.isLocalStream() << "\n";
|
||||
std::cout << std::boolalpha << "IS LOCAL SEQPACKET: " << prs.isLocalSeqpacket() << "\n";
|
||||
std::cout << std::boolalpha << "IS UDP: " << prs.isUDP() << "\n";
|
||||
|
||||
std::cout << "\n\n";
|
||||
bs.clear();
|
||||
AdcDeviceProtoMessage dpm(bs);
|
||||
|
||||
std::cout << std::boolalpha << "IS VALID: " << dpm.isValid() << "\n";
|
||||
|
||||
@ -40,7 +40,9 @@ int main()
|
||||
|
||||
acc.asyncAccept([](std::error_code ec, auto srv) {
|
||||
if (!ec) {
|
||||
receive(std::move(srv));
|
||||
auto sptr = std::make_shared<srv_t>(std::move(srv));
|
||||
receive(sptr);
|
||||
// receive(std::move(srv));
|
||||
} else {
|
||||
std::cout << "ACCEPT ERR: " << ec.message() << "\n";
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user