...
This commit is contained in:
parent
7685f4c014
commit
1047b57013
@ -151,6 +151,13 @@ if (BUILD_TESTS)
|
|||||||
add_executable(${NETSERVICE_TEST_APP} tests/adc_netservice_test.cpp)
|
add_executable(${NETSERVICE_TEST_APP} tests/adc_netservice_test.cpp)
|
||||||
target_link_libraries(${NETSERVICE_TEST_APP} OpenSSL::SSL OpenSSL::Crypto)
|
target_link_libraries(${NETSERVICE_TEST_APP} OpenSSL::SSL OpenSSL::Crypto)
|
||||||
|
|
||||||
|
if (ASIO_LIBRARY)
|
||||||
|
find_package(cxxopts CONFIG)
|
||||||
|
set(ASIO_NETSERVER_TEST_APP adc_asio_netserver_test)
|
||||||
|
add_executable(${ASIO_NETSERVER_TEST_APP} tests/adc_asio_netserver_test.cpp)
|
||||||
|
target_link_libraries(${ASIO_NETSERVER_TEST_APP} PUBLIC cxxopts::cxxopts)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT doctest_FOUND)
|
if (NOT doctest_FOUND)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
@ -167,6 +174,7 @@ if (BUILD_TESTS)
|
|||||||
# add_test(VALUE_HOLDER ${VALUEHOLDER_TEST_APP})
|
# add_test(VALUE_HOLDER ${VALUEHOLDER_TEST_APP})
|
||||||
add_test(VALUE_HOLDER ${DEVATTR_TEST_APP})
|
add_test(VALUE_HOLDER ${DEVATTR_TEST_APP})
|
||||||
add_test(NETMSG_TEST ${NETMSG_TEST_APP})
|
add_test(NETMSG_TEST ${NETMSG_TEST_APP})
|
||||||
|
add_test(ASIO_NETSRV_TEST ${ASIO_NETSERVER_TEST_APP})
|
||||||
enable_testing()
|
enable_testing()
|
||||||
endif(BUILD_TESTS)
|
endif(BUILD_TESTS)
|
||||||
|
|
||||||
|
|||||||
@ -377,12 +377,16 @@ public:
|
|||||||
// _devices.try_emplace(dev_ptr, dev_ptr, std::forward<IdSerialT>(id_ser_func),
|
// _devices.try_emplace(dev_ptr, dev_ptr, std::forward<IdSerialT>(id_ser_func),
|
||||||
// std::forward<AttrIdDeserialT>(attr_id_deser_func),
|
// std::forward<AttrIdDeserialT>(attr_id_deser_func),
|
||||||
// std::forward<CmdIdDeserialT>(cmd_id_deser_func));
|
// std::forward<CmdIdDeserialT>(cmd_id_deser_func));
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <interfaces::adc_device_c DeviceT>
|
template <interfaces::adc_device_c DeviceT>
|
||||||
AdcDeviceNetServer& delDevice(DeviceT* dev_ptr)
|
AdcDeviceNetServer& delDevice(DeviceT* dev_ptr)
|
||||||
{
|
{
|
||||||
_devices.erase(dev_ptr);
|
_devices.erase(dev_ptr);
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,8 @@ namespace adc
|
|||||||
|
|
||||||
class AdcEndpointParser
|
class AdcEndpointParser
|
||||||
{
|
{
|
||||||
|
typedef std::span<char> host_part_t;
|
||||||
|
|
||||||
public:
|
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 = ":";
|
||||||
@ -115,16 +117,19 @@ public:
|
|||||||
|
|
||||||
_proto = validProtoMarks[idx];
|
_proto = validProtoMarks[idx];
|
||||||
|
|
||||||
_host = std::string_view{found.end(), _endpoint.end()};
|
// _host = std::string_view{found.end(), _endpoint.end()};
|
||||||
|
_host = host_part_t{found.end(), _endpoint.end()};
|
||||||
|
|
||||||
auto f1 = std::ranges::search(_host, portPathDelim);
|
auto f1 = std::ranges::search(_host, portPathDelim);
|
||||||
std::string_view port_sv;
|
std::string_view port_sv;
|
||||||
if (f1.empty() && isLocal()) { // no path, but it is mandatory for 'local'!
|
if (f1.empty() && isLocal()) { // no path, but it is mandatory for 'local'!
|
||||||
return _isValid;
|
return _isValid;
|
||||||
} else {
|
} else {
|
||||||
_host = std::string_view(_host.begin(), f1.begin());
|
// _host = std::string_view(_host.begin(), f1.begin());
|
||||||
|
_host = host_part_t{found.end(), _endpoint.end()};
|
||||||
|
|
||||||
_path = std::string_view(f1.end(), &*_endpoint.end());
|
// _path = std::string_view(f1.end(), &*_endpoint.end());
|
||||||
|
_path = std::string_view(&*f1.end(), &*_endpoint.end());
|
||||||
|
|
||||||
f1 = std::ranges::search(_host, hostPortDelim);
|
f1 = std::ranges::search(_host, hostPortDelim);
|
||||||
if (f1.empty() && !isLocal()) { // no port, but it is mandatory for non-local!
|
if (f1.empty() && !isLocal()) { // no port, but it is mandatory for non-local!
|
||||||
@ -133,7 +138,8 @@ public:
|
|||||||
|
|
||||||
port_sv = std::string_view(f1.end(), _host.end());
|
port_sv = std::string_view(f1.end(), _host.end());
|
||||||
if (port_sv.size()) {
|
if (port_sv.size()) {
|
||||||
_host = std::string_view(_host.begin(), f1.begin());
|
// _host = std::string_view(_host.begin(), f1.begin());
|
||||||
|
_host = host_part_t{found.end(), _endpoint.end()};
|
||||||
|
|
||||||
if (!isLocal()) {
|
if (!isLocal()) {
|
||||||
// convert port string to int
|
// convert port string to int
|
||||||
@ -159,7 +165,7 @@ public:
|
|||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
})) {
|
})) {
|
||||||
_host = validLocalProtoTypes[idx];
|
// _host = validLocalProtoTypes[idx];
|
||||||
} else {
|
} else {
|
||||||
return _isValid;
|
return _isValid;
|
||||||
}
|
}
|
||||||
@ -223,17 +229,20 @@ public:
|
|||||||
|
|
||||||
bool isLocalStream() const
|
bool isLocalStream() const
|
||||||
{
|
{
|
||||||
return host() == localProtoTypeStream;
|
// return host() == localProtoTypeStream;
|
||||||
|
return utils::AdcCharRangeCompare(host(), localProtoTypeStream, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLocalDatagram() const
|
bool isLocalDatagram() const
|
||||||
{
|
{
|
||||||
return host() == localProtoTypeDatagram;
|
// return host() == localProtoTypeDatagram;
|
||||||
|
return utils::AdcCharRangeCompare(host(), localProtoTypeDatagram, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLocalSeqpacket() const
|
bool isLocalSeqpacket() const
|
||||||
{
|
{
|
||||||
return host() == localProtoTypeSeqpacket;
|
// return host() == localProtoTypeSeqpacket;
|
||||||
|
return utils::AdcCharRangeCompare(host(), localProtoTypeSeqpacket, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -264,7 +273,9 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _endpoint;
|
std::string _endpoint;
|
||||||
std::string_view _proto, _host, _path;
|
// std::string_view _proto, _host, _path;
|
||||||
|
std::string_view _proto, _path;
|
||||||
|
host_part_t _host;
|
||||||
int _port;
|
int _port;
|
||||||
bool _isValid;
|
bool _isValid;
|
||||||
|
|
||||||
@ -298,28 +309,54 @@ protected:
|
|||||||
// return res;
|
// return res;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto part = _proto;
|
// auto part = _proto;
|
||||||
|
|
||||||
|
// switch (what) {
|
||||||
|
// case PROTO_PART:
|
||||||
|
// part = _proto;
|
||||||
|
// break;
|
||||||
|
// case HOST_PART:
|
||||||
|
// part = _host;
|
||||||
|
// break;
|
||||||
|
// case PATH_PART:
|
||||||
|
// part = _path;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if constexpr (std::ranges::view<R>) {
|
||||||
|
// return R(part.begin(), part.end());
|
||||||
|
// } else {
|
||||||
|
// std::ranges::copy(part, std::back_inserter(res));
|
||||||
|
// }
|
||||||
|
|
||||||
switch (what) {
|
switch (what) {
|
||||||
case PROTO_PART:
|
case PROTO_PART:
|
||||||
part = _proto;
|
if constexpr (std::ranges::view<R>) {
|
||||||
|
res = R(_proto.begin(), _proto.size());
|
||||||
|
} else {
|
||||||
|
std::ranges::copy(_proto, std::back_inserter(res));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case HOST_PART:
|
case HOST_PART:
|
||||||
part = _host;
|
if constexpr (std::ranges::view<R>) {
|
||||||
|
res = R(_host.begin(), _host.end());
|
||||||
|
} else {
|
||||||
|
std::ranges::copy(_host, std::back_inserter(res));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PATH_PART:
|
case PATH_PART:
|
||||||
part = _path;
|
if constexpr (std::ranges::view<R>) {
|
||||||
|
res = R(_path.begin(), _path.end());
|
||||||
|
} else {
|
||||||
|
std::ranges::copy(_path, std::back_inserter(res));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (std::ranges::view<R>) {
|
|
||||||
return {part.begin(), part.end()};
|
|
||||||
} else {
|
|
||||||
std::ranges::copy(part, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,7 +18,8 @@ class AdcDeviceNetServerASIO : public AdcDeviceNetServer
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <traits::adc_input_char_range R>
|
template <traits::adc_input_char_range R>
|
||||||
AdcDeviceNetServerASIO(const R& id, asio::io_context& io_context) : AdcDeviceNetServer(id), _ioContext(io_context)
|
AdcDeviceNetServerASIO(const R& id, asio::io_context& io_context)
|
||||||
|
: AdcDeviceNetServer(id), _ioContext(io_context), _stopSignal(io_context), _restartSignal(io_context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +54,10 @@ public:
|
|||||||
asio::local::stream_protocol::endpoint ept(endpoint.template path<std::string>());
|
asio::local::stream_protocol::endpoint ept(endpoint.template path<std::string>());
|
||||||
using srv_t = AdcNetServiceASIO<asio::local::stream_protocol, SessProtoT>;
|
using srv_t = AdcNetServiceASIO<asio::local::stream_protocol, SessProtoT>;
|
||||||
AdcDeviceNetServer::start<Session<srv_t>>("LOCAL STREAM", this, _ioContext, ept);
|
AdcDeviceNetServer::start<Session<srv_t>>("LOCAL STREAM", this, _ioContext, ept);
|
||||||
} else if (endpoint.isLocalDatagram()) {
|
// } else if (endpoint.isLocalDatagram()) {
|
||||||
asio::local::datagram_protocol::endpoint ept(endpoint.template path<std::string>());
|
// asio::local::datagram_protocol::endpoint ept(endpoint.template path<std::string>());
|
||||||
using srv_t = AdcNetServiceASIO<asio::local::datagram_protocol, SessProtoT>;
|
// using srv_t = AdcNetServiceASIO<asio::local::datagram_protocol, SessProtoT>;
|
||||||
AdcDeviceNetServer::start<Session<srv_t>>("LOCAL DGRAM", this, _ioContext, ept);
|
// AdcDeviceNetServer::start<Session<srv_t>>("LOCAL DGRAM", this, _ioContext, ept);
|
||||||
} else if (endpoint.isLocalSeqpacket()) {
|
} else if (endpoint.isLocalSeqpacket()) {
|
||||||
asio::local::seq_packet_protocol::endpoint ept(endpoint.template path<std::string>());
|
asio::local::seq_packet_protocol::endpoint ept(endpoint.template path<std::string>());
|
||||||
using srv_t = AdcNetServiceASIO<asio::local::seq_packet_protocol, SessProtoT>;
|
using srv_t = AdcNetServiceASIO<asio::local::seq_packet_protocol, SessProtoT>;
|
||||||
@ -70,7 +71,7 @@ public:
|
|||||||
// some default endpoint?!!
|
// some default endpoint?!!
|
||||||
void start() {}
|
void start() {}
|
||||||
|
|
||||||
template <std::ranges::range RST, std::ranges::range RRT>
|
template <std::ranges::range RST = std::vector<int>, std::ranges::range RRT = std::vector<int>>
|
||||||
void setupSignals(const RST& stop_sig_num = std::vector<int>{SIGINT, SIGTERM},
|
void setupSignals(const RST& stop_sig_num = std::vector<int>{SIGINT, SIGTERM},
|
||||||
const RRT& restart_sig_num = std::vector<int>{SIGUSR1})
|
const RRT& restart_sig_num = std::vector<int>{SIGUSR1})
|
||||||
requires(std::convertible_to<std::ranges::range_value_t<RST>, int> &&
|
requires(std::convertible_to<std::ranges::range_value_t<RST>, int> &&
|
||||||
|
|||||||
@ -116,8 +116,8 @@ class AdcBaseNetServiceASIO : public SESSION_PROTOT
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#ifdef USE_OPENSSL_WITH_ASIO
|
#ifdef USE_OPENSSL_WITH_ASIO
|
||||||
static_assert(!(USE_TLS && adc_asio_tls_transport_proto_c<TRANSPORT_PROTOT>),
|
// static_assert(!(USE_TLS && adc_asio_tls_transport_proto_c<TRANSPORT_PROTOT>),
|
||||||
"INVALID 'TRANSPORT_PROTOT' TEMPLATE ARGUMENT!");
|
// "INVALID 'TRANSPORT_PROTOT' TEMPLATE ARGUMENT!");
|
||||||
|
|
||||||
static constexpr bool isTLS = USE_TLS;
|
static constexpr bool isTLS = USE_TLS;
|
||||||
#else // ignore USE_TLS
|
#else // ignore USE_TLS
|
||||||
@ -250,7 +250,8 @@ public:
|
|||||||
template <traits::adc_time_duration_c DT = decltype(DEFAULT_ACCEPT_TIMEOUT)>
|
template <traits::adc_time_duration_c DT = decltype(DEFAULT_ACCEPT_TIMEOUT)>
|
||||||
auto accept(const endpoint_t& endpoint, const DT& timeout = DEFAULT_ACCEPT_TIMEOUT)
|
auto accept(const endpoint_t& endpoint, const DT& timeout = DEFAULT_ACCEPT_TIMEOUT)
|
||||||
{
|
{
|
||||||
return accept(endpoint, timeout);
|
_acceptor = srv_acceptor_t(_ioContext, endpoint);
|
||||||
|
return accept(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
68
tests/adc_asio_netserver_test.cpp
Normal file
68
tests/adc_asio_netserver_test.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include <cxxopts.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "../net/adc_endpoint.h"
|
||||||
|
#include "../net/adc_netproto.h"
|
||||||
|
#include "../net/asio/adc_device_netserver_asio.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
/* COMMANDLINE OPTS */
|
||||||
|
cxxopts::Options options(argv[0], "ADC-library test device network server (ASIO implementation)\n");
|
||||||
|
|
||||||
|
options.allow_unrecognised_options();
|
||||||
|
|
||||||
|
options.add_options()("h,help", "Print usage");
|
||||||
|
options.add_options()(
|
||||||
|
"endpoints", "endpoints server will be listening for",
|
||||||
|
cxxopts::value<std::vector<std::string>>()->default_value("local://stream/tmp/ADC_ASIO_TEST_SERVER"));
|
||||||
|
|
||||||
|
options.parse_positional({"endpoints"});
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto opt_result = options.parse(argc, argv);
|
||||||
|
|
||||||
|
if (opt_result["help"].count()) {
|
||||||
|
std::cout << options.help();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
asio::io_context io_ctx;
|
||||||
|
adc::impl::AdcDeviceNetServerASIO server("TEST SRV", io_ctx);
|
||||||
|
server.setupSignals();
|
||||||
|
|
||||||
|
auto epnt = opt_result["endpoints"].as<std::vector<std::string>>();
|
||||||
|
|
||||||
|
for (auto& ep : epnt) {
|
||||||
|
adc::AdcEndpointParser epn(ep);
|
||||||
|
if (epn.isValid()) {
|
||||||
|
if (epn.isLocalSeqpacket() || epn.isLocalStream()) {
|
||||||
|
if (opt_result["abstract"].as<bool>()) {
|
||||||
|
auto s = epn.path<std::span<char>>();
|
||||||
|
if (s[0] == '@') { // replace '@' to '\0' (use of UNIX abstract namespace)
|
||||||
|
s[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "try to start listenning at '" << ep << "' ...";
|
||||||
|
server.start<adc::AdcStopSeqSessionProto<>>(epn);
|
||||||
|
std::cout << "\tOK\n";
|
||||||
|
} else {
|
||||||
|
std::cerr << "Unrecognized endpoint: '" << ep << "'! Ignore!\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
io_ctx.run();
|
||||||
|
|
||||||
|
} catch (const cxxopts::exceptions::exception& ex) {
|
||||||
|
std::cerr << "\nAn error occured while parsing input options: " << ex.what() << "\n";
|
||||||
|
return 127;
|
||||||
|
} catch (const std::system_error& ex) {
|
||||||
|
std::cerr << "\nAn error ocured: " << ex.what() << "\n";
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user