diff --git a/CMakeLists.txt b/CMakeLists.txt index fd8005f..538e4e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,6 +151,13 @@ if (BUILD_TESTS) add_executable(${NETSERVICE_TEST_APP} tests/adc_netservice_test.cpp) 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) include(FetchContent) FetchContent_Declare( @@ -167,6 +174,7 @@ if (BUILD_TESTS) # add_test(VALUE_HOLDER ${VALUEHOLDER_TEST_APP}) add_test(VALUE_HOLDER ${DEVATTR_TEST_APP}) add_test(NETMSG_TEST ${NETMSG_TEST_APP}) + add_test(ASIO_NETSRV_TEST ${ASIO_NETSERVER_TEST_APP}) enable_testing() endif(BUILD_TESTS) diff --git a/net/adc_device_netserver.h b/net/adc_device_netserver.h index b7316c2..a49715c 100644 --- a/net/adc_device_netserver.h +++ b/net/adc_device_netserver.h @@ -377,12 +377,16 @@ public: // _devices.try_emplace(dev_ptr, dev_ptr, std::forward(id_ser_func), // std::forward(attr_id_deser_func), // std::forward(cmd_id_deser_func)); + + return *this; } template AdcDeviceNetServer& delDevice(DeviceT* dev_ptr) { _devices.erase(dev_ptr); + + return *this; } }; diff --git a/net/adc_endpoint.h b/net/adc_endpoint.h index b863406..e1f96c8 100644 --- a/net/adc_endpoint.h +++ b/net/adc_endpoint.h @@ -40,6 +40,8 @@ namespace adc class AdcEndpointParser { + typedef std::span host_part_t; + public: static constexpr std::string_view protoHostDelim = "://"; static constexpr std::string_view hostPortDelim = ":"; @@ -115,16 +117,19 @@ public: _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); std::string_view port_sv; if (f1.empty() && isLocal()) { // no path, but it is mandatory for 'local'! return _isValid; } 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); 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()); 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()) { // convert port string to int @@ -159,7 +165,7 @@ public: } return ok; })) { - _host = validLocalProtoTypes[idx]; + // _host = validLocalProtoTypes[idx]; } else { return _isValid; } @@ -223,17 +229,20 @@ public: bool isLocalStream() const { - return host() == localProtoTypeStream; + // return host() == localProtoTypeStream; + return utils::AdcCharRangeCompare(host(), localProtoTypeStream, true); } bool isLocalDatagram() const { - return host() == localProtoTypeDatagram; + // return host() == localProtoTypeDatagram; + return utils::AdcCharRangeCompare(host(), localProtoTypeDatagram, true); } bool isLocalSeqpacket() const { - return host() == localProtoTypeSeqpacket; + // return host() == localProtoTypeSeqpacket; + return utils::AdcCharRangeCompare(host(), localProtoTypeSeqpacket, true); } @@ -264,7 +273,9 @@ public: protected: 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; bool _isValid; @@ -298,28 +309,54 @@ protected: // 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) { + // return R(part.begin(), part.end()); + // } else { + // std::ranges::copy(part, std::back_inserter(res)); + // } switch (what) { case PROTO_PART: - part = _proto; + if constexpr (std::ranges::view) { + res = R(_proto.begin(), _proto.size()); + } else { + std::ranges::copy(_proto, std::back_inserter(res)); + } break; case HOST_PART: - part = _host; + if constexpr (std::ranges::view) { + res = R(_host.begin(), _host.end()); + } else { + std::ranges::copy(_host, std::back_inserter(res)); + } break; case PATH_PART: - part = _path; + if constexpr (std::ranges::view) { + res = R(_path.begin(), _path.end()); + } else { + std::ranges::copy(_path, std::back_inserter(res)); + } break; default: break; } - if constexpr (std::ranges::view) { - return {part.begin(), part.end()}; - } else { - std::ranges::copy(part, res); - } - return res; } }; diff --git a/net/asio/adc_device_netserver_asio.h b/net/asio/adc_device_netserver_asio.h index 1d2abb8..ed7f980 100644 --- a/net/asio/adc_device_netserver_asio.h +++ b/net/asio/adc_device_netserver_asio.h @@ -18,7 +18,8 @@ class AdcDeviceNetServerASIO : public AdcDeviceNetServer { public: template - 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()); using srv_t = AdcNetServiceASIO; AdcDeviceNetServer::start>("LOCAL STREAM", this, _ioContext, ept); - } else if (endpoint.isLocalDatagram()) { - asio::local::datagram_protocol::endpoint ept(endpoint.template path()); - using srv_t = AdcNetServiceASIO; - AdcDeviceNetServer::start>("LOCAL DGRAM", this, _ioContext, ept); + // } else if (endpoint.isLocalDatagram()) { + // asio::local::datagram_protocol::endpoint ept(endpoint.template path()); + // using srv_t = AdcNetServiceASIO; + // AdcDeviceNetServer::start>("LOCAL DGRAM", this, _ioContext, ept); } else if (endpoint.isLocalSeqpacket()) { asio::local::seq_packet_protocol::endpoint ept(endpoint.template path()); using srv_t = AdcNetServiceASIO; @@ -70,7 +71,7 @@ public: // some default endpoint?!! void start() {} - template + template , std::ranges::range RRT = std::vector> void setupSignals(const RST& stop_sig_num = std::vector{SIGINT, SIGTERM}, const RRT& restart_sig_num = std::vector{SIGUSR1}) requires(std::convertible_to, int> && diff --git a/net/asio/adc_netservice_asio.h b/net/asio/adc_netservice_asio.h index 8bc4941..a5c2cb0 100644 --- a/net/asio/adc_netservice_asio.h +++ b/net/asio/adc_netservice_asio.h @@ -116,8 +116,8 @@ class AdcBaseNetServiceASIO : public SESSION_PROTOT { public: #ifdef USE_OPENSSL_WITH_ASIO - static_assert(!(USE_TLS && adc_asio_tls_transport_proto_c), - "INVALID 'TRANSPORT_PROTOT' TEMPLATE ARGUMENT!"); + // static_assert(!(USE_TLS && adc_asio_tls_transport_proto_c), + // "INVALID 'TRANSPORT_PROTOT' TEMPLATE ARGUMENT!"); static constexpr bool isTLS = USE_TLS; #else // ignore USE_TLS @@ -250,7 +250,8 @@ public: template 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: diff --git a/tests/adc_asio_netserver_test.cpp b/tests/adc_asio_netserver_test.cpp new file mode 100644 index 0000000..c0b65dd --- /dev/null +++ b/tests/adc_asio_netserver_test.cpp @@ -0,0 +1,68 @@ +#include +#include + +#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>()->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>(); + + for (auto& ep : epnt) { + adc::AdcEndpointParser epn(ep); + if (epn.isValid()) { + if (epn.isLocalSeqpacket() || epn.isLocalStream()) { + if (opt_result["abstract"].as()) { + auto s = epn.path>(); + if (s[0] == '@') { // replace '@' to '\0' (use of UNIX abstract namespace) + s[0] = '\0'; + } + } + } + + std::cout << "try to start listenning at '" << ep << "' ..."; + server.start>(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; +}