diff --git a/CMakeLists.txt b/CMakeLists.txt index 538e4e4..49c5cb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,7 +155,10 @@ if (BUILD_TESTS) 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) + target_link_libraries(${ASIO_NETSERVER_TEST_APP} PUBLIC Threads::Threads cxxopts::cxxopts) + if (OPENSSL_LIBRARY) + target_link_libraries(${ASIO_NETSERVER_TEST_APP} PUBLIC OpenSSL::SSL OpenSSL::Crypto) + endif() endif() if (NOT doctest_FOUND) diff --git a/common/adc_utils.h b/common/adc_utils.h index 604b643..9dbaed8 100644 --- a/common/adc_utils.h +++ b/common/adc_utils.h @@ -170,14 +170,19 @@ static ValueT AdcFromChars(R&& range) static const std::regex AdcIntegerRegex("^ *[+-]?\\d+\\d* *$", std::regex::ECMAScript); static const std::regex AdcRealRegex("^ *[-+]?\\d+\\d*\\.?\\d*([Ee][-+]?\\d+)? *$", std::regex::ECMAScript); -template +// template +template static SerializedT AdcTrivialSerializer(VT&& value) { using v_t = std::decay_t; if constexpr (std::is_convertible_v) { return static_cast(std::forward(value)); - } else if constexpr (traits::adc_output_char_range) { + } else if constexpr (traits::adc_output_char_range && traits::adc_input_char_range) { + SerializedT s_val; + std::ranges::copy(std::forward(value), std::back_inserter(s_val)); + return s_val; + } else if constexpr (traits::adc_output_char_range && traits::formattable) { SerializedT s_val; std::format_to(std::back_inserter(s_val), "{}", std::forward(value)); return s_val; diff --git a/net/adc_device_netmsg.h b/net/adc_device_netmsg.h index 7f3fddb..4df79db 100644 --- a/net/adc_device_netmsg.h +++ b/net/adc_device_netmsg.h @@ -496,7 +496,7 @@ public: void err(const std::error_code& ec) { - base_t::setKeyValue(ERR_KEY, ec.value(), ec.category(), ec.message()); + base_t::setKeyValue(ERR_KEY, ec.value(), ec.category().name(), ec.message()); keyHash(); } diff --git a/net/adc_device_netserver.h b/net/adc_device_netserver.h index 9a61a93..3ef5347 100644 --- a/net/adc_device_netserver.h +++ b/net/adc_device_netserver.h @@ -158,7 +158,7 @@ protected: if constexpr (std::same_as || std::convertible_to) { return val; } else { - // !!!!!!!! TODO: val_t maust be a char range + // !!!!!!!! TODO: val_t must be a char range return serialized_t{val.begin(), val.end()}; } }; @@ -199,7 +199,7 @@ protected: } }; - static DeviceWrapper nullDevice; + static inline DeviceWrapper nullDevice{}; std::unordered_map _devices; @@ -324,7 +324,7 @@ public: attrs = msg.template attrs(0, 1); if (attrs.size()) { auto val = _bindDevice.getAttr(get_elem(0)); - msg.ack(get_elem(0), {val.begin(), val.end()}); + msg.ack(get_elem(0), serialized_t{val.begin(), val.end()}); } else { // no attr name! msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NO_PROTO_ATTRNAME)); } diff --git a/net/adc_netserver.h b/net/adc_netserver.h index 93092b4..41df2c8 100644 --- a/net/adc_netserver.h +++ b/net/adc_netserver.h @@ -8,10 +8,10 @@ ABSTRACT DEVICE COMPONENTS LIBRARY #include #include +#include #include #include #include -#include #if __has_include() // POSIX #define FORK_EXISTS 1 @@ -139,28 +139,46 @@ protected: // started sessions weak pointers template - static std::unordered_map>> _serverSessions; + // static std::unordered_map>> + // _serverSessions; + static inline std::unordered_map>> _serverSessions{}; std::vector> _stopSessionFunc; std::vector> _moveCtorFunc; template void startSession(std::shared_ptr& sess_ptr) { - auto res = _serverSessions[this].emplace(sess_ptr); - if (res.second) { - sess_ptr->start(); + auto it = _serverSessions[this].end(); + it = _serverSessions[this].emplace(it, sess_ptr); + sess_ptr->start(); - _stopSessionFunc.emplace_back([res, this]() { - if (!res.first->expired()) { // session is still existing - auto sess = res.first->lock(); - sess->stop(); - _serverSessions[this].erase(res.first); - return true; - } else { - return false; - } - }); - } + _stopSessionFunc.emplace_back([it, this]() { + if (!it->expired()) { // session is still existing + auto sess = it->lock(); + sess->stop(); + _serverSessions[this].erase(it); + return true; + } else { + return false; + } + }); + + + // auto res = _serverSessions[this].emplace(sess_ptr); + // if (res.second) { + // sess_ptr->start(); + + // _stopSessionFunc.emplace_back([res, this]() { + // if (!res.first->expired()) { // session is still existing + // auto sess = res.first->lock(); + // sess->stop(); + // _serverSessions[this].erase(res.first); + // return true; + // } else { + // return false; + // } + // }); + // } // define move-function only once per SessionT! if (_serverSessions[this].size() == 1) { diff --git a/net/asio/adc_device_netserver_asio.h b/net/asio/adc_device_netserver_asio.h index 431bd3e..3533ee1 100644 --- a/net/asio/adc_device_netserver_asio.h +++ b/net/asio/adc_device_netserver_asio.h @@ -48,7 +48,8 @@ public: } else { using srv_t = AdcNetServiceASIOTLS; - AdcGenericNetServer::start>("TLS", this, _ioContext, ept, tls_context, tls_verify_mode); + AdcGenericNetServer::start>("TLS", this, _ioContext, ept, std::move(tls_context), + tls_verify_mode); } #else if (endpoint.isTCP()) { diff --git a/net/asio/adc_netservice_asio.h b/net/asio/adc_netservice_asio.h index e081675..b908ac3 100644 --- a/net/asio/adc_netservice_asio.h +++ b/net/asio/adc_netservice_asio.h @@ -168,13 +168,39 @@ public: typedef std::function async_accept_callback_t; - acceptor_t(asio::io_context& io_context) : _ioContext(io_context), _acceptor(io_context) {} + acceptor_t(asio::io_context& io_context) + requires(!netservice_t::isTLS) + : _ioContext(io_context), _acceptor(io_context) + { + } acceptor_t(asio::io_context& io_context, const netservice_t::endpoint_t& endpoint) + requires(!netservice_t::isTLS) : _ioContext(io_context), _acceptor(io_context, endpoint) { } +#ifdef USE_OPENSSL_WITH_ASIO + acceptor_t(asio::io_context& io_context, + asio::ssl::context tls_ctx, + asio::ssl::verify_mode tls_verify_mode = asio::ssl::context_base::verify_peer) + requires netservice_t::isTLS + : _ioContext(io_context), _acceptor(io_context), _tlsCtx(std::move(tls_ctx)), _tlsVerMode(tls_verify_mode) + { + } + + acceptor_t(asio::io_context& io_context, + const netservice_t::endpoint_t& endpoint, + asio::ssl::context tls_ctx, + asio::ssl::verify_mode tls_verify_mode = asio::ssl::context_base::verify_peer) + requires netservice_t::isTLS + : _ioContext(io_context), + _acceptor(io_context, endpoint), + _tlsCtx(std::move(tls_ctx)), + _tlsVerMode(tls_verify_mode) + { + } +#endif template TokenT, traits::adc_time_duration_c DT = decltype(DEFAULT_ACCEPT_TIMEOUT)> auto asyncAccept(TokenT&& token, const DT& timeout = DEFAULT_ACCEPT_TIMEOUT) @@ -183,10 +209,17 @@ public: auto timer = netservice_t::getDeadlineTimer(_acceptor, timeout); - // auto srv = std::make_unique(_ioContext); - auto srv = netservice_t::isTLS ? std::make_unique(_ioContext, srv->_tlsContext) - : std::make_unique(_ioContext); - +#ifdef USE_OPENSSL_WITH_ASIO + auto srv = [&, this]() { + if constexpr (netservice_t::isTLS) { + return std::make_unique(_ioContext, std::move(_tlsCtx), _tlsVerMode); + } else { + return std::make_unique(_ioContext); + } + }(); +#else + auto srv = std::make_unique(_ioContext); +#endif return asio::async_compose( [timer = std::move(timer), srv = std::move(srv), state = sock_accept, this]( auto& self, std::error_code ec = {}) mutable { @@ -205,7 +238,7 @@ public: #ifdef USE_OPENSSL_WITH_ASIO if constexpr (netservice_t::isTLS) { srv->_sessSocket = - netservice_t::session_level_socket_t(srv->_socket, srv->_tlsContext); + netservice_t::session_level_socket_t(std::move(srv->_socket), srv->_tlsContext); return srv->_sessSocket.async_handshake(asio::ssl::stream_base::server, std::move(self)); } @@ -264,6 +297,11 @@ public: private: asio::io_context& _ioContext; srv_acceptor_t _acceptor; + +#ifdef USE_OPENSSL_WITH_ASIO + asio::ssl::context _tlsCtx{asio::ssl::context_base::tlsv13}; + asio::ssl::verify_mode _tlsVerMode; +#endif }; @@ -291,7 +329,7 @@ public: #ifdef USE_OPENSSL_WITH_ASIO AdcBaseNetServiceASIO(asio::io_context& ctx, - const asio::ssl::context& tls_context, + asio::ssl::context tls_context, const asio::ssl::verify_mode& tls_peer_verify_mode = asio::ssl::verify_peer) requires isTLS : SESSION_PROTOT(), @@ -299,8 +337,9 @@ public: _receiveStrand(_ioContext), _socket(_ioContext), _receiveQueue(), - _tlsContext(tls_context), - _tlsPeerVerifyMode(tls_peer_verify_mode) + _tlsContext(std::move(tls_context)), + _tlsPeerVerifyMode(tls_peer_verify_mode), + _sessSocket(_ioContext, _tlsContext) { } #endif @@ -418,7 +457,7 @@ public: state = done; #ifdef USE_OPENSSL_WITH_ASIO if constexpr (isTLS) { - _sessSocket = session_level_socket_t(_socket, _tlsContext); + _sessSocket = session_level_socket_t(std::move(_socket), _tlsContext); return _sessSocket.async_handshake(session_level_socket_t::client, std::move(self)); } #endif @@ -666,7 +705,7 @@ public: #ifdef USE_OPENSSL_WITH_ASIO if constexpr (isTLS) { - _sessSocket.shutdown(_shutdownType, ec); + _sessSocket.shutdown(ec); } #endif