diff --git a/net/adc_endpoint.h b/net/adc_endpoint.h index 905ebfd..4f79844 100644 --- a/net/adc_endpoint.h +++ b/net/adc_endpoint.h @@ -143,7 +143,7 @@ public: _host = std::string_view{found.end(), _endpoint.end()}; 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'! return _isValid; } else { @@ -156,15 +156,15 @@ public: return _isValid; } - port_sv = std::string_view(f1.end(), _host.end()); - if (port_sv.size()) { + _portView = std::string_view(f1.end(), _host.end()); + if (_portView.size()) { _host = std::string_view(_host.begin(), f1.begin()); if (!isLocal()) { // convert port string to int - auto end_ptr = port_sv.data() + port_sv.size(); + auto end_ptr = _portView.data() + _portView.size(); - auto [ptr, ec] = std::from_chars(port_sv.data(), end_ptr, _port); + auto [ptr, ec] = std::from_chars(_portView.data(), end_ptr, _port); if (ec != std::errc() || ptr != end_ptr) { return _isValid; } @@ -235,6 +235,17 @@ public: return _port; } + template + R portView() const + { + return part(PORT_PART); + } + + std::string_view portView() const + { + return portView(); + } + template R path() const { @@ -295,7 +306,7 @@ public: protected: std::string _endpoint; - std::string_view _proto, _host, _path; + std::string_view _proto, _host, _path, _portView; int _port; bool _isValid; @@ -318,7 +329,7 @@ protected: return found ? idx : -1; } - enum EndpointPart { PROTO_PART, HOST_PART, PATH_PART }; + enum EndpointPart { PROTO_PART, HOST_PART, PATH_PART, PORT_PART }; template R part(EndpointPart what) const @@ -341,6 +352,9 @@ protected: case PATH_PART: part = _path; break; + case PORT_PART: + part = _portView; + break; default: break; } diff --git a/net/adc_netclient.h b/net/adc_netclient.h index 12241a2..ad6c1c0 100644 --- a/net/adc_netclient.h +++ b/net/adc_netclient.h @@ -8,7 +8,7 @@ namespace adc { -/* */ +/* A VERY GENERIC NETWORK CLIENT */ template > @@ -30,11 +30,13 @@ public: stopAllSessions(); } + + // start the client: connect to server and start session template - void asyncConnect(const SessionT::netservice_t::endpoint_t& endpoint, - SessionT::netsession_ident_t id, - SessionT::netsession_ctx_t sess_ctx, - NetServiceCtorArgTs&&... ctor_args) + void start(const SessionT::netservice_t::endpoint_t& endpoint, + SessionT::netsession_ident_t id, + SessionT::netsession_ctx_t sess_ctx, + NetServiceCtorArgTs&&... ctor_args) { auto srv_sptr = std::make_shared(std::forward(ctor_args)...); @@ -53,20 +55,6 @@ public: } - template - void connect(const SessionT::netservice_t::endpoint_t& endpoint, - SessionT::netsession_ident_t id, - SessionT::netsession_ctx_t sess_ctx, - NetServiceCtorArgTs&&... ctor_args) - { - typename SessionT::netservice_t srv(std::forward(ctor_args)...); - srv.connect(endpoint, _connectTimeout); - - auto sess = std::make_shared(std::move(id), std::move(srv), std::move(sess_ctx)); - startSession(sess); - } - - template void setConnectTimeout(const DT& timeout) { @@ -82,6 +70,29 @@ protected: client_ident_t _clientIdent; std::chrono::milliseconds _connectTimeout = std::chrono::milliseconds(5000); + + template + auto asyncSendRecv(ServiceT& netservice, + const SendMsgT& send_msg, + TokenT&& token, + const SendTimeoutT& send_timeout = std::chrono::milliseconds(5000), + const RecvTimeoutT& recv_timeout = std::chrono::milliseconds(5000)) + { + return netservice.asyncSend( + send_msg, + [&netservice, recv_timeout, wrapper = traits::adc_pf_wrapper(std::forward(token)), this](auto err) { + if (err) { + this->logError("An error occured while sending the message: {}", ServiceT::formattableError(err)); + } else { + netservice.asyncReceive(std::get<0>(wrapper), recv_timeout); + } + }, + send_timeout); + } }; } // namespace adc diff --git a/net/asio/adc_device_netserver_asio.h b/net/asio/adc_device_netserver_asio.h index 40c2660..5932abf 100644 --- a/net/asio/adc_device_netserver_asio.h +++ b/net/asio/adc_device_netserver_asio.h @@ -53,21 +53,66 @@ public: } + // may throw here! if (endpoint.isTCP()) { - asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port()); + // asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port()); using srv_t = AdcNetServiceASIO; - // base_t::template start>("TCP", this, _ioContext, ept); - base_t::template start>("TCP", {this, _sessionRecvTimeout, _sessionSendTimeout}, _ioContext, - ept); + + // base_t::template start>("TCP", {this, _sessionRecvTimeout, _sessionSendTimeout}, + // _ioContext, + // ept); + auto res = std::make_shared(_ioContext); + res->async_resolve( + endpoint.host(), endpoint.portView(), [endpoint, res, this](std::error_code ec, auto results) { + if (ec) { + this->logError( + "An error occured while resolve hostname ('{}') of the given endpoint! (ec = {})", + endpoint.host(), ec.message()); + this->logError("Cannot start listening at endpoint '{}'!", endpoint.endpoint()); + } else { + if (results.size() == 1) { + this->logDebug("Resolved the single IP-address for the hostname '{}'", endpoint.host()); + } else { + this->logDebug("Resolved {} IP-addresses for the hostname '{}'! Use of the first one!", + results.size(), endpoint.host()); + } + base_t::template start>("TCP", {this, _sessionRecvTimeout, _sessionSendTimeout}, + _ioContext, *results.begin()); + } + }); + #ifdef USE_OPENSSL_WITH_ASIO } else if (endpoint.isTLS()) { - asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port()); + // asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port()); using srv_t = AdcNetServiceASIOTLS; - // base_t::template start>("TLS", this, _ioContext, ept, std::move(tls_context), - // tls_verify_mode); - base_t::template start>("TLS", {this, _sessionRecvTimeout, _sessionSendTimeout}, _ioContext, - ept, std::move(tls_context), tls_verify_mode); + // base_t::template start>("TLS", {this, _sessionRecvTimeout, _sessionSendTimeout}, + // _ioContext, + // ept, std::move(tls_context), tls_verify_mode); + + auto res = std::make_shared(_ioContext); + res->async_resolve( + endpoint.host(), endpoint.portView(), + [endpoint, res, tls_context = std::move(tls_context), tls_verify_mode, this](std::error_code ec, + auto results) mutable { + if (ec) { + this->logError( + "An error occured while resolve hostname ('{}') of the given endpoint! (ec = {})", + endpoint.host(), ec.message()); + this->logError("Cannot start listening at endpoint '{}'!", endpoint.endpoint()); + } else { + if (results.size() == 1) { + this->logDebug("Resolved the single IP-address for the hostname '{}'", endpoint.host()); + } else { + this->logDebug("Resolved {} IP-addresses for the hostname '{}'! Use of the first one!", + results.size(), endpoint.host()); + } + base_t::template start>("TLS", {this, _sessionRecvTimeout, _sessionSendTimeout}, + _ioContext, *results.begin(), std::move(tls_context), + tls_verify_mode); + } + }); + #endif } else if (endpoint.isLocal()) { if (endpoint.isLocalStream()) { diff --git a/net/asio/adc_netservice_asio.h b/net/asio/adc_netservice_asio.h index ac3e9f0..388cd51 100644 --- a/net/asio/adc_netservice_asio.h +++ b/net/asio/adc_netservice_asio.h @@ -590,9 +590,9 @@ public: } auto n_avail = _socket.available(); - if (!n_avail) { - return _socket.async_wait(asio::ip::tcp::socket::wait_read, std::move(self)); - } + // 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); do_read = false;