diff --git a/CMakeLists.txt b/CMakeLists.txt index 45a805d..9f39c2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.14) project(ADC LANGUAGES CXX) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}") + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) # set(CMAKE_BUILD_TYPE Release) @@ -32,7 +34,22 @@ set(ADC_NETWORK_HEADERS ) -option(SPDLOG_LIBRARY "Use SPDLOG library for logging" ON) +option(ASIO_LIBRARY "Use of ASIO library for networking implementation" ON) + +if (ASIO_LIBRARY) + find_package(ASIO REQUIRED) + + set(ADC_NETWORK_HEADERS ${ADC_NETWORK_HEADERS} + net/adc_netservice_asio.h + ) + + add_compile_options(ASIO::ASIO) + add_compile_definitions(PUBLIC USE_ASIO_LIBRARY) +endif() + + + +option(SPDLOG_LIBRARY "Use of SPDLOG library for logging" ON) if (SPDLOG_LIBRARY) find_package(spdlog REQUIRED) diff --git a/FindASIO.cmake b/FindASIO.cmake new file mode 100644 index 0000000..051185b --- /dev/null +++ b/FindASIO.cmake @@ -0,0 +1,24 @@ +# +# ASIO +# + +set(ASIO_FOUND FALSE) + +find_package(Threads REQUIRED) + +find_path(ASIO_DIR asio.hpp HINTS ${ASIO_INSTALL_DIR} PATH_SUFFIXES include) + +if (NOT ASIO_DIR) + message(FATAL_ERROR "Cannot find ASIO library headers!") +endif() + +message(STATUS "Found ASIO: TRUE (${ASIO_DIR})") + +# ASIO is header-only library so it is IMPORTED target +add_library(ASIO::ASIO INTERFACE IMPORTED GLOBAL) + +# set standalone version (do not use Boost) +set_target_properties(ASIO::ASIO PROPERTIES INTERFACE_COMPILE_DEFINITIONS "ASIO_STANDALONE" INTERFACE_INCLUDE_DIRECTORIES "${ASIO_DIR}") + +target_link_libraries(ASIO::ASIO INTERFACE Threads::Threads) +set(ASIO_FOUND TRUE) diff --git a/net/adc_netmsg.h b/net/adc_netmsg.h index eb9649f..9cf1cc8 100644 --- a/net/adc_netmsg.h +++ b/net/adc_netmsg.h @@ -46,11 +46,14 @@ void convertToBytes(ByteStorageT& res, const T& v, const Ts&... vs) namespace traits { -template +template concept adc_netmessage_c = requires(const T t) { // const methods + requires std::same_as, char>; { t.empty() } -> std::convertible_to; + { t.byteSize() } -> std::convertible_to; { t.bytes() } -> adc_output_char_range; { t.byteView() } -> adc_range_of_view_char_range; + { t.setFromBytes(std::input_iterator) } -> std::same_as; }; } // namespace traits diff --git a/net/adc_netservice.h b/net/adc_netservice.h index 53935a5..56c0870 100644 --- a/net/adc_netservice.h +++ b/net/adc_netservice.h @@ -29,6 +29,7 @@ public: using timeout_drtn_t = timeout_clock_t::duration; static constexpr timeout_drtn_t defaultConnectTimeout = std::chrono::seconds(5); + // static constexpr std::chrono::duration defaultConnectTimeout = std::chrono::seconds(5); static constexpr timeout_drtn_t defaultSendTimeout = std::chrono::seconds(5); static constexpr timeout_drtn_t defaultRecvTimeout = std::chrono::seconds(5); diff --git a/net/adc_netservice_asio.h b/net/adc_netservice_asio.h new file mode 100644 index 0000000..1820323 --- /dev/null +++ b/net/adc_netservice_asio.h @@ -0,0 +1,100 @@ +#pragma once + +/* + + ABSTRACT DEVICE COMPONENTS LIBRARY + + ASIO-library implementation of network service + + */ + + +#ifdef USE_ASIO_LIBRARY + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace adc::impl +{ + + +template +class AdcNetServiceASIOStream +{ +public: + using socket_t = typename InetProtoT::socket; + + AdcNetServiceASIOStream(socket_t& sock) : _socket(sock) {} + + virtual ~AdcNetServiceASIOStream() = default; + + + template + auto asynSend(const NetMessageT& msg, const TimeoutT& timeout, CompletionTokenT&& token) + requires std::derived_from> + { + using namespace asio::experimental::awaitable_operators; + + auto deadline = std::chrono::steady_clock::now() + timeout; + + std::error_code ec; + + co_await (asio::async_write(_socket, msg.bytes(), asio::use_awaitable) && watchdog(deadline, ec)); + + std::forward(token)(ec); + } + + + template + auto asynSend(const NetMessageT& msg, CompletionTokenT&& token) + requires std::derived_from> + { + } + + + template + auto asynSend(const NetMessageT& msg, CompletionTokenT&& token) + requires std::derived_from> + { + } + + + +protected: + socket_t& _socket; + + asio::streambuf _streamBuffer; + + template + asio::awaitable watchdog(TimepointT& deadline, std::error_code& ec) + { + ec.clear(); + typename TimepointT::clock timer(co_await asio::this_coro::executor); + + auto now = TimepointT::clock::template now(); + + while (deadline > now) { + timer.expires_at(deadline); + co_await timer.async_wait(asio::use_awaitable); + now = TimepointT::clock::template now(); + } + + ec = std::make_error_code(std::errc::timed_out); + + throw std::system_error(ec); + } +}; + + +} // namespace adc::impl + + +#endif