diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 90acf8e..e88d23c 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -48,6 +48,10 @@ jobs: restore-keys: conan-${{ runner.os }}- - name: Configure native release run: python3 modulus.py configure --target x86_64_gcc12_release + - name: Check code style + run: | + python3 -m pip install --no-cache-dir -r build/build_tools/docker/format-requirements.txt + python3 modulus.py format --check - name: Build native release run: python3 modulus.py build --target x86_64_gcc12_release - name: Test native release diff --git a/README.md b/README.md index 739bfd2..98df9e5 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Ligo uses Modulus for shared build tooling, Boost.JSON, and OpenSSL integration. ## Build +Code style is managed by Modulus: run `./modulus.py format` or `./modulus.py format --check`. The generated Neovim integration uses the same pinned container formatter for C++ and Python, including existing format-on-save toggles. Configure first to prepare tooling; customize `tooling.editor.clang_format` and `tooling.format.exclude` in `modulus.json`, not generated editor files. See the shared Modulus README for the compact layout and no-alias policy. + Configure, build, and test the default target: ```sh diff --git a/conanfile.py b/conanfile.py index 1c6bcdc..9d67c0f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -41,15 +41,12 @@ class ligo_conan(conan.ConanFile): "tests/*.cpp", "tests/*.hpp", ) - def config_options(self): if self.settings.os == "Windows": del self.options.fPIC - def configure(self): if self.options.shared: del self.options.fPIC - def requirements(self): self.requires( "modulus/latest", @@ -59,7 +56,6 @@ class ligo_conan(conan.ConanFile): "with_openssl": True, }, ) - def generate(self): deps = conan.tools.cmake.CMakeDeps(self) deps.generate() @@ -69,14 +65,12 @@ class ligo_conan(conan.ConanFile): toolchain.variables["BUILD_SHARED_LIBS"] = bool(self.options.shared) toolchain.variables["BUILD_TESTING"] = bool(self.options.with_tests) toolchain.generate() - def build(self): cmake = conan.tools.cmake.CMake(self) cmake.configure() cmake.build() if self.options.with_tests and conan.tools.build.can_run(self): cmake.test(target="check") - def package_id(self): self.info.options.rm_safe("with_tests") for requirement in ( @@ -88,11 +82,9 @@ class ligo_conan(conan.ConanFile): ): if requirement in self.info.requires.pkg_names: self.info.requires.remove(requirement) - def package(self): cmake = conan.tools.cmake.CMake(self) cmake.install() - def package_info(self): self.cpp_info.set_property( "cmake_file_name", diff --git a/include/ligo/config.hpp b/include/ligo/config.hpp index 2efebfb..dfec250 100755 --- a/include/ligo/config.hpp +++ b/include/ligo/config.hpp @@ -12,6 +12,7 @@ #include + namespace ligo { enum class protocol { @@ -41,14 +42,14 @@ struct endpoint_config { ligo::udp_reliability_config udp{}; }; -auto validate(ligo::endpoint_config const& config) -> std::expected; -auto parse_endpoint_config(boost::json::value const& value) -> std::expected; -auto parse_endpoint_configs(boost::json::value const& value) -> std::expected, modulus::error>; -auto load_endpoint_configs(std::string const& path) -> std::expected, modulus::error>; -auto to_json(ligo::udp_reliability_config const& config) -> boost::json::value; -auto to_json(ligo::http_config const& config) -> boost::json::value; -auto to_json(ligo::security_config const& config) -> boost::json::value; -auto to_json(ligo::endpoint_config const& config) -> boost::json::value; -auto to_json(std::vector const& configs) -> boost::json::value; +auto validate(ligo::endpoint_config const &config) -> std::expected; +auto parse_endpoint_config(boost::json::value const &value) -> std::expected; +auto parse_endpoint_configs(boost::json::value const &value) -> std::expected, modulus::error>; +auto load_endpoint_configs(std::string const &path) -> std::expected, modulus::error>; +auto to_json(ligo::udp_reliability_config const &config) -> boost::json::value; +auto to_json(ligo::http_config const &config) -> boost::json::value; +auto to_json(ligo::security_config const &config) -> boost::json::value; +auto to_json(ligo::endpoint_config const &config) -> boost::json::value; +auto to_json(std::vector const &configs) -> boost::json::value; } diff --git a/include/ligo/detail/errors.hpp b/include/ligo/detail/errors.hpp index caf17b7..7459cb9 100644 --- a/include/ligo/detail/errors.hpp +++ b/include/ligo/detail/errors.hpp @@ -8,26 +8,27 @@ #include + namespace ligo::detail { - constexpr std::int32_t error_ok{0}; - constexpr std::int32_t error_invalid_argument{1}; - constexpr std::int32_t error_not_found{2}; - constexpr std::int32_t error_unavailable{3}; - constexpr std::int32_t error_timeout{4}; - constexpr std::int32_t error_internal{5}; +constexpr std::int32_t error_ok{0}; +constexpr std::int32_t error_invalid_argument{1}; +constexpr std::int32_t error_not_found{2}; +constexpr std::int32_t error_unavailable{3}; +constexpr std::int32_t error_timeout{4}; +constexpr std::int32_t error_internal{5}; - auto make_error(std::int32_t code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> modulus::error; - auto fail_void(modulus::error error) -> std::expected; +auto make_error(std::int32_t code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> modulus::error; +auto fail_void(modulus::error error) -> std::expected; - template - auto fail(modulus::error error) -> std::expected; - template - auto fail(std::expected const& result) -> std::expected; - template - auto fail(std::int32_t code, MESSAGE&& message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected; - template - auto fail_void(std::int32_t code, MESSAGE&& message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected; +template +auto fail(modulus::error error) -> std::expected; +template +auto fail(std::expected const &result) -> std::expected; +template +auto fail(std::int32_t code, MESSAGE &&message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected; +template +auto fail_void(std::int32_t code, MESSAGE &&message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected; } @@ -37,17 +38,17 @@ auto ligo::detail::fail(modulus::error error) -> std::expected -auto ligo::detail::fail(std::expected const& result) -> std::expected { +auto ligo::detail::fail(std::expected const &result) -> std::expected { assert(!result); return ligo::detail::fail(result.error()); } template -auto ligo::detail::fail(std::int32_t code, MESSAGE&& message, modulus::source_location location) -> std::expected { +auto ligo::detail::fail(std::int32_t code, MESSAGE &&message, modulus::source_location location) -> std::expected { return modulus::fail(ligo::detail::make_error(code, std::string{std::forward(message)}, location)); } template -auto ligo::detail::fail_void(std::int32_t code, MESSAGE&& message, modulus::source_location location) -> std::expected { +auto ligo::detail::fail_void(std::int32_t code, MESSAGE &&message, modulus::source_location location) -> std::expected { return modulus::fail(ligo::detail::make_error(code, std::string{std::forward(message)}, location)); } diff --git a/include/ligo/detail/lifecycle.hpp b/include/ligo/detail/lifecycle.hpp index 852a049..00d3e18 100644 --- a/include/ligo/detail/lifecycle.hpp +++ b/include/ligo/detail/lifecycle.hpp @@ -25,17 +25,18 @@ #include #include + namespace ligo::detail { -auto cancel_session_stream(boost::beast::tcp_stream& stream) -> void; +auto cancel_session_stream(boost::beast::tcp_stream &stream) -> void; template -auto cancel_session_stream(boost::asio::ssl::stream& stream) -> void; +auto cancel_session_stream(boost::asio::ssl::stream &stream) -> void; template struct session_registry { - static auto cancel_waiters(std::vector> const& live) -> void; - auto add(std::shared_ptr const& stream) -> void; - auto remove(std::shared_ptr const& stream) -> void; + static auto cancel_waiters(std::vector> const &live) -> void; + auto add(std::shared_ptr const &stream) -> void; + auto remove(std::shared_ptr const &stream) -> void; auto cancel_all() -> void; auto empty() const -> std::bool_t; auto wait_empty(std::chrono::milliseconds timeout) -> boost::asio::awaitable>; @@ -57,34 +58,34 @@ struct session_guard { template auto stop_accepting_server(std::shared_ptr state) -> void; template -auto stop_accepting_server_now(std::shared_ptr const& state) -> void; +auto stop_accepting_server_now(std::shared_ptr const &state) -> void; template auto async_stop_accepting_server(std::shared_ptr state, std::chrono::milliseconds timeout) -> boost::asio::awaitable>; } template -auto ligo::detail::cancel_session_stream(boost::asio::ssl::stream& stream) -> void { +auto ligo::detail::cancel_session_stream(boost::asio::ssl::stream &stream) -> void { auto ignored = boost::system::error_code{}; stream.lowest_layer().cancel(ignored); stream.lowest_layer().close(ignored); } template -auto ligo::detail::session_registry::cancel_waiters(std::vector> const& live) -> void { - for (auto& waiter : live) { +auto ligo::detail::session_registry::cancel_waiters(std::vector> const &live) -> void { + for (auto &waiter : live) { waiter->cancel(); } } template -auto ligo::detail::session_registry::add(std::shared_ptr const& stream) -> void { +auto ligo::detail::session_registry::add(std::shared_ptr const &stream) -> void { auto lock = std::scoped_lock{mutex}; sessions.insert(stream); } template -auto ligo::detail::session_registry::remove(std::shared_ptr const& stream) -> void { +auto ligo::detail::session_registry::remove(std::shared_ptr const &stream) -> void { auto live = std::vector>{}; { auto lock = std::scoped_lock{mutex}; @@ -101,7 +102,7 @@ auto ligo::detail::session_registry::cancel_all() -> void { auto lock = std::scoped_lock{mutex}; copy.assign(sessions.begin(), sessions.end()); } - for (auto& stream : copy) { + for (auto &stream : copy) { boost::asio::post(stream->get_executor(), [stream] { ligo::detail::cancel_session_stream(*stream); }); @@ -132,7 +133,7 @@ auto ligo::detail::session_registry::wait_empty(std::chrono::milliseconds tim waiters.push_back(notify_timer); } deadline_timer->expires_after(timeout); - deadline_timer->async_wait([notify_timer, timed_out](boost::system::error_code const& error) { + deadline_timer->async_wait([notify_timer, timed_out](boost::system::error_code const &error) { if (!error) { timed_out->store(true, std::memory_order_relaxed); notify_timer->cancel(); @@ -168,7 +169,7 @@ template auto ligo::detail::session_registry::live_waiters_locked() -> std::vector> { auto live = std::vector>{}; auto retained = std::vector>{}; - for (auto& waiter : waiters) { + for (auto &waiter : waiters) { if (auto locked = waiter.lock()) { live.push_back(locked); retained.push_back(locked); @@ -209,7 +210,7 @@ auto ligo::detail::stop_accepting_server(std::shared_ptr state) -> void { } template -auto ligo::detail::stop_accepting_server_now(std::shared_ptr const& state) -> void { +auto ligo::detail::stop_accepting_server_now(std::shared_ptr const &state) -> void { auto lock = std::scoped_lock{state->lifecycle_mutex}; if (state->stopped.exchange(true)) { return; diff --git a/include/ligo/detail/state.hpp b/include/ligo/detail/state.hpp index 9d2acbc..f692fb3 100644 --- a/include/ligo/detail/state.hpp +++ b/include/ligo/detail/state.hpp @@ -7,16 +7,17 @@ #include + namespace ligo::detail { class state_handle { public: state_handle() = default; - state_handle(ligo::detail::state_handle const&) = delete; - state_handle(ligo::detail::state_handle&& other) noexcept; + state_handle(ligo::detail::state_handle const &) = delete; + state_handle(ligo::detail::state_handle &&other) noexcept; ~state_handle() = default; - auto operator=(ligo::detail::state_handle const&) -> ligo::detail::state_handle& = delete; - auto operator=(ligo::detail::state_handle&& other) noexcept -> ligo::detail::state_handle&; + auto operator=(ligo::detail::state_handle const &) -> ligo::detail::state_handle & = delete; + auto operator=(ligo::detail::state_handle &&other) noexcept -> ligo::detail::state_handle &; explicit operator std::bool_t() const noexcept; template explicit state_handle(std::shared_ptr state); @@ -29,27 +30,28 @@ private: class unique_state { public: unique_state() noexcept = default; - unique_state(ligo::detail::unique_state const&) = delete; - unique_state(ligo::detail::unique_state&&) noexcept = default; + unique_state(ligo::detail::unique_state const &) = delete; + unique_state(ligo::detail::unique_state &&) noexcept = default; ~unique_state() = default; - auto operator=(ligo::detail::unique_state const&) -> ligo::detail::unique_state& = delete; - auto operator=(ligo::detail::unique_state&&) noexcept -> ligo::detail::unique_state& = default; + auto operator=(ligo::detail::unique_state const &) -> ligo::detail::unique_state & = delete; + auto operator=(ligo::detail::unique_state &&) noexcept -> ligo::detail::unique_state & = default; explicit operator std::bool_t() const noexcept; template explicit unique_state(std::unique_ptr state); template - auto as() const noexcept -> STATE*; + auto as() const noexcept -> STATE *; private: - static auto ignore_state(void* state) -> void; + static auto ignore_state(void *state) -> void; template - static auto delete_state(void* state) -> void; - std::unique_ptr> state_{nullptr, ignore_state}; + static auto delete_state(void *state) -> void; + std::unique_ptr> state_{nullptr, ignore_state}; }; } template -ligo::detail::state_handle::state_handle(std::shared_ptr state) : state_{std::shared_ptr{std::move(state)}} {} +ligo::detail::state_handle::state_handle(std::shared_ptr state) + : state_{std::shared_ptr{std::move(state)}} {} template auto ligo::detail::state_handle::as() const -> std::shared_ptr { @@ -57,14 +59,15 @@ auto ligo::detail::state_handle::as() const -> std::shared_ptr { } template -ligo::detail::unique_state::unique_state(std::unique_ptr state) : state_{state.release(), delete_state} {} +ligo::detail::unique_state::unique_state(std::unique_ptr state) + : state_{state.release(), delete_state} {} template -auto ligo::detail::unique_state::as() const noexcept -> STATE* { - return static_cast(state_.get()); +auto ligo::detail::unique_state::as() const noexcept -> STATE * { + return static_cast(state_.get()); } template -auto ligo::detail::unique_state::delete_state(void* state) -> void { - delete static_cast(state); +auto ligo::detail::unique_state::delete_state(void *state) -> void { + delete static_cast(state); } diff --git a/include/ligo/detail/transport.hpp b/include/ligo/detail/transport.hpp index 2524cfd..29ceaff 100644 --- a/include/ligo/detail/transport.hpp +++ b/include/ligo/detail/transport.hpp @@ -28,6 +28,7 @@ #include #include + namespace ligo::detail { struct endpoint_parts { @@ -37,13 +38,13 @@ struct endpoint_parts { auto status_name(std::int32_t code) -> std::string; auto parse_status_code(std::string_view value) -> std::int32_t; -auto network_failure(boost::system::error_code const& error) -> modulus::error; -auto operation_failure(boost::system::error_code const& error, std::string timeout_message) -> modulus::error; +auto network_failure(boost::system::error_code const &error) -> modulus::error; +auto operation_failure(boost::system::error_code const &error, std::string timeout_message) -> modulus::error; auto invalid_argument(std::string message) -> modulus::error; auto unavailable(std::string message) -> modulus::error; auto validate_positive_timeout(std::chrono::milliseconds timeout, std::string_view name) -> std::expected; -auto report_error(std::function const& on_error, modulus::error error) -> void; -auto report_error(std::function const& on_error, std::expected status) -> void; +auto report_error(std::function const &on_error, modulus::error error) -> void; +auto report_error(std::function const &on_error, std::expected status) -> void; auto response_envelope(std::expected result) -> boost::json::value; auto serialize_response_envelope(std::expected result) -> std::string; auto unwrap_response_envelope(boost::json::value value, std::string_view protocol_name) -> std::expected; @@ -51,10 +52,10 @@ auto parse_port(std::string_view text) -> std::expected std::expected; auto parse_client_endpoint_text(std::string_view text) -> std::expected; auto parse_server_endpoint_text(std::string_view text) -> std::expected; -auto start_tcp_acceptor(boost::asio::ip::tcp::acceptor& acceptor, std::string const& host, std::uint16_t port) -> std::expected; -auto resolve_tcp_endpoints(boost::asio::any_io_executor executor, std::string const& host, std::uint16_t port, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable>; -auto call_handler(ligo::service_router const& router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable>; -auto call_response_handler(ligo::service_router const& router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable>; +auto start_tcp_acceptor(boost::asio::ip::tcp::acceptor &acceptor, std::string const &host, std::uint16_t port) -> std::expected; +auto resolve_tcp_endpoints(boost::asio::any_io_executor executor, std::string const &host, std::uint16_t port, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable>; +auto call_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable>; +auto call_response_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable>; struct stream_deadline { std::shared_ptr timer{}; @@ -63,29 +64,29 @@ struct stream_deadline { std::shared_ptr cancellation{}; }; -auto start_stream_deadline(boost::beast::tcp_stream& stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline; -auto start_stream_deadline(boost::asio::ip::tcp::socket& socket, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline; +auto start_stream_deadline(boost::beast::tcp_stream &stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline; +auto start_stream_deadline(boost::asio::ip::tcp::socket &socket, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline; template -auto start_stream_deadline(boost::asio::ssl::stream& stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline; +auto start_stream_deadline(boost::asio::ssl::stream &stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline; -auto cancel_stream_deadline(ligo::detail::stream_deadline& deadline) -> void; -auto deadline_token(ligo::detail::stream_deadline& deadline) -> decltype(boost::asio::bind_cancellation_slot(std::declval(), boost::asio::as_tuple(boost::asio::use_awaitable))); -auto operation_failure(boost::system::error_code const& error, ligo::detail::stream_deadline const& deadline, std::string timeout_message) -> modulus::error; +auto cancel_stream_deadline(ligo::detail::stream_deadline &deadline) -> void; +auto deadline_token(ligo::detail::stream_deadline &deadline) -> decltype(boost::asio::bind_cancellation_slot(std::declval(), boost::asio::as_tuple(boost::asio::use_awaitable))); +auto operation_failure(boost::system::error_code const &error, ligo::detail::stream_deadline const &deadline, std::string timeout_message) -> modulus::error; template -auto async_tls_handshake(boost::asio::ssl::stream& stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable>; +auto async_tls_handshake(boost::asio::ssl::stream &stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable>; template -auto async_tls_shutdown(boost::asio::ssl::stream& stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable>; +auto async_tls_shutdown(boost::asio::ssl::stream &stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable>; } template -auto ligo::detail::start_stream_deadline(boost::asio::ssl::stream& stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline { +auto ligo::detail::start_stream_deadline(boost::asio::ssl::stream &stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline { auto deadline = ligo::detail::stream_deadline{.timer = std::make_shared(stream.get_executor()), .timed_out = std::make_shared>(false), .active = std::make_shared>(true), .cancellation = std::make_shared()}; deadline.timer->expires_after(timeout); - deadline.timer->async_wait([timer = deadline.timer, timed_out = deadline.timed_out, active = deadline.active, cancellation = deadline.cancellation](boost::system::error_code const& error) { + deadline.timer->async_wait([timer = deadline.timer, timed_out = deadline.timed_out, active = deadline.active, cancellation = deadline.cancellation](boost::system::error_code const &error) { if (!error && active->exchange(false, std::memory_order_acq_rel)) { timed_out->store(true, std::memory_order_release); cancellation->emit(boost::asio::cancellation_type::terminal); @@ -95,7 +96,7 @@ auto ligo::detail::start_stream_deadline(boost::asio::ssl::stream& s } template -auto ligo::detail::async_tls_handshake(boost::asio::ssl::stream& stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { +auto ligo::detail::async_tls_handshake(boost::asio::ssl::stream &stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { auto deadline = ligo::detail::start_stream_deadline(stream, timeout); auto [error] = co_await stream.async_handshake(type, ligo::detail::deadline_token(deadline)); ligo::detail::cancel_stream_deadline(deadline); @@ -106,7 +107,7 @@ auto ligo::detail::async_tls_handshake(boost::asio::ssl::stream& str } template -auto ligo::detail::async_tls_shutdown(boost::asio::ssl::stream& stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { +auto ligo::detail::async_tls_shutdown(boost::asio::ssl::stream &stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { auto deadline = ligo::detail::start_stream_deadline(stream, timeout); auto [error] = co_await stream.async_shutdown(ligo::detail::deadline_token(deadline)); ligo::detail::cancel_stream_deadline(deadline); diff --git a/include/ligo/http.hpp b/include/ligo/http.hpp index 78d1b27..fe35618 100755 --- a/include/ligo/http.hpp +++ b/include/ligo/http.hpp @@ -55,7 +55,7 @@ struct server_options { class client { public: explicit client(ligo::http::endpoint endpoint, ligo::http::client_options options = {}); - auto call(ligo::http::request const& request) const -> boost::asio::awaitable>; + auto call(ligo::http::request const &request) const -> boost::asio::awaitable>; private: ligo::http::endpoint endpoint_{}; ligo::http::client_options options_{}; @@ -63,13 +63,13 @@ private: class server { public: - server(boost::asio::io_context& io, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options = {}); + server(boost::asio::io_context &io, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options = {}); server(boost::asio::any_io_executor executor, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options = {}); - server(ligo::http::server const&) = delete; - server(ligo::http::server&&) noexcept = default; + server(ligo::http::server const &) = delete; + server(ligo::http::server &&) noexcept = default; ~server(); - auto operator=(ligo::http::server const&) -> ligo::http::server& = delete; - auto operator=(ligo::http::server&&) noexcept -> ligo::http::server&; + auto operator=(ligo::http::server const &) -> ligo::http::server & = delete; + auto operator=(ligo::http::server &&) noexcept -> ligo::http::server &; auto start() -> std::expected; auto stop() -> void; auto async_stop(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable>; @@ -78,9 +78,9 @@ private: ligo::detail::state_handle state_{}; }; -auto client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected; -auto server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected; -auto client_options_from_config(ligo::endpoint_config const& config) -> ligo::http::client_options; -auto server_options_from_config(ligo::endpoint_config const& config) -> ligo::http::server_options; +auto client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected; +auto server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected; +auto client_options_from_config(ligo::endpoint_config const &config) -> ligo::http::client_options; +auto server_options_from_config(ligo::endpoint_config const &config) -> ligo::http::server_options; } diff --git a/include/ligo/net.hpp b/include/ligo/net.hpp index 0076569..682e0f0 100644 --- a/include/ligo/net.hpp +++ b/include/ligo/net.hpp @@ -25,18 +25,18 @@ class byte_stream_state; class byte_stream { public: byte_stream() = default; - byte_stream(ligo::net::byte_stream const&) = delete; - byte_stream(ligo::net::byte_stream&&) noexcept = default; + byte_stream(ligo::net::byte_stream const &) = delete; + byte_stream(ligo::net::byte_stream &&) noexcept = default; ~byte_stream(); - auto operator=(ligo::net::byte_stream const&) -> ligo::net::byte_stream& = delete; - auto operator=(ligo::net::byte_stream&&) noexcept -> ligo::net::byte_stream&; + auto operator=(ligo::net::byte_stream const &) -> ligo::net::byte_stream & = delete; + auto operator=(ligo::net::byte_stream &&) noexcept -> ligo::net::byte_stream &; static auto from_socket(ligo::tcp::socket_handle socket) -> std::expected; static auto from_tls_socket(ligo::tcp::tls_socket socket) -> std::expected; auto async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable>; auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable>; auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable>; auto async_shutdown(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable>; - auto close(boost::system::error_code& error) -> void; + auto close(boost::system::error_code &error) -> void; auto is_open() const -> std::bool_t; private: explicit byte_stream(std::shared_ptr state); @@ -46,11 +46,11 @@ private: class listener { public: listener() = default; - listener(ligo::net::listener const&) = delete; - listener(ligo::net::listener&&) noexcept = default; + listener(ligo::net::listener const &) = delete; + listener(ligo::net::listener &&) noexcept = default; ~listener(); - auto operator=(ligo::net::listener const&) -> ligo::net::listener& = delete; - auto operator=(ligo::net::listener&&) noexcept -> ligo::net::listener&; + auto operator=(ligo::net::listener const &) -> ligo::net::listener & = delete; + auto operator=(ligo::net::listener &&) noexcept -> ligo::net::listener &; static auto bind(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint) -> std::expected; auto selected_port() const -> std::uint16_t; auto async_accept() -> boost::asio::awaitable>; @@ -64,7 +64,7 @@ private: auto connect_tcp(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable>; auto connect(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable>; -auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const& config) -> boost::asio::awaitable>; +auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable>; auto connect_tls_configured(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}, ligo::security_config security = {.mode = ligo::security_mode::TLS}) -> boost::asio::awaitable>; auto connect_tls_handshaken(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}, ligo::security_config security = {.mode = ligo::security_mode::TLS}) -> boost::asio::awaitable>; diff --git a/include/ligo/security.hpp b/include/ligo/security.hpp index 9c1ceb2..a7cde26 100644 --- a/include/ligo/security.hpp +++ b/include/ligo/security.hpp @@ -11,6 +11,7 @@ #include + namespace ligo { enum class security_mode { @@ -35,12 +36,12 @@ struct security_config { std::shared_ptr tls_context{}; }; -auto make_tls_client_context(ligo::security_config const& config) -> std::expected, modulus::error>; -auto make_tls_server_context(ligo::security_config const& config) -> std::expected, modulus::error>; -auto apply_tls_client_verification(boost::asio::ssl::stream& stream, std::string const& host, ligo::security_config const& config) -> std::expected; -auto configure_tls_client_stream(boost::asio::ssl::stream& stream, std::string const& host, ligo::security_config const& config) -> std::expected; -auto validate_tls_server_config(std::string_view protocol, ligo::security_config const& config) -> std::expected; -auto validate_tls_server_context(std::shared_ptr const& context) -> std::expected; +auto make_tls_client_context(ligo::security_config const &config) -> std::expected, modulus::error>; +auto make_tls_server_context(ligo::security_config const &config) -> std::expected, modulus::error>; +auto apply_tls_client_verification(boost::asio::ssl::stream &stream, std::string const &host, ligo::security_config const &config) -> std::expected; +auto configure_tls_client_stream(boost::asio::ssl::stream &stream, std::string const &host, ligo::security_config const &config) -> std::expected; +auto validate_tls_server_config(std::string_view protocol, ligo::security_config const &config) -> std::expected; +auto validate_tls_server_context(std::shared_ptr const &context) -> std::expected; auto unsupported_security(std::string_view protocol, ligo::security_mode mode) -> modulus::error; } diff --git a/include/ligo/service.hpp b/include/ligo/service.hpp index c894e7d..75e5810 100755 --- a/include/ligo/service.hpp +++ b/include/ligo/service.hpp @@ -13,6 +13,7 @@ #include + namespace ligo { struct request_context { @@ -29,11 +30,11 @@ struct service_response { class service_router { public: service_router() = default; - service_router(ligo::service_router const& other); - service_router(ligo::service_router&& other); + service_router(ligo::service_router const &other); + service_router(ligo::service_router &&other); ~service_router() = default; - auto operator=(ligo::service_router const& other) -> ligo::service_router&; - auto operator=(ligo::service_router&& other) -> ligo::service_router&; + auto operator=(ligo::service_router const &other) -> ligo::service_router &; + auto operator=(ligo::service_router &&other) -> ligo::service_router &; auto add_route(std::string method, std::string route, std::function>(ligo::request_context, boost::json::value)> handler) -> void; auto add_response_route(std::string method, std::string route, std::function>(ligo::request_context, boost::json::value)> handler) -> void; auto call(ligo::request_context context, boost::json::value payload) const -> boost::asio::awaitable>; diff --git a/include/ligo/tcp.hpp b/include/ligo/tcp.hpp index 2b93b2f..1752a00 100755 --- a/include/ligo/tcp.hpp +++ b/include/ligo/tcp.hpp @@ -33,16 +33,16 @@ struct endpoint { struct socket_handle { socket_handle() = default; - socket_handle(ligo::tcp::socket_handle const&) = delete; - socket_handle(ligo::tcp::socket_handle&&) noexcept = default; + socket_handle(ligo::tcp::socket_handle const &) = delete; + socket_handle(ligo::tcp::socket_handle &&) noexcept = default; explicit socket_handle(boost::asio::ip::tcp::socket socket); explicit socket_handle(std::shared_ptr socket); - auto operator=(ligo::tcp::socket_handle const&) -> ligo::tcp::socket_handle& = delete; - auto operator=(ligo::tcp::socket_handle&&) noexcept -> ligo::tcp::socket_handle& = default; + auto operator=(ligo::tcp::socket_handle const &) -> ligo::tcp::socket_handle & = delete; + auto operator=(ligo::tcp::socket_handle &&) noexcept -> ligo::tcp::socket_handle & = default; auto socket() -> std::expected, modulus::error>; auto socket() const -> std::expected, modulus::error>; auto is_open() const -> std::bool_t; - auto close(boost::system::error_code& error) -> void; + auto close(boost::system::error_code &error) -> void; auto release_socket() -> std::expected; private: std::shared_ptr socket_{}; @@ -55,17 +55,17 @@ struct tls_socket { boost::asio::ssl::stream stream; }; tls_socket() = default; - tls_socket(ligo::tcp::tls_socket const&) = delete; - tls_socket(ligo::tcp::tls_socket&&) noexcept = default; + tls_socket(ligo::tcp::tls_socket const &) = delete; + tls_socket(ligo::tcp::tls_socket &&) noexcept = default; tls_socket(std::shared_ptr context, boost::asio::ip::tcp::socket socket); - auto operator=(ligo::tcp::tls_socket const&) -> ligo::tcp::tls_socket& = delete; - auto operator=(ligo::tcp::tls_socket&&) noexcept -> ligo::tcp::tls_socket& = default; + auto operator=(ligo::tcp::tls_socket const &) -> ligo::tcp::tls_socket & = delete; + auto operator=(ligo::tcp::tls_socket &&) noexcept -> ligo::tcp::tls_socket & = default; auto stream() -> std::expected>, modulus::error>; auto stream() const -> std::expected const>, modulus::error>; auto context() -> std::expected, modulus::error>; auto context() const -> std::expected, modulus::error>; auto is_open() const -> std::bool_t; - auto close(boost::system::error_code& error) -> void; + auto close(boost::system::error_code &error) -> void; auto release_stream() -> std::expected; private: std::shared_ptr context_{}; @@ -91,7 +91,7 @@ struct server_options { class client { public: explicit client(ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}); - auto call(ligo::tcp::request const& request) const -> boost::asio::awaitable>; + auto call(ligo::tcp::request const &request) const -> boost::asio::awaitable>; private: ligo::tcp::endpoint endpoint_{}; ligo::tcp::client_options options_{}; @@ -99,13 +99,13 @@ private: class server { public: - server(boost::asio::io_context& io, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options = {}); + server(boost::asio::io_context &io, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options = {}); server(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options = {}); - server(ligo::tcp::server const&) = delete; - server(ligo::tcp::server&&) noexcept = default; + server(ligo::tcp::server const &) = delete; + server(ligo::tcp::server &&) noexcept = default; ~server(); - auto operator=(ligo::tcp::server const&) -> ligo::tcp::server& = delete; - auto operator=(ligo::tcp::server&&) noexcept -> ligo::tcp::server&; + auto operator=(ligo::tcp::server const &) -> ligo::tcp::server & = delete; + auto operator=(ligo::tcp::server &&) noexcept -> ligo::tcp::server &; auto start() -> std::expected; auto stop() -> void; auto async_stop(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable>; @@ -114,15 +114,16 @@ private: ligo::detail::state_handle state_{}; }; -auto client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected; -auto server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected; -auto client_options_from_config(ligo::endpoint_config const& config) -> ligo::tcp::client_options; -auto server_options_from_config(ligo::endpoint_config const& config) -> ligo::tcp::server_options; +auto client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected; +auto server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected; +auto client_options_from_config(ligo::endpoint_config const &config) -> ligo::tcp::client_options; +auto server_options_from_config(ligo::endpoint_config const &config) -> ligo::tcp::server_options; auto connect(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable>; -auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const& config) -> boost::asio::awaitable>; +auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable>; auto connect_tls_configured(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}, ligo::security_config security = {.mode = ligo::security_mode::TLS}) -> boost::asio::awaitable>; auto connect_tls_handshaken(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}, ligo::security_config security = {.mode = ligo::security_mode::TLS}) -> boost::asio::awaitable>; -inline tls_socket::released_stream::released_stream(std::shared_ptr context, boost::asio::ssl::stream stream) : context{std::move(context)}, stream{std::move(stream)} {} +inline tls_socket::released_stream::released_stream(std::shared_ptr context, boost::asio::ssl::stream stream) + : context{std::move(context)}, stream{std::move(stream)} {} } diff --git a/include/ligo/udp.hpp b/include/ligo/udp.hpp index 053741e..c6f41dc 100755 --- a/include/ligo/udp.hpp +++ b/include/ligo/udp.hpp @@ -42,15 +42,15 @@ struct server_options { class client { public: - client(ligo::udp::client const&) = delete; - client(ligo::udp::client&&) noexcept = default; + client(ligo::udp::client const &) = delete; + client(ligo::udp::client &&) noexcept = default; ~client(); - auto operator=(ligo::udp::client const&) -> ligo::udp::client& = delete; - auto operator=(ligo::udp::client&&) noexcept -> ligo::udp::client&; + auto operator=(ligo::udp::client const &) -> ligo::udp::client & = delete; + auto operator=(ligo::udp::client &&) noexcept -> ligo::udp::client &; static auto open(boost::asio::any_io_executor executor, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected; - static auto open(boost::asio::io_context& io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected; + static auto open(boost::asio::io_context &io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected; static auto bind(boost::asio::any_io_executor executor, ligo::udp::endpoint endpoint, ligo::udp::client_options options = {}) -> std::expected; - static auto bind(boost::asio::io_context& io, ligo::udp::endpoint endpoint, ligo::udp::client_options options = {}) -> std::expected; + static auto bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::client_options options = {}) -> std::expected; static auto adopt(std::unique_ptr socket, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected; auto send(boost::json::value payload) -> boost::asio::awaitable>; auto send(ligo::udp::message message) -> boost::asio::awaitable>; @@ -65,13 +65,13 @@ private: class server { public: - server(ligo::udp::server const&) = delete; - server(ligo::udp::server&&) noexcept = default; + server(ligo::udp::server const &) = delete; + server(ligo::udp::server &&) noexcept = default; ~server(); - auto operator=(ligo::udp::server const&) -> ligo::udp::server& = delete; - auto operator=(ligo::udp::server&&) noexcept -> ligo::udp::server&; + auto operator=(ligo::udp::server const &) -> ligo::udp::server & = delete; + auto operator=(ligo::udp::server &&) noexcept -> ligo::udp::server &; static auto bind(boost::asio::any_io_executor executor, ligo::udp::endpoint endpoint, ligo::udp::server_options options = {}) -> std::expected; - static auto bind(boost::asio::io_context& io, ligo::udp::endpoint endpoint, ligo::udp::server_options options = {}) -> std::expected; + static auto bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::server_options options = {}) -> std::expected; static auto adopt(std::unique_ptr socket, boost::asio::ip::udp::endpoint peer, ligo::udp::server_options options = {}) -> std::expected; auto send(boost::json::value payload) -> boost::asio::awaitable>; auto send(ligo::udp::message message) -> boost::asio::awaitable>; @@ -84,9 +84,9 @@ private: ligo::detail::state_handle state_{}; }; -auto client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected; -auto server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected; -auto client_options_from_config(ligo::endpoint_config const& config) -> ligo::udp::client_options; -auto server_options_from_config(ligo::endpoint_config const& config) -> ligo::udp::server_options; +auto client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected; +auto server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected; +auto client_options_from_config(ligo::endpoint_config const &config) -> ligo::udp::client_options; +auto server_options_from_config(ligo::endpoint_config const &config) -> ligo::udp::server_options; } diff --git a/modulus.py b/modulus.py index b27d44c..1b69392 100755 --- a/modulus.py +++ b/modulus.py @@ -16,6 +16,7 @@ COMMANDS = ( "package", "lsp", "clangd", + "format", ) COMMON_DIR = pathlib.Path("build") / "build_common" TOOLS_DIR = pathlib.Path("build") / "build_tools" @@ -60,6 +61,9 @@ def runtime_ready(root): and (root / TOOLS_DIR / "clangd.py").is_file() and (root / RUNTIME_DIR / "modulus" / "cli.py").is_file() and (root / RUNTIME_DIR / "modulus" / "export.py").is_file() + and (root / TOOLS_DIR / "format.py").is_file() + and (root / RUNTIME_DIR / "modulus" / "formatting.py").is_file() + and (root / RUNTIME_DIR / "modulus" / "format_layout.py").is_file() ) def optional_credentials(): @@ -340,9 +344,9 @@ def ensure_runtime(root): def delegate(command, argv): root = repo_root() - if command == "clangd": + if command in {"clangd", "format"}: if not runtime_ready(root): - print("Modulus clangd tooling is missing; run ./modulus.py configure first", file=sys.stderr) + print(f"Modulus {command} tooling is missing; run ./modulus.py configure first", file=sys.stderr) return 1 else: ensure_runtime(root) diff --git a/src/config.cpp b/src/config.cpp index 98c92cc..850012c 100755 --- a/src/config.cpp +++ b/src/config.cpp @@ -17,13 +17,13 @@ #include #include + namespace { constexpr auto json_options = modulus::json_config::options{ .category = "ligo", .invalid_argument_code = ligo::detail::error_invalid_argument, - .not_found_code = ligo::detail::error_not_found -}; + .not_found_code = ligo::detail::error_not_found}; auto protocol_name(ligo::protocol value) -> std::string_view { switch (value) { @@ -61,54 +61,57 @@ auto verify_mode_name(ligo::verify_mode value) -> std::string_view { return "defaulted"; } -auto parse_security_config(boost::json::value const& value) -> std::expected { +auto parse_security_config(boost::json::value const &value) -> std::expected { auto object = modulus::json_config::require_object(value, "endpoint security", json_options); if (!object) { return ligo::detail::fail(object.error()); } auto unknown = modulus::json_config::reject_unknown_fields(**object, { - "mode", - "verify", - "peer_name", - "ca_file", - "certificate_chain_file", - "private_key_file", - }, "endpoint security", json_options); + "mode", + "verify", + "peer_name", + "ca_file", + "certificate_chain_file", + "private_key_file", + }, + "endpoint security", json_options); if (!unknown) { return ligo::detail::fail(unknown.error()); } auto config = ligo::security_config{}; auto mode = modulus::json_config::optional_enum_field(**object, "mode", config.mode, { - { - .name = "none", - .value = ligo::security_mode::NONE, - }, - { - .name = "tls", - .value = ligo::security_mode::TLS, - }, - { - .name = "dtls", - .value = ligo::security_mode::DTLS, - }, - }, "endpoint security mode must be none, tls, or dtls", json_options); + { + .name = "none", + .value = ligo::security_mode::NONE, + }, + { + .name = "tls", + .value = ligo::security_mode::TLS, + }, + { + .name = "dtls", + .value = ligo::security_mode::DTLS, + }, + }, + "endpoint security mode must be none, tls, or dtls", json_options); if (!mode) { return ligo::detail::fail(mode.error()); } auto verify = modulus::json_config::optional_enum_field(**object, "verify", config.verify, { - { - .name = "defaulted", - .value = ligo::verify_mode::DEFAULTED, - }, - { - .name = "none", - .value = ligo::verify_mode::NONE, - }, - { - .name = "peer", - .value = ligo::verify_mode::PEER, - }, - }, "endpoint security verify must be defaulted, none, or peer", json_options); + { + .name = "defaulted", + .value = ligo::verify_mode::DEFAULTED, + }, + { + .name = "none", + .value = ligo::verify_mode::NONE, + }, + { + .name = "peer", + .value = ligo::verify_mode::PEER, + }, + }, + "endpoint security verify must be defaulted, none, or peer", json_options); if (!verify) { return ligo::detail::fail(verify.error()); } @@ -139,7 +142,7 @@ auto parse_security_config(boost::json::value const& value) -> std::expected std::expected { +auto ligo::validate(ligo::endpoint_config const &config) -> std::expected { if (config.name.empty()) { return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "endpoint name is required"); } @@ -161,21 +164,22 @@ auto ligo::validate(ligo::endpoint_config const& config) -> std::expected std::expected { +auto ligo::parse_endpoint_config(boost::json::value const &value) -> std::expected { auto object = modulus::json_config::require_object(value, "endpoint", json_options); if (!object) { return ligo::detail::fail(object.error()); } auto unknown = modulus::json_config::reject_unknown_fields(**object, { - "name", - "protocol", - "bind", - "connect", - "timeout_ms", - "security", - "http", - "udp", - }, "endpoint", json_options); + "name", + "protocol", + "bind", + "connect", + "timeout_ms", + "security", + "http", + "udp", + }, + "endpoint", json_options); if (!unknown) { return ligo::detail::fail(unknown.error()); } @@ -185,19 +189,20 @@ auto ligo::parse_endpoint_config(boost::json::value const& value) -> std::expect return ligo::detail::fail(name.error()); } auto protocol = modulus::json_config::optional_enum_field(**object, "protocol", config.protocol, { - { - .name = "http", - .value = ligo::protocol::HTTP, - }, - { - .name = "tcp", - .value = ligo::protocol::TCP, - }, - { - .name = "udp", - .value = ligo::protocol::UDP, - }, - }, "endpoint protocol must be http, tcp, or udp", json_options); + { + .name = "http", + .value = ligo::protocol::HTTP, + }, + { + .name = "tcp", + .value = ligo::protocol::TCP, + }, + { + .name = "udp", + .value = ligo::protocol::UDP, + }, + }, + "endpoint protocol must be http, tcp, or udp", json_options); if (!protocol) { return ligo::detail::fail(protocol.error()); } @@ -246,10 +251,11 @@ auto ligo::parse_endpoint_config(boost::json::value const& value) -> std::expect return ligo::detail::fail(udp.error()); } auto udp_unknown = modulus::json_config::reject_unknown_fields(**udp, { - "resend_interval_ms", - "max_in_flight", - "session_timeout_ms", - }, "endpoint udp", json_options); + "resend_interval_ms", + "max_in_flight", + "session_timeout_ms", + }, + "endpoint udp", json_options); if (!udp_unknown) { return ligo::detail::fail(udp_unknown.error()); } @@ -276,7 +282,7 @@ auto ligo::parse_endpoint_config(boost::json::value const& value) -> std::expect return modulus::success(std::move(config)); } -auto ligo::parse_endpoint_configs(boost::json::value const& value) -> std::expected, modulus::error> { +auto ligo::parse_endpoint_configs(boost::json::value const &value) -> std::expected, modulus::error> { auto object = modulus::json_config::require_object(value, "config root", json_options); if (!object) { return ligo::detail::fail>(object.error()); @@ -290,7 +296,7 @@ auto ligo::parse_endpoint_configs(boost::json::value const& value) -> std::expec return ligo::detail::fail>(ligo::detail::error_invalid_argument, "config endpoints array is required"); } auto configs = std::vector{}; - for (auto const& endpoint_value : found->value().as_array()) { + for (auto const &endpoint_value : found->value().as_array()) { auto parsed = ligo::parse_endpoint_config(endpoint_value); if (!parsed) { return ligo::detail::fail>(parsed.error()); @@ -300,7 +306,7 @@ auto ligo::parse_endpoint_configs(boost::json::value const& value) -> std::expec return modulus::success(std::move(configs)); } -auto ligo::load_endpoint_configs(std::string const& path) -> std::expected, modulus::error> { +auto ligo::load_endpoint_configs(std::string const &path) -> std::expected, modulus::error> { auto value = modulus::json_config::load_value(path, json_options); if (!value) { return ligo::detail::fail>(value.error()); @@ -308,7 +314,7 @@ auto ligo::load_endpoint_configs(std::string const& path) -> std::expected boost::json::value { +auto ligo::to_json(ligo::udp_reliability_config const &config) -> boost::json::value { return boost::json::object{ { "resend_interval_ms", @@ -325,7 +331,7 @@ auto ligo::to_json(ligo::udp_reliability_config const& config) -> boost::json::v }; } -auto ligo::to_json(ligo::http_config const& config) -> boost::json::value { +auto ligo::to_json(ligo::http_config const &config) -> boost::json::value { return boost::json::object{ { "max_body_size", @@ -334,7 +340,7 @@ auto ligo::to_json(ligo::http_config const& config) -> boost::json::value { }; } -auto ligo::to_json(ligo::security_config const& config) -> boost::json::value { +auto ligo::to_json(ligo::security_config const &config) -> boost::json::value { return boost::json::object{ { "mode", @@ -363,7 +369,7 @@ auto ligo::to_json(ligo::security_config const& config) -> boost::json::value { }; } -auto ligo::to_json(ligo::endpoint_config const& config) -> boost::json::value { +auto ligo::to_json(ligo::endpoint_config const &config) -> boost::json::value { return boost::json::object{ { "name", @@ -400,9 +406,9 @@ auto ligo::to_json(ligo::endpoint_config const& config) -> boost::json::value { }; } -auto ligo::to_json(std::vector const& configs) -> boost::json::value { +auto ligo::to_json(std::vector const &configs) -> boost::json::value { auto endpoints = boost::json::array{}; - for (auto const& config : configs) { + for (auto const &config : configs) { endpoints.push_back(ligo::to_json(config)); } return boost::json::object{ diff --git a/src/detail/errors.cpp b/src/detail/errors.cpp index 65c4ea7..3881a9a 100644 --- a/src/detail/errors.cpp +++ b/src/detail/errors.cpp @@ -5,6 +5,7 @@ #include #include + auto ligo::detail::make_error(std::int32_t code, std::string message, modulus::source_location location) -> modulus::error { return modulus::make_error("ligo", code, std::move(message), location); } diff --git a/src/detail/lifecycle.cpp b/src/detail/lifecycle.cpp index 7a5a897..76bd531 100644 --- a/src/detail/lifecycle.cpp +++ b/src/detail/lifecycle.cpp @@ -3,7 +3,8 @@ #include #include -auto ligo::detail::cancel_session_stream(boost::beast::tcp_stream& stream) -> void { + +auto ligo::detail::cancel_session_stream(boost::beast::tcp_stream &stream) -> void { auto ignored = boost::system::error_code{}; stream.socket().cancel(ignored); stream.socket().close(ignored); diff --git a/src/detail/transport.cpp b/src/detail/transport.cpp index 7fa92b6..1b5a048 100644 --- a/src/detail/transport.cpp +++ b/src/detail/transport.cpp @@ -30,9 +30,10 @@ #include #include + namespace { -auto error_status_code(boost::system::error_code const& error) -> std::int32_t { +auto error_status_code(boost::system::error_code const &error) -> std::int32_t { if (!error) { return ligo::detail::error_ok; } @@ -47,9 +48,10 @@ auto error_status_code(boost::system::error_code const& error) -> std::int32_t { } -ligo::detail::state_handle::state_handle(ligo::detail::state_handle&& other) noexcept : state_{other.state_.exchange(nullptr)} {} +ligo::detail::state_handle::state_handle(ligo::detail::state_handle &&other) noexcept + : state_{other.state_.exchange(nullptr)} {} -auto ligo::detail::state_handle::operator=(ligo::detail::state_handle&& other) noexcept -> ligo::detail::state_handle& { +auto ligo::detail::state_handle::operator=(ligo::detail::state_handle &&other) noexcept -> ligo::detail::state_handle & { if (this != &other) { state_.store(other.state_.exchange(nullptr)); } @@ -64,7 +66,7 @@ ligo::detail::unique_state::operator std::bool_t() const noexcept { return static_cast(state_); } -auto ligo::detail::unique_state::ignore_state(void* state) -> void { +auto ligo::detail::unique_state::ignore_state(void *state) -> void { static_cast(state); } @@ -105,25 +107,25 @@ auto ligo::detail::parse_status_code(std::string_view value) -> std::int32_t { return ligo::detail::error_internal; } -auto ligo::detail::network_failure(boost::system::error_code const& error) -> modulus::error { +auto ligo::detail::network_failure(boost::system::error_code const &error) -> modulus::error { return ligo::detail::make_error(error_status_code(error), error.message()); } -auto ligo::detail::operation_failure(boost::system::error_code const& error, std::string timeout_message) -> modulus::error { +auto ligo::detail::operation_failure(boost::system::error_code const &error, std::string timeout_message) -> modulus::error { if (error_status_code(error) == ligo::detail::error_timeout) { return ligo::detail::make_error(ligo::detail::error_timeout, std::move(timeout_message)); } return ligo::detail::network_failure(error); } -auto ligo::detail::start_stream_deadline(boost::beast::tcp_stream& stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline { +auto ligo::detail::start_stream_deadline(boost::beast::tcp_stream &stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline { stream.expires_after(timeout); return { .cancellation = std::make_shared(), }; } -auto ligo::detail::start_stream_deadline(boost::asio::ip::tcp::socket& socket, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline { +auto ligo::detail::start_stream_deadline(boost::asio::ip::tcp::socket &socket, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline { auto deadline = ligo::detail::stream_deadline{ .timer = std::make_shared(socket.get_executor()), .timed_out = std::make_shared>(false), @@ -131,7 +133,7 @@ auto ligo::detail::start_stream_deadline(boost::asio::ip::tcp::socket& socket, s .cancellation = std::make_shared(), }; deadline.timer->expires_after(timeout); - deadline.timer->async_wait([timer = deadline.timer, timed_out = deadline.timed_out, active = deadline.active, cancellation = deadline.cancellation](boost::system::error_code const& error) { + deadline.timer->async_wait([timer = deadline.timer, timed_out = deadline.timed_out, active = deadline.active, cancellation = deadline.cancellation](boost::system::error_code const &error) { if (!error && active->exchange(false, std::memory_order_acq_rel)) { timed_out->store(true, std::memory_order_release); cancellation->emit(boost::asio::cancellation_type::terminal); @@ -140,7 +142,7 @@ auto ligo::detail::start_stream_deadline(boost::asio::ip::tcp::socket& socket, s return deadline; } -auto ligo::detail::cancel_stream_deadline(ligo::detail::stream_deadline& deadline) -> void { +auto ligo::detail::cancel_stream_deadline(ligo::detail::stream_deadline &deadline) -> void { if (deadline.active) { deadline.active->store(false, std::memory_order_release); } @@ -149,11 +151,11 @@ auto ligo::detail::cancel_stream_deadline(ligo::detail::stream_deadline& deadlin } } -auto ligo::detail::deadline_token(ligo::detail::stream_deadline& deadline) -> decltype(boost::asio::bind_cancellation_slot(std::declval(), boost::asio::as_tuple(boost::asio::use_awaitable))) { +auto ligo::detail::deadline_token(ligo::detail::stream_deadline &deadline) -> decltype(boost::asio::bind_cancellation_slot(std::declval(), boost::asio::as_tuple(boost::asio::use_awaitable))) { return boost::asio::bind_cancellation_slot(deadline.cancellation->slot(), boost::asio::as_tuple(boost::asio::use_awaitable)); } -auto ligo::detail::operation_failure(boost::system::error_code const& error, ligo::detail::stream_deadline const& deadline, std::string timeout_message) -> modulus::error { +auto ligo::detail::operation_failure(boost::system::error_code const &error, ligo::detail::stream_deadline const &deadline, std::string timeout_message) -> modulus::error { if (deadline.timed_out && deadline.timed_out->load(std::memory_order_acquire)) { return ligo::detail::make_error(ligo::detail::error_timeout, std::move(timeout_message)); } @@ -175,7 +177,7 @@ auto ligo::detail::validate_positive_timeout(std::chrono::milliseconds timeout, return {}; } -auto ligo::detail::report_error(std::function const& on_error, modulus::error error) -> void { +auto ligo::detail::report_error(std::function const &on_error, modulus::error error) -> void { if (!on_error) { return; } @@ -185,7 +187,7 @@ auto ligo::detail::report_error(std::function const& on_er } } -auto ligo::detail::report_error(std::function const& on_error, std::expected status) -> void { +auto ligo::detail::report_error(std::function const &on_error, std::expected status) -> void { if (!status) { ligo::detail::report_error(on_error, status.error()); } @@ -212,7 +214,7 @@ auto ligo::detail::unwrap_response_envelope(boost::json::value value, std::strin if (!value.is_object()) { return ligo::detail::fail(ligo::detail::error_invalid_argument, prefix + " response must be an object"); } - auto const& object = value.as_object(); + auto const &object = value.as_object(); auto ok = object.find("ok"); if (ok == object.end() || !ok->value().is_bool()) { return ligo::detail::fail(ligo::detail::error_invalid_argument, prefix + " response missing ok flag"); @@ -234,8 +236,8 @@ auto ligo::detail::parse_port(std::string_view text) -> std::expected(ligo::detail::error_invalid_argument, "endpoint port is required"); } auto parsed = 0U; - auto const* begin = text.data(); - auto const* end = text.data() + text.size(); + auto const *begin = text.data(); + auto const *end = text.data() + text.size(); auto [ptr, error] = std::from_chars(begin, end, parsed); if (error != std::errc{} || ptr != end || parsed > std::numeric_limits::max()) { return ligo::detail::fail(ligo::detail::error_invalid_argument, "endpoint port is invalid"); @@ -313,7 +315,7 @@ auto ligo::detail::parse_server_endpoint_text(std::string_view text) -> std::exp return ligo::detail::parse_endpoint_text(text, 0); } -auto ligo::detail::start_tcp_acceptor(boost::asio::ip::tcp::acceptor& acceptor, std::string const& host, std::uint16_t port) -> std::expected { +auto ligo::detail::start_tcp_acceptor(boost::asio::ip::tcp::acceptor &acceptor, std::string const &host, std::uint16_t port) -> std::expected { auto close_on_failure = [&acceptor] { auto ignored = boost::system::error_code{}; acceptor.close(ignored); @@ -361,7 +363,7 @@ auto ligo::detail::start_tcp_acceptor(boost::asio::ip::tcp::acceptor& acceptor, return ligo::detail::fail(ligo::detail::error_unavailable, error.message()); } auto last_error = ligo::detail::unavailable("no TCP bind endpoint resolved"); - for (auto const& endpoint : endpoints) { + for (auto const &endpoint : endpoints) { auto selected = bind_endpoint(endpoint.endpoint()); if (selected) { return selected; @@ -371,12 +373,12 @@ auto ligo::detail::start_tcp_acceptor(boost::asio::ip::tcp::acceptor& acceptor, return ligo::detail::fail(last_error); } -auto ligo::detail::resolve_tcp_endpoints(boost::asio::any_io_executor executor, std::string const& host, std::uint16_t port, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { +auto ligo::detail::resolve_tcp_endpoints(boost::asio::any_io_executor executor, std::string const &host, std::uint16_t port, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { auto resolver = std::make_shared(executor); auto timer = std::make_shared(executor); auto timed_out = std::make_shared>(false); timer->expires_after(timeout); - timer->async_wait([resolver, timer, timed_out](boost::system::error_code const& error) { + timer->async_wait([resolver, timer, timed_out](boost::system::error_code const &error) { if (!error) { timed_out->store(true, std::memory_order_release); resolver->cancel(); @@ -394,10 +396,10 @@ auto ligo::detail::resolve_tcp_endpoints(boost::asio::any_io_executor executor, co_return modulus::success(std::move(endpoints)); } -auto ligo::detail::call_handler(ligo::service_router const& router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable> { +auto ligo::detail::call_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable> { co_return co_await router.call(std::move(context), std::move(payload)); } -auto ligo::detail::call_response_handler(ligo::service_router const& router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable> { +auto ligo::detail::call_response_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable> { co_return co_await router.call_response(std::move(context), std::move(payload)); } diff --git a/src/http.cpp b/src/http.cpp index 479fabf..59306b1 100755 --- a/src/http.cpp +++ b/src/http.cpp @@ -43,6 +43,7 @@ #include #include + namespace { struct http_server_state { @@ -80,7 +81,7 @@ auto http_status(std::int32_t code) -> boost::beast::http::status { return boost::beast::http::status::internal_server_error; } -auto http_body_limit_exceeded(boost::system::error_code const& error) -> std::bool_t { +auto http_body_limit_exceeded(boost::system::error_code const &error) -> std::bool_t { return error == boost::beast::http::error::body_limit; } @@ -104,7 +105,7 @@ auto http_verb(ligo::http::method method) -> std::expected(ligo::detail::error_invalid_argument, "HTTP method is invalid"); } -auto should_send_json_body(ligo::http::request const& request) -> std::bool_t { +auto should_send_json_body(ligo::http::request const &request) -> std::bool_t { if (request.method != ligo::http::method::GET) { return true; } @@ -114,7 +115,7 @@ auto should_send_json_body(ligo::http::request const& request) -> std::bool_t { return !request.payload.is_object() || !request.payload.as_object().empty(); } -auto host_header(std::string const& host, std::uint16_t port) -> std::string { +auto host_header(std::string const &host, std::uint16_t port) -> std::string { auto value = std::string{}; if (!host.empty() && host.front() == '[' && host.back() == ']') { value = host; @@ -128,30 +129,30 @@ auto host_header(std::string const& host, std::uint16_t port) -> std::string { return value; } -auto remote_peer(boost::beast::tcp_stream& stream) -> std::string { +auto remote_peer(boost::beast::tcp_stream &stream) -> std::string { auto endpoint_error = boost::system::error_code{}; auto remote_endpoint = stream.socket().remote_endpoint(endpoint_error); return endpoint_error ? std::string{} : remote_endpoint.address().to_string(); } -auto remote_peer(boost::asio::ssl::stream& stream) -> std::string { +auto remote_peer(boost::asio::ssl::stream &stream) -> std::string { auto endpoint_error = boost::system::error_code{}; auto remote_endpoint = stream.next_layer().remote_endpoint(endpoint_error); return endpoint_error ? std::string{} : remote_endpoint.address().to_string(); } -auto close_http_session(boost::beast::tcp_stream& stream, std::chrono::milliseconds) -> boost::asio::awaitable { +auto close_http_session(boost::beast::tcp_stream &stream, std::chrono::milliseconds) -> boost::asio::awaitable { auto ignored = boost::beast::error_code{}; stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ignored); co_return; } -auto close_http_session(boost::asio::ssl::stream& stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable { +auto close_http_session(boost::asio::ssl::stream &stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable { static_cast(co_await ligo::detail::async_tls_shutdown(stream, timeout, "HTTP TLS shutdown timed out")); } template -auto write_http_failure_response(STREAM& stream, modulus::error status, std::chrono::milliseconds timeout, std::function const& on_error) -> boost::asio::awaitable { +auto write_http_failure_response(STREAM &stream, modulus::error status, std::chrono::milliseconds timeout, std::function const &on_error) -> boost::asio::awaitable { auto response = boost::beast::http::response{}; response.version(11); response.set(boost::beast::http::field::content_type, "application/json"); @@ -170,7 +171,7 @@ auto write_http_failure_response(STREAM& stream, modulus::error status, std::chr } template -auto handle_session(STREAM& stream, std::shared_ptr router, ligo::http::server_options options) -> boost::asio::awaitable { +auto handle_session(STREAM &stream, std::shared_ptr router, ligo::http::server_options options) -> boost::asio::awaitable { assert(router != nullptr); auto buffer = boost::beast::flat_buffer{}; auto parser = boost::beast::http::request_parser{}; @@ -287,7 +288,7 @@ auto accept_tls_loop(std::shared_ptr state) -> boost::asio::a } } -auto http_state(ligo::detail::state_handle const& state) -> std::shared_ptr { +auto http_state(ligo::detail::state_handle const &state) -> std::shared_ptr { return state.as(); } @@ -295,7 +296,7 @@ auto uninitialized_http_server() -> std::expected { return ligo::detail::fail_void(ligo::detail::unavailable("HTTP server is not initialized")); } -auto start_http_server(std::shared_ptr const& state) -> std::expected { +auto start_http_server(std::shared_ptr const &state) -> std::expected { assert(!state || state->acceptor != nullptr); assert(!state || state->router != nullptr); if (!state) { @@ -363,7 +364,7 @@ auto stop_http_server(std::shared_ptr state) -> void { }); } -auto stop_http_server_now(std::shared_ptr const& state) -> void { +auto stop_http_server_now(std::shared_ptr const &state) -> void { auto lock = std::scoped_lock{state->lifecycle_mutex}; if (state->stopped.exchange(true)) { return; @@ -403,14 +404,14 @@ auto async_stop_http_server(std::shared_ptr state, std::chron co_return co_await state->tls_sessions->wait_empty(timeout); } -auto selected_http_port(std::shared_ptr const& state) -> std::uint16_t { +auto selected_http_port(std::shared_ptr const &state) -> std::uint16_t { if (!state) { return 0; } return state->selected_port.load(); } -auto make_http_request_message(ligo::http::endpoint const& endpoint, ligo::http::request const& request, boost::beast::http::verb verb) -> boost::beast::http::request { +auto make_http_request_message(ligo::http::endpoint const &endpoint, ligo::http::request const &request, boost::beast::http::verb verb) -> boost::beast::http::request { auto http_request = boost::beast::http::request{ verb, request.target, @@ -426,7 +427,7 @@ auto make_http_request_message(ligo::http::endpoint const& endpoint, ligo::http: } template -auto read_http_response(STREAM& stream, std::chrono::milliseconds timeout, std::uint64_t max_body_size) -> boost::asio::awaitable> { +auto read_http_response(STREAM &stream, std::chrono::milliseconds timeout, std::uint64_t max_body_size) -> boost::asio::awaitable> { auto buffer = boost::beast::flat_buffer{}; auto parser = boost::beast::http::response_parser{}; parser.body_limit(max_body_size); @@ -544,19 +545,23 @@ auto call_http_endpoint(ligo::http::endpoint endpoint, std::shared_ptrexecutor)}, acceptor{std::make_shared(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared(std::move(router))} {} +http_server_state::http_server_state(boost::asio::any_io_executor executor, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options) + : executor{std::move(executor)}, strand{boost::asio::make_strand(this->executor)}, acceptor{std::make_shared(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared(std::move(router))} {} } -ligo::http::client::client(ligo::http::endpoint endpoint, ligo::http::client_options options) : endpoint_{std::move(endpoint)}, options_{options} {} +ligo::http::client::client(ligo::http::endpoint endpoint, ligo::http::client_options options) + : endpoint_{std::move(endpoint)}, options_{options} {} -auto ligo::http::client::call(ligo::http::request const& request) const -> boost::asio::awaitable> { +auto ligo::http::client::call(ligo::http::request const &request) const -> boost::asio::awaitable> { return call_http_endpoint(endpoint_, std::make_shared(request), options_); } -ligo::http::server::server(boost::asio::io_context& io, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options) : ligo::http::server{io.get_executor(), std::move(endpoint), std::move(router), options} {} +ligo::http::server::server(boost::asio::io_context &io, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options) + : ligo::http::server{io.get_executor(), std::move(endpoint), std::move(router), options} {} -ligo::http::server::server(boost::asio::any_io_executor executor, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options) : state_{ligo::detail::state_handle{std::make_shared(std::move(executor), std::move(endpoint), std::move(router), options)}} {} +ligo::http::server::server(boost::asio::any_io_executor executor, ligo::http::endpoint endpoint, ligo::service_router router, ligo::http::server_options options) + : state_{ligo::detail::state_handle{std::make_shared(std::move(executor), std::move(endpoint), std::move(router), options)}} {} ligo::http::server::~server() { if (auto state = http_state(state_)) { @@ -564,7 +569,7 @@ ligo::http::server::~server() { } } -auto ligo::http::server::operator=(ligo::http::server&& other) noexcept -> ligo::http::server& { +auto ligo::http::server::operator=(ligo::http::server &&other) noexcept -> ligo::http::server & { if (this != &other) { if (auto state = http_state(state_)) { stop_http_server_now(state); @@ -592,18 +597,17 @@ auto ligo::http::server::selected_port() const -> std::uint16_t { return selected_http_port(http_state(state_)); } -auto ligo::http::client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected { +auto ligo::http::client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected { auto parsed = ligo::detail::parse_client_endpoint_text(config.connect); if (!parsed) { return ligo::detail::fail(parsed.error()); } return modulus::success(ligo::http::endpoint{ .host = std::move(parsed->host), - .port = parsed->port - }); + .port = parsed->port}); } -auto ligo::http::server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected { +auto ligo::http::server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected { auto parsed = ligo::detail::parse_server_endpoint_text(config.bind); if (!parsed) { return ligo::detail::fail(parsed.error()); @@ -614,7 +618,7 @@ auto ligo::http::server_endpoint_from_config(ligo::endpoint_config const& config }); } -auto ligo::http::client_options_from_config(ligo::endpoint_config const& config) -> ligo::http::client_options { +auto ligo::http::client_options_from_config(ligo::endpoint_config const &config) -> ligo::http::client_options { return { .timeout = config.timeout, .max_body_size = config.http.max_body_size, @@ -622,7 +626,7 @@ auto ligo::http::client_options_from_config(ligo::endpoint_config const& config) }; } -auto ligo::http::server_options_from_config(ligo::endpoint_config const& config) -> ligo::http::server_options { +auto ligo::http::server_options_from_config(ligo::endpoint_config const &config) -> ligo::http::server_options { return { .timeout = config.timeout, .max_body_size = config.http.max_body_size, diff --git a/src/net.cpp b/src/net.cpp index 4a1f235..94f44f6 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -37,23 +37,23 @@ #include #include + class ligo::net::byte_stream_state { public: byte_stream_state() = default; - byte_stream_state(ligo::net::byte_stream_state const&) = delete; - byte_stream_state(ligo::net::byte_stream_state&&) noexcept = delete; + byte_stream_state(ligo::net::byte_stream_state const &) = delete; + byte_stream_state(ligo::net::byte_stream_state &&) noexcept = delete; virtual ~byte_stream_state() = default; - auto operator=(ligo::net::byte_stream_state const&) -> ligo::net::byte_stream_state& = delete; - auto operator=(ligo::net::byte_stream_state&&) noexcept -> ligo::net::byte_stream_state& = delete; + auto operator=(ligo::net::byte_stream_state const &) -> ligo::net::byte_stream_state & = delete; + auto operator=(ligo::net::byte_stream_state &&) noexcept -> ligo::net::byte_stream_state & = delete; virtual auto async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> = 0; virtual auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> = 0; virtual auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> = 0; virtual auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable> = 0; - virtual auto close(boost::system::error_code& error) -> void = 0; + virtual auto close(boost::system::error_code &error) -> void = 0; virtual auto is_open() const -> std::bool_t = 0; }; - namespace { struct net_listener_state { @@ -71,7 +71,7 @@ public: auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> override; auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> override; auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable> override; - auto close(boost::system::error_code& error) -> void override; + auto close(boost::system::error_code &error) -> void override; auto is_open() const -> std::bool_t override; private: std::shared_ptr socket_{}; @@ -84,18 +84,18 @@ public: auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> override; auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> override; auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable> override; - auto close(boost::system::error_code& error) -> void override; + auto close(boost::system::error_code &error) -> void override; auto is_open() const -> std::bool_t override; private: std::shared_ptr context_{}; std::unique_ptr> stream_{}; }; -auto listener_state(ligo::detail::state_handle const& state) -> std::shared_ptr { +auto listener_state(ligo::detail::state_handle const &state) -> std::shared_ptr { return state.as(); } -auto close_listener(std::shared_ptr const& state) -> void { +auto close_listener(std::shared_ptr const &state) -> void { if (!state || state->closed.exchange(true)) { return; } @@ -106,7 +106,7 @@ auto close_listener(std::shared_ptr const& state) -> void { }); } -auto validate_tls_accept_security(ligo::security_config const& security) -> std::expected { +auto validate_tls_accept_security(ligo::security_config const &security) -> std::expected { if (security.mode != ligo::security_mode::TLS) { return ligo::detail::fail_void(ligo::unsupported_security("TCP TLS accept", security.mode)); } @@ -118,7 +118,7 @@ auto validate_stream_timeout(std::chrono::milliseconds timeout) -> std::expected } template -auto read_some_from(STREAM& stream, boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { +auto read_some_from(STREAM &stream, boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { auto valid = validate_stream_timeout(timeout); if (!valid) { co_return ligo::detail::fail(valid.error()); @@ -134,7 +134,7 @@ auto read_some_from(STREAM& stream, boost::asio::mutable_buffer buffer, std::chr } template -auto write_some_to(STREAM& stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { +auto write_some_to(STREAM &stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { auto valid = validate_stream_timeout(timeout); if (!valid) { co_return ligo::detail::fail(valid.error()); @@ -150,7 +150,7 @@ auto write_some_to(STREAM& stream, boost::asio::const_buffer buffer, std::chrono } template -auto write_all_to(STREAM& stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { +auto write_all_to(STREAM &stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable> { auto valid = validate_stream_timeout(timeout); if (!valid) { co_return valid; @@ -185,7 +185,7 @@ auto accept_socket(std::shared_ptr state, std::optional(state->strand); timer->expires_after(*timeout); - timer->async_wait([state, timer, timed_out](boost::system::error_code const& error) { + timer->async_wait([state, timer, timed_out](boost::system::error_code const &error) { if (!error) { timed_out->store(true, std::memory_order_release); auto ignored = boost::system::error_code{}; @@ -207,7 +207,7 @@ auto accept_socket(std::shared_ptr state, std::optional std::expected, modulus::error> { +auto make_server_tls_context(ligo::security_config const &security) -> std::expected, modulus::error> { auto valid_security = validate_tls_accept_security(security); if (!valid_security) { return ligo::detail::fail>(valid_security.error()); @@ -227,9 +227,11 @@ auto make_server_tls_context(ligo::security_config const& security) -> std::expe return context; } -net_listener_state::net_listener_state(boost::asio::any_io_executor executor) : strand{boost::asio::make_strand(std::move(executor))}, acceptor{strand} {} +net_listener_state::net_listener_state(boost::asio::any_io_executor executor) + : strand{boost::asio::make_strand(std::move(executor))}, acceptor{strand} {} -tcp_byte_stream_state::tcp_byte_stream_state(boost::asio::ip::tcp::socket socket) : socket_{std::make_shared(std::move(socket))} {} +tcp_byte_stream_state::tcp_byte_stream_state(boost::asio::ip::tcp::socket socket) + : socket_{std::make_shared(std::move(socket))} {} auto tcp_byte_stream_state::async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { if (!is_open()) { @@ -272,7 +274,7 @@ auto tcp_byte_stream_state::async_shutdown(std::chrono::milliseconds timeout) -> co_return std::expected{}; } -auto tcp_byte_stream_state::close(boost::system::error_code& error) -> void { +auto tcp_byte_stream_state::close(boost::system::error_code &error) -> void { if (socket_) { socket_->close(error); } @@ -282,7 +284,8 @@ auto tcp_byte_stream_state::is_open() const -> std::bool_t { return socket_ && socket_->is_open(); } -tls_byte_stream_state::tls_byte_stream_state(ligo::tcp::tls_socket::released_stream released) : context_{std::move(released.context)}, stream_{std::make_unique>(std::move(released.stream))} {} +tls_byte_stream_state::tls_byte_stream_state(ligo::tcp::tls_socket::released_stream released) + : context_{std::move(released.context)}, stream_{std::make_unique>(std::move(released.stream))} {} auto tls_byte_stream_state::async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { if (!is_open()) { @@ -315,7 +318,7 @@ auto tls_byte_stream_state::async_shutdown(std::chrono::milliseconds timeout) -> co_return status; } -auto tls_byte_stream_state::close(boost::system::error_code& error) -> void { +auto tls_byte_stream_state::close(boost::system::error_code &error) -> void { if (stream_) { stream_->lowest_layer().close(error); } @@ -332,7 +335,7 @@ ligo::net::byte_stream::~byte_stream() { close(error); } -auto ligo::net::byte_stream::operator=(ligo::net::byte_stream&& other) noexcept -> ligo::net::byte_stream& { +auto ligo::net::byte_stream::operator=(ligo::net::byte_stream &&other) noexcept -> ligo::net::byte_stream & { if (this != &other) { auto error = boost::system::error_code{}; close(error); @@ -389,7 +392,7 @@ auto ligo::net::byte_stream::async_shutdown(std::chrono::milliseconds timeout) - co_return co_await state_->async_shutdown(timeout); } -auto ligo::net::byte_stream::close(boost::system::error_code& error) -> void { +auto ligo::net::byte_stream::close(boost::system::error_code &error) -> void { if (state_) { state_->close(error); } @@ -402,13 +405,14 @@ auto ligo::net::byte_stream::is_open() const -> std::bool_t { return false; } -ligo::net::byte_stream::byte_stream(std::shared_ptr state) : state_{std::move(state)} {} +ligo::net::byte_stream::byte_stream(std::shared_ptr state) + : state_{std::move(state)} {} ligo::net::listener::~listener() { close(); } -auto ligo::net::listener::operator=(ligo::net::listener&& other) noexcept -> ligo::net::listener& { +auto ligo::net::listener::operator=(ligo::net::listener &&other) noexcept -> ligo::net::listener & { if (this != &other) { close(); state_ = std::move(other.state_); @@ -487,7 +491,8 @@ auto ligo::net::listener::close() -> void { close_listener(listener_state(state_)); } -ligo::net::listener::listener(ligo::detail::state_handle state) : state_{std::move(state)} {} +ligo::net::listener::listener(ligo::detail::state_handle state) + : state_{std::move(state)} {} auto ligo::net::connect_tcp(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options) -> boost::asio::awaitable> { co_return co_await ligo::tcp::connect(std::move(executor), std::move(endpoint), options); @@ -497,7 +502,7 @@ auto ligo::net::connect(boost::asio::any_io_executor executor, ligo::tcp::endpoi co_return co_await ligo::net::connect_tcp(std::move(executor), std::move(endpoint), options); } -auto ligo::net::connect(boost::asio::any_io_executor executor, ligo::endpoint_config const& config) -> boost::asio::awaitable> { +auto ligo::net::connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable> { co_return co_await ligo::tcp::connect(std::move(executor), config); } diff --git a/src/security.cpp b/src/security.cpp index e44e5c5..644363b 100644 --- a/src/security.cpp +++ b/src/security.cpp @@ -19,6 +19,7 @@ #include #include + namespace { auto ssl_failure(std::int32_t code, std::string message) -> modulus::error { @@ -34,7 +35,7 @@ auto ssl_failure(std::string message) -> modulus::error { return ssl_failure(ligo::detail::error_unavailable, std::move(message)); } -auto apply_verify_mode(boost::asio::ssl::context& context, ligo::verify_mode verify) -> std::expected { +auto apply_verify_mode(boost::asio::ssl::context &context, ligo::verify_mode verify) -> std::expected { auto const mode = verify == ligo::verify_mode::PEER || verify == ligo::verify_mode::DEFAULTED ? boost::asio::ssl::verify_peer : boost::asio::ssl::verify_none; auto error = boost::system::error_code{}; context.set_verify_mode(mode, error); @@ -44,7 +45,7 @@ auto apply_verify_mode(boost::asio::ssl::context& context, ligo::verify_mode ver return {}; } -auto apply_server_verify_mode(boost::asio::ssl::context& context, ligo::verify_mode verify) -> std::expected { +auto apply_server_verify_mode(boost::asio::ssl::context &context, ligo::verify_mode verify) -> std::expected { auto const mode = verify == ligo::verify_mode::PEER ? boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert : boost::asio::ssl::verify_none; auto error = boost::system::error_code{}; context.set_verify_mode(mode, error); @@ -54,7 +55,7 @@ auto apply_server_verify_mode(boost::asio::ssl::context& context, ligo::verify_m return {}; } -auto load_verify_paths(boost::asio::ssl::context& context, ligo::security_config const& config) -> std::expected { +auto load_verify_paths(boost::asio::ssl::context &context, ligo::security_config const &config) -> std::expected { if (config.verify == ligo::verify_mode::NONE) { return {}; } @@ -70,7 +71,7 @@ auto load_verify_paths(boost::asio::ssl::context& context, ligo::security_config return {}; } -auto load_server_identity(boost::asio::ssl::context& context, ligo::security_config const& config) -> std::expected { +auto load_server_identity(boost::asio::ssl::context &context, ligo::security_config const &config) -> std::expected { if (config.certificate_chain_file.empty() && config.private_key_file.empty()) { return {}; } @@ -92,7 +93,7 @@ auto load_server_identity(boost::asio::ssl::context& context, ligo::security_con return {}; } -auto make_context(boost::asio::ssl::context::method method, ligo::security_config const& config, std::bool_t server) -> std::expected, modulus::error> { +auto make_context(boost::asio::ssl::context::method method, ligo::security_config const &config, std::bool_t server) -> std::expected, modulus::error> { if (config.mode == ligo::security_mode::DTLS) { return ligo::detail::fail>(ligo::detail::error_invalid_argument, "DTLS config cannot create a TLS context"); } @@ -154,19 +155,19 @@ auto make_context(boost::asio::ssl::context::method method, ligo::security_confi } -auto ligo::make_tls_client_context(ligo::security_config const& config) -> std::expected, modulus::error> { +auto ligo::make_tls_client_context(ligo::security_config const &config) -> std::expected, modulus::error> { return make_context(boost::asio::ssl::context::tls_client, config, false); } -auto ligo::make_tls_server_context(ligo::security_config const& config) -> std::expected, modulus::error> { +auto ligo::make_tls_server_context(ligo::security_config const &config) -> std::expected, modulus::error> { return make_context(boost::asio::ssl::context::tls_server, config, true); } -auto ligo::apply_tls_client_verification(boost::asio::ssl::stream& stream, std::string const& host, ligo::security_config const& config) -> std::expected { +auto ligo::apply_tls_client_verification(boost::asio::ssl::stream &stream, std::string const &host, ligo::security_config const &config) -> std::expected { return ligo::configure_tls_client_stream(stream, host, config); } -auto ligo::configure_tls_client_stream(boost::asio::ssl::stream& stream, std::string const& host, ligo::security_config const& config) -> std::expected { +auto ligo::configure_tls_client_stream(boost::asio::ssl::stream &stream, std::string const &host, ligo::security_config const &config) -> std::expected { auto const identity = config.peer_name.empty() ? host : config.peer_name; if (!identity.empty()) { if (SSL_set_tlsext_host_name(stream.native_handle(), identity.c_str()) != 1) { @@ -195,7 +196,7 @@ auto ligo::configure_tls_client_stream(boost::asio::ssl::stream std::expected { +auto ligo::validate_tls_server_config(std::string_view protocol, ligo::security_config const &config) -> std::expected { if (config.mode != ligo::security_mode::TLS) { return {}; } @@ -211,7 +212,7 @@ auto ligo::validate_tls_server_config(std::string_view protocol, ligo::security_ return ligo::detail::fail_void(ligo::detail::error_invalid_argument, std::string{protocol} + " TLS server requires certificate chain/private key files or an SSL context"); } -auto ligo::validate_tls_server_context(std::shared_ptr const& context) -> std::expected { +auto ligo::validate_tls_server_context(std::shared_ptr const &context) -> std::expected { if (!context) { return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "TLS server requires an SSL context"); } diff --git a/src/service.cpp b/src/service.cpp index a3db541..9701acb 100755 --- a/src/service.cpp +++ b/src/service.cpp @@ -18,25 +18,26 @@ #include #include + namespace { -auto json_content_type(std::string const& value) -> std::bool_t { +auto json_content_type(std::string const &value) -> std::bool_t { return value == "application/json" || value.starts_with("application/json;"); } } -ligo::service_router::service_router(ligo::service_router const& other) { +ligo::service_router::service_router(ligo::service_router const &other) { auto lock = std::scoped_lock{other.mutex_}; handlers_ = other.handlers_; } -ligo::service_router::service_router(ligo::service_router&& other) { +ligo::service_router::service_router(ligo::service_router &&other) { auto lock = std::scoped_lock{other.mutex_}; handlers_ = std::move(other.handlers_); } -auto ligo::service_router::operator=(ligo::service_router const& other) -> ligo::service_router& { +auto ligo::service_router::operator=(ligo::service_router const &other) -> ligo::service_router & { if (this != &other) { auto lock = std::scoped_lock{ mutex_, @@ -47,7 +48,7 @@ auto ligo::service_router::operator=(ligo::service_router const& other) -> ligo: return *this; } -auto ligo::service_router::operator=(ligo::service_router&& other) -> ligo::service_router& { +auto ligo::service_router::operator=(ligo::service_router &&other) -> ligo::service_router & { if (this != &other) { auto lock = std::scoped_lock{ mutex_, @@ -109,7 +110,7 @@ auto ligo::service_router::call_response(ligo::request_context context, boost::j } try { co_return co_await (*handler)(std::move(context), std::move(payload)); - } catch (std::exception const& error) { + } catch (std::exception const &error) { co_return ligo::detail::fail(ligo::detail::error_internal, std::string{"handler failed: "} + error.what()); } catch (...) { co_return ligo::detail::fail(ligo::detail::error_internal, "handler failed"); diff --git a/src/tcp.cpp b/src/tcp.cpp index 931a675..125356a 100755 --- a/src/tcp.cpp +++ b/src/tcp.cpp @@ -46,6 +46,7 @@ #include #include + namespace { struct tcp_server_state { @@ -81,12 +82,12 @@ auto encode_size(std::uint32_t size) -> std::array { }; } -auto decode_size(std::array const& bytes) -> std::uint32_t { +auto decode_size(std::array const &bytes) -> std::uint32_t { return (static_cast(bytes[0]) << 24U) | (static_cast(bytes[1]) << 16U) | (static_cast(bytes[2]) << 8U) | static_cast(bytes[3]); } template -auto read_frame_from(S& stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { +auto read_frame_from(S &stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { auto header = std::array{}; auto header_deadline = ligo::detail::start_stream_deadline(stream, timeout); auto [header_error, header_size] = co_await boost::asio::async_read(stream, boost::asio::buffer(header), ligo::detail::deadline_token(header_deadline)); @@ -122,7 +123,7 @@ auto read_frame_from(S& stream, std::chrono::milliseconds timeout) -> boost::asi } template -auto write_frame_to(S& stream, std::string body, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { +auto write_frame_to(S &stream, std::string body, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { if (body.size() > max_frame_size) { co_return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "frame too large"); } @@ -148,11 +149,11 @@ auto write_frame_to(S& stream, std::string body, std::chrono::milliseconds timeo co_return std::expected{}; } -auto parse_tcp_request(boost::json::value const& value) -> std::expected { +auto parse_tcp_request(boost::json::value const &value) -> std::expected { if (!value.is_object()) { return ligo::detail::fail(ligo::detail::error_invalid_argument, "TCP request must be an object"); } - auto const& object = value.as_object(); + auto const &object = value.as_object(); auto route = object.find("route"); auto payload = object.find("payload"); if (route == object.end() || !route->value().is_string() || payload == object.end()) { @@ -164,7 +165,7 @@ auto parse_tcp_request(boost::json::value const& value) -> std::expected std::expected { +auto serialize_tcp_request(ligo::tcp::request const &request) -> std::expected { auto envelope = boost::json::object{}; envelope["route"] = request.route; envelope["payload"] = request.payload; @@ -175,20 +176,20 @@ auto serialize_tcp_request(ligo::tcp::request const& request) -> std::expected std::string { +auto remote_peer(boost::beast::tcp_stream &stream) -> std::string { auto endpoint_error = boost::system::error_code{}; auto remote_endpoint = stream.socket().remote_endpoint(endpoint_error); return endpoint_error ? std::string{} : remote_endpoint.address().to_string(); } -auto remote_peer(boost::asio::ssl::stream& stream) -> std::string { +auto remote_peer(boost::asio::ssl::stream &stream) -> std::string { auto endpoint_error = boost::system::error_code{}; auto remote_endpoint = stream.next_layer().remote_endpoint(endpoint_error); return endpoint_error ? std::string{} : remote_endpoint.address().to_string(); } template -auto handle_session(STREAM& stream, std::shared_ptr router, ligo::tcp::server_options options) -> boost::asio::awaitable { +auto handle_session(STREAM &stream, std::shared_ptr router, ligo::tcp::server_options options) -> boost::asio::awaitable { assert(router != nullptr); auto request_value = co_await read_frame_from(stream, options.timeout); if (!request_value) { @@ -273,7 +274,7 @@ auto accept_tls_loop(std::shared_ptr state) -> boost::asio::aw } } -auto tcp_state(ligo::detail::state_handle const& state) -> std::shared_ptr { +auto tcp_state(ligo::detail::state_handle const &state) -> std::shared_ptr { return state.as(); } @@ -281,7 +282,7 @@ auto uninitialized_tcp_server() -> std::expected { return ligo::detail::fail_void(ligo::detail::unavailable("TCP server is not initialized")); } -auto start_tcp_server(std::shared_ptr const& state) -> std::expected { +auto start_tcp_server(std::shared_ptr const &state) -> std::expected { assert(!state || state->acceptor != nullptr); assert(!state || state->router != nullptr); if (!state) { @@ -349,7 +350,7 @@ auto stop_tcp_server(std::shared_ptr state) -> void { }); } -auto stop_tcp_server_now(std::shared_ptr const& state) -> void { +auto stop_tcp_server_now(std::shared_ptr const &state) -> void { auto lock = std::scoped_lock{state->lifecycle_mutex}; if (state->stopped.exchange(true)) { return; @@ -389,7 +390,7 @@ auto async_stop_tcp_server(std::shared_ptr state, std::chrono: co_return co_await state->tls_sessions->wait_empty(timeout); } -auto selected_tcp_port(std::shared_ptr const& state) -> std::uint16_t { +auto selected_tcp_port(std::shared_ptr const &state) -> std::uint16_t { if (!state) { return 0; } @@ -489,20 +490,23 @@ auto connect_tcp_socket(boost::asio::any_io_executor executor, ligo::tcp::endpoi co_return modulus::success(ligo::tcp::socket_handle{stream.release_socket()}); } -auto validate_tls_connect_security(ligo::security_config const& security) -> std::expected { +auto validate_tls_connect_security(ligo::security_config const &security) -> std::expected { if (security.mode == ligo::security_mode::TLS) { return {}; } return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "TLS connect requires TLS security mode"); } -tcp_server_state::tcp_server_state(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options) : executor{std::move(executor)}, strand{boost::asio::make_strand(this->executor)}, acceptor{std::make_shared(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared(std::move(router))} {} +tcp_server_state::tcp_server_state(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options) + : executor{std::move(executor)}, strand{boost::asio::make_strand(this->executor)}, acceptor{std::make_shared(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared(std::move(router))} {} } -ligo::tcp::socket_handle::socket_handle(boost::asio::ip::tcp::socket socket) : socket_{std::make_shared(std::move(socket))} {} +ligo::tcp::socket_handle::socket_handle(boost::asio::ip::tcp::socket socket) + : socket_{std::make_shared(std::move(socket))} {} -ligo::tcp::socket_handle::socket_handle(std::shared_ptr socket) : socket_{std::move(socket)} {} +ligo::tcp::socket_handle::socket_handle(std::shared_ptr socket) + : socket_{std::move(socket)} {} auto ligo::tcp::socket_handle::socket() -> std::expected, modulus::error> { if (!socket_) { @@ -522,7 +526,7 @@ auto ligo::tcp::socket_handle::is_open() const -> std::bool_t { return socket_ && socket_->is_open(); } -auto ligo::tcp::socket_handle::close(boost::system::error_code& error) -> void { +auto ligo::tcp::socket_handle::close(boost::system::error_code &error) -> void { if (socket_) { socket_->close(error); } @@ -540,7 +544,8 @@ auto ligo::tcp::socket_handle::release_socket() -> std::expected context, boost::asio::ip::tcp::socket socket) : context_{std::move(context)} { +ligo::tcp::tls_socket::tls_socket(std::shared_ptr context, boost::asio::ip::tcp::socket socket) + : context_{std::move(context)} { if (context_) { stream_ = std::make_unique>(std::move(socket), *context_); } @@ -578,7 +583,7 @@ auto ligo::tcp::tls_socket::is_open() const -> std::bool_t { return stream_ && stream_->lowest_layer().is_open(); } -auto ligo::tcp::tls_socket::close(boost::system::error_code& error) -> void { +auto ligo::tcp::tls_socket::close(boost::system::error_code &error) -> void { if (stream_) { stream_->lowest_layer().close(error); } @@ -597,9 +602,10 @@ auto ligo::tcp::tls_socket::release_stream() -> std::expected boost::asio::awaitable> { +auto ligo::tcp::client::call(ligo::tcp::request const &request) const -> boost::asio::awaitable> { auto body = serialize_tcp_request(request); if (!body) { return failed_tcp_call(body.error()); @@ -607,9 +613,11 @@ auto ligo::tcp::client::call(ligo::tcp::request const& request) const -> boost:: return call_tcp_endpoint(endpoint_, std::make_shared(std::move(*body)), options_); } -ligo::tcp::server::server(boost::asio::io_context& io, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options) : ligo::tcp::server{io.get_executor(), std::move(endpoint), std::move(router), options} {} +ligo::tcp::server::server(boost::asio::io_context &io, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options) + : ligo::tcp::server{io.get_executor(), std::move(endpoint), std::move(router), options} {} -ligo::tcp::server::server(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options) : state_{ligo::detail::state_handle{std::make_shared(std::move(executor), std::move(endpoint), std::move(router), options)}} {} +ligo::tcp::server::server(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::service_router router, ligo::tcp::server_options options) + : state_{ligo::detail::state_handle{std::make_shared(std::move(executor), std::move(endpoint), std::move(router), options)}} {} ligo::tcp::server::~server() { if (auto state = tcp_state(state_)) { @@ -617,7 +625,7 @@ ligo::tcp::server::~server() { } } -auto ligo::tcp::server::operator=(ligo::tcp::server&& other) noexcept -> ligo::tcp::server& { +auto ligo::tcp::server::operator=(ligo::tcp::server &&other) noexcept -> ligo::tcp::server & { if (this != &other) { if (auto state = tcp_state(state_)) { stop_tcp_server_now(state); @@ -645,7 +653,7 @@ auto ligo::tcp::server::selected_port() const -> std::uint16_t { return selected_tcp_port(tcp_state(state_)); } -auto ligo::tcp::client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected { +auto ligo::tcp::client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected { auto parsed = ligo::detail::parse_client_endpoint_text(config.connect); if (!parsed) { return ligo::detail::fail(parsed.error()); @@ -656,7 +664,7 @@ auto ligo::tcp::client_endpoint_from_config(ligo::endpoint_config const& config) }); } -auto ligo::tcp::server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected { +auto ligo::tcp::server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected { auto parsed = ligo::detail::parse_server_endpoint_text(config.bind); if (!parsed) { return ligo::detail::fail(parsed.error()); @@ -667,14 +675,14 @@ auto ligo::tcp::server_endpoint_from_config(ligo::endpoint_config const& config) }); } -auto ligo::tcp::client_options_from_config(ligo::endpoint_config const& config) -> ligo::tcp::client_options { +auto ligo::tcp::client_options_from_config(ligo::endpoint_config const &config) -> ligo::tcp::client_options { return { .timeout = config.timeout, .security = config.security, }; } -auto ligo::tcp::server_options_from_config(ligo::endpoint_config const& config) -> ligo::tcp::server_options { +auto ligo::tcp::server_options_from_config(ligo::endpoint_config const &config) -> ligo::tcp::server_options { return { .timeout = config.timeout, .on_error = {}, @@ -686,7 +694,7 @@ auto ligo::tcp::connect(boost::asio::any_io_executor executor, ligo::tcp::endpoi co_return co_await connect_tcp_socket(std::move(executor), std::move(endpoint), options); } -auto ligo::tcp::connect(boost::asio::any_io_executor executor, ligo::endpoint_config const& config) -> boost::asio::awaitable> { +auto ligo::tcp::connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable> { auto endpoint = ligo::tcp::client_endpoint_from_config(config); if (!endpoint) { co_return ligo::detail::fail(endpoint.error()); diff --git a/src/udp.cpp b/src/udp.cpp index bbc395d..9c40950 100755 --- a/src/udp.cpp +++ b/src/udp.cpp @@ -48,18 +48,19 @@ #include #include + namespace { struct ssl_ctx_deleter { - auto operator()(SSL_CTX* context) const noexcept -> void; + auto operator()(SSL_CTX *context) const noexcept -> void; }; struct ssl_deleter { - auto operator()(SSL* ssl) const noexcept -> void; + auto operator()(SSL *ssl) const noexcept -> void; }; struct bio_deleter { - auto operator()(BIO* bio) const noexcept -> void; + auto operator()(BIO *bio) const noexcept -> void; }; struct dtls_state { @@ -108,11 +109,11 @@ struct reliable_channel_state { constexpr auto max_datagram_size = std::size_t{65507}; constexpr auto max_dtls_plaintext_size = std::size_t{12000}; -auto same_peer(boost::asio::ip::udp::endpoint const& left, boost::asio::ip::udp::endpoint const& right) -> std::bool_t { +auto same_peer(boost::asio::ip::udp::endpoint const &left, boost::asio::ip::udp::endpoint const &right) -> std::bool_t { return left.address() == right.address() && left.port() == right.port(); } -auto uint_member(boost::json::object const& object, std::string_view name) -> std::optional { +auto uint_member(boost::json::object const &object, std::string_view name) -> std::optional { auto found = object.find(name); if (found == object.end() || !found->value().is_number()) { return std::nullopt; @@ -126,7 +127,7 @@ auto uint_member(boost::json::object const& object, std::string_view name) -> st return found->value().is_uint64() ? found->value().as_uint64() : static_cast(found->value().as_int64()); } -auto string_member(boost::json::object const& object, std::string_view name) -> std::string { +auto string_member(boost::json::object const &object, std::string_view name) -> std::string { auto found = object.find(name); if (found == object.end() || !found->value().is_string()) { return {}; @@ -151,7 +152,7 @@ auto make_ack(std::uint64_t session_id, std::uint64_t sequence) -> std::string { return boost::json::serialize(envelope); } -auto validate_config(ligo::udp_reliability_config const& config) -> std::expected { +auto validate_config(ligo::udp_reliability_config const &config) -> std::expected { if (config.resend_interval <= std::chrono::milliseconds{0}) { return ligo::detail::fail_void(ligo::detail::invalid_argument("UDP resend_interval must be positive")); } @@ -177,7 +178,7 @@ auto dtls_failure(std::string message) -> modulus::error { return dtls_failure(ligo::detail::error_unavailable, std::move(message)); } -auto validate_security(ligo::security_config const& config, std::bool_t server) -> std::expected { +auto validate_security(ligo::security_config const &config, std::bool_t server) -> std::expected { if (config.mode == ligo::security_mode::TLS) { return ligo::detail::fail_void(ligo::unsupported_security("UDP", config.mode)); } @@ -196,7 +197,7 @@ auto validate_security(ligo::security_config const& config, std::bool_t server) return {}; } -auto load_dtls_verify_paths(SSL_CTX* context, ligo::security_config const& config) -> std::expected { +auto load_dtls_verify_paths(SSL_CTX *context, ligo::security_config const &config) -> std::expected { if (config.verify == ligo::verify_mode::NONE) { return {}; } @@ -212,7 +213,7 @@ auto load_dtls_verify_paths(SSL_CTX* context, ligo::security_config const& confi return {}; } -auto load_dtls_identity(SSL_CTX* context, ligo::security_config const& config) -> std::expected { +auto load_dtls_identity(SSL_CTX *context, ligo::security_config const &config) -> std::expected { if (config.certificate_chain_file.empty() && config.private_key_file.empty()) { return {}; } @@ -228,7 +229,7 @@ auto load_dtls_identity(SSL_CTX* context, ligo::security_config const& config) - return {}; } -auto make_dtls_state(ligo::security_config const& config, std::bool_t server) -> std::expected, modulus::error> { +auto make_dtls_state(ligo::security_config const &config, std::bool_t server) -> std::expected, modulus::error> { if (config.mode != ligo::security_mode::DTLS) { return modulus::success(std::unique_ptr{}); } @@ -265,8 +266,8 @@ auto make_dtls_state(ligo::security_config const& config, std::bool_t server) -> } } SSL_set_mtu(ssl.get(), 1200); - auto* ssl_bio = static_cast(nullptr); - auto* network_bio = static_cast(nullptr); + auto *ssl_bio = static_cast(nullptr); + auto *network_bio = static_cast(nullptr); if (BIO_new_bio_dgram_pair(&ssl_bio, 0, &network_bio, 0) != 1 || ssl_bio == nullptr || network_bio == nullptr) { BIO_free(ssl_bio); BIO_free(network_bio); @@ -287,9 +288,9 @@ auto make_dtls_state(ligo::security_config const& config, std::bool_t server) -> })); } -auto drain_dtls_output(dtls_state& state) -> std::expected, modulus::error> { +auto drain_dtls_output(dtls_state &state) -> std::expected, modulus::error> { auto output = std::vector{}; - auto* bio = state.network_bio.get(); + auto *bio = state.network_bio.get(); while (BIO_ctrl_pending(bio) > 0) { auto const pending = static_cast(BIO_ctrl_pending(bio)); auto datagram = std::string(std::min(pending, max_datagram_size), '\0'); @@ -303,18 +304,18 @@ auto drain_dtls_output(dtls_state& state) -> std::expected& target, dtls_state& state) -> std::expected { +auto append_dtls_output(std::vector &target, dtls_state &state) -> std::expected { auto drained = drain_dtls_output(state); if (!drained) { return ligo::detail::fail_void(drained.error()); } - for (auto& datagram : *drained) { + for (auto &datagram : *drained) { target.push_back(std::move(datagram)); } return {}; } -auto run_dtls_handshake(dtls_state& state, std::vector& output) -> std::expected { +auto run_dtls_handshake(dtls_state &state, std::vector &output) -> std::expected { if (state.handshake_complete) { return {}; } @@ -331,7 +332,7 @@ auto run_dtls_handshake(dtls_state& state, std::vector& output) -> return ligo::detail::fail_void(dtls_failure("UDP DTLS handshake failed")); } -auto protect_dtls_payload(reliable_channel_state& state, std::string_view plaintext) -> std::expected, modulus::error> { +auto protect_dtls_payload(reliable_channel_state &state, std::string_view plaintext) -> std::expected, modulus::error> { if (!state.dtls) { return modulus::success(std::vector{ std::string{plaintext}, @@ -362,7 +363,7 @@ auto protect_dtls_payload(reliable_channel_state& state, std::string_view plaint return modulus::success(std::move(output)); } -auto process_dtls_input(reliable_channel_state& state, std::string_view datagram) -> std::expected { +auto process_dtls_input(reliable_channel_state &state, std::string_view datagram) -> std::expected { auto processed = dtls_processed{}; if (!state.dtls) { processed.plaintext.push_back(std::string{datagram}); @@ -400,28 +401,28 @@ auto process_dtls_input(reliable_channel_state& state, std::string_view datagram return modulus::success(std::move(processed)); } -auto channel_state(ligo::detail::state_handle const& handle) -> std::shared_ptr { +auto channel_state(ligo::detail::state_handle const &handle) -> std::shared_ptr { return handle.as(); } -auto notify_waiters(std::shared_ptr const& state) -> void { +auto notify_waiters(std::shared_ptr const &state) -> void { state->notify_timer.cancel(); } -auto notify_close_waiters(std::shared_ptr const& state) -> void { +auto notify_close_waiters(std::shared_ptr const &state) -> void { state->close_timer.cancel(); } -auto notify_send_waiters(std::shared_ptr const& state) -> void { - for (auto& [_, waiter] : state->ack_waiters) { +auto notify_send_waiters(std::shared_ptr const &state) -> void { + for (auto &[_, waiter] : state->ack_waiters) { if (auto timer = waiter.lock()) { timer->cancel(); } } } -auto send_wire_datagrams(std::shared_ptr const& state, std::vector const& datagrams) -> boost::asio::awaitable> { - for (auto const& datagram : datagrams) { +auto send_wire_datagrams(std::shared_ptr const &state, std::vector const &datagrams) -> boost::asio::awaitable> { + for (auto const &datagram : datagrams) { auto [send_error, _] = co_await state->socket->async_send_to(boost::asio::buffer(datagram), state->peer, boost::asio::bind_executor(state->strand, boost::asio::as_tuple(boost::asio::use_awaitable))); if (send_error) { co_return ligo::detail::fail_void(ligo::detail::network_failure(send_error)); @@ -430,7 +431,7 @@ auto send_wire_datagrams(std::shared_ptr const& state, s co_return std::expected{}; } -auto send_ack(std::shared_ptr const& state, std::uint64_t sequence) -> boost::asio::awaitable> { +auto send_ack(std::shared_ptr const &state, std::uint64_t sequence) -> boost::asio::awaitable> { auto ack_body = make_ack(state->session_id, sequence); auto datagrams = protect_dtls_payload(*state, ack_body); if (!datagrams) { @@ -439,7 +440,7 @@ auto send_ack(std::shared_ptr const& state, std::uint64_ co_return co_await send_wire_datagrams(state, *datagrams); } -auto close_state(std::shared_ptr const& state) -> void { +auto close_state(std::shared_ptr const &state) -> void { if (!state || state->closed) { return; } @@ -487,9 +488,9 @@ auto receive_loop(std::shared_ptr state) -> boost::asio: continue; } auto processed = process_dtls_input(*state, std::string_view{ - state->receive_buffer.data(), - size, - }); + state->receive_buffer.data(), + size, + }); if (!processed) { state->receive_error = processed.error(); notify_send_waiters(state); @@ -503,13 +504,13 @@ auto receive_loop(std::shared_ptr state) -> boost::asio: notify_waiters(state); continue; } - for (auto& plaintext : processed->plaintext) { + for (auto &plaintext : processed->plaintext) { auto parse_error = boost::system::error_code{}; auto envelope = boost::json::parse(plaintext, parse_error); if (parse_error || !envelope.is_object()) { continue; } - auto const& object = envelope.as_object(); + auto const &object = envelope.as_object(); auto session = uint_member(object, "session"); auto sequence = uint_member(object, "sequence"); if (!session.has_value() || *session != state->session_id || !sequence.has_value()) { @@ -563,7 +564,7 @@ auto receive_loop(std::shared_ptr state) -> boost::asio: } } -auto ensure_receive_loop(std::shared_ptr const& state) -> void { +auto ensure_receive_loop(std::shared_ptr const &state) -> void { if (state->receive_loop_started || state->closed) { return; } @@ -571,7 +572,7 @@ auto ensure_receive_loop(std::shared_ptr const& state) - boost::asio::co_spawn(state->strand, receive_loop(state), boost::asio::detached); } -auto begin_operation(std::shared_ptr const& state) -> std::expected { +auto begin_operation(std::shared_ptr const &state) -> std::expected { if (state->closed || state->close_requested.load(std::memory_order_acquire)) { return ligo::detail::fail_void(ligo::detail::unavailable("UDP channel closed")); } @@ -580,7 +581,7 @@ auto begin_operation(std::shared_ptr const& state) -> st return {}; } -auto finish_operation(std::shared_ptr const& state) -> void { +auto finish_operation(std::shared_ptr const &state) -> void { if (state->active_operations > 0) { --state->active_operations; } @@ -593,7 +594,7 @@ auto finish_operation(std::shared_ptr const& state) -> v } } -auto finish_send(std::shared_ptr const& state, std::uint64_t sequence) -> void { +auto finish_send(std::shared_ptr const &state, std::uint64_t sequence) -> void { if (state->in_flight > 0) { --state->in_flight; } @@ -603,7 +604,7 @@ auto finish_send(std::shared_ptr const& state, std::uint finish_operation(state); } -auto udp_endpoint_from_parts(ligo::detail::endpoint_parts const& parts) -> std::expected { +auto udp_endpoint_from_parts(ligo::detail::endpoint_parts const &parts) -> std::expected { auto error = boost::system::error_code{}; auto address = boost::asio::ip::make_address(parts.host, error); if (error) { @@ -704,7 +705,6 @@ auto send_payload_on_strand(std::shared_ptr state, boost finish_send(state, sequence); co_return ligo::detail::fail_void(sent.error()); } - if (state->acked.erase(sequence) > 0) { finish_send(state, sequence); co_return std::expected{}; @@ -813,7 +813,7 @@ auto receive_message(std::shared_ptr state) -> boost::as }); } -auto local_endpoint_for(std::shared_ptr const& state) -> std::expected { +auto local_endpoint_for(std::shared_ptr const &state) -> std::expected { if (!state || !state->socket) { return ligo::detail::fail(ligo::detail::error_unavailable, "UDP channel is not initialized"); } @@ -830,7 +830,7 @@ auto close_channel(std::shared_ptr state) -> void { }); } -auto channel_drained(std::shared_ptr const& state) -> std::bool_t { +auto channel_drained(std::shared_ptr const &state) -> std::bool_t { return !state || (state->active_operations == 0 && !state->receive_loop_started); } @@ -842,7 +842,7 @@ auto async_close_channel_on_strand(std::shared_ptr state auto deadline_timer = std::make_shared(state->strand); auto timed_out = std::make_shared>(false); deadline_timer->expires_after(timeout); - deadline_timer->async_wait([state, deadline_timer, timed_out](boost::system::error_code const& error) { + deadline_timer->async_wait([state, deadline_timer, timed_out](boost::system::error_code const &error) { if (!error) { timed_out->store(true, std::memory_order_release); notify_close_waiters(state); @@ -876,7 +876,7 @@ auto async_close_channel(std::shared_ptr state, std::chr co_return co_await boost::asio::co_spawn(state->strand, async_close_channel_on_strand(state, timeout), boost::asio::use_awaitable); } -auto endpoint_from_config(ligo::endpoint_config const& config) -> std::expected { +auto endpoint_from_config(ligo::endpoint_config const &config) -> std::expected { auto local_parts = ligo::detail::parse_server_endpoint_text(config.bind); if (!local_parts) { return ligo::detail::fail(local_parts.error()); @@ -899,19 +899,20 @@ auto endpoint_from_config(ligo::endpoint_config const& config) -> std::expected< }); } -auto ssl_ctx_deleter::operator()(SSL_CTX* context) const noexcept -> void { +auto ssl_ctx_deleter::operator()(SSL_CTX *context) const noexcept -> void { SSL_CTX_free(context); } -auto ssl_deleter::operator()(SSL* ssl) const noexcept -> void { +auto ssl_deleter::operator()(SSL *ssl) const noexcept -> void { SSL_free(ssl); } -auto bio_deleter::operator()(BIO* bio) const noexcept -> void { +auto bio_deleter::operator()(BIO *bio) const noexcept -> void { BIO_free(bio); } -reliable_channel_state::reliable_channel_state(std::unique_ptr socket, boost::asio::ip::udp::endpoint local_endpoint, boost::asio::ip::udp::endpoint peer, ligo::udp_reliability_config config, ligo::security_config security, std::uint64_t session_id, std::unique_ptr dtls) : socket{std::move(socket)}, local_endpoint{std::move(local_endpoint)}, peer{std::move(peer)}, config{config}, security{std::move(security)}, dtls{std::move(dtls)}, session_id{session_id} { +reliable_channel_state::reliable_channel_state(std::unique_ptr socket, boost::asio::ip::udp::endpoint local_endpoint, boost::asio::ip::udp::endpoint peer, ligo::udp_reliability_config config, ligo::security_config security, std::uint64_t session_id, std::unique_ptr dtls) + : socket{std::move(socket)}, local_endpoint{std::move(local_endpoint)}, peer{std::move(peer)}, config{config}, security{std::move(security)}, dtls{std::move(dtls)}, session_id{session_id} { notify_timer.expires_at(std::chrono::steady_clock::time_point::max()); close_timer.expires_at(std::chrono::steady_clock::time_point::max()); } @@ -922,7 +923,7 @@ ligo::udp::client::~client() { close(); } -auto ligo::udp::client::operator=(ligo::udp::client&& other) noexcept -> ligo::udp::client& { +auto ligo::udp::client::operator=(ligo::udp::client &&other) noexcept -> ligo::udp::client & { if (this != &other) { close(); state_ = std::move(other.state_); @@ -932,15 +933,16 @@ auto ligo::udp::client::operator=(ligo::udp::client&& other) noexcept -> ligo::u auto ligo::udp::client::open(boost::asio::any_io_executor executor, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options) -> std::expected { return ligo::udp::client::bind(std::move(executor), { - .local = { - peer.protocol(), - 0, - }, - .peer = std::move(peer), - }, options); + .local = { + peer.protocol(), + 0, + }, + .peer = std::move(peer), + }, + options); } -auto ligo::udp::client::open(boost::asio::io_context& io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options) -> std::expected { +auto ligo::udp::client::open(boost::asio::io_context &io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options) -> std::expected { return ligo::udp::client::open(io.get_executor(), std::move(peer), options); } @@ -954,7 +956,7 @@ auto ligo::udp::client::bind(boost::asio::any_io_executor executor, ligo::udp::e }); } -auto ligo::udp::client::bind(boost::asio::io_context& io, ligo::udp::endpoint endpoint, ligo::udp::client_options options) -> std::expected { +auto ligo::udp::client::bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::client_options options) -> std::expected { return ligo::udp::client::bind(io.get_executor(), std::move(endpoint), options); } @@ -992,13 +994,14 @@ auto ligo::udp::client::async_close(std::chrono::milliseconds timeout) -> boost: co_return co_await async_close_channel(channel_state(state_), timeout); } -ligo::udp::client::client(ligo::detail::state_handle state) : state_{std::move(state)} {} +ligo::udp::client::client(ligo::detail::state_handle state) + : state_{std::move(state)} {} ligo::udp::server::~server() { close(); } -auto ligo::udp::server::operator=(ligo::udp::server&& other) noexcept -> ligo::udp::server& { +auto ligo::udp::server::operator=(ligo::udp::server &&other) noexcept -> ligo::udp::server & { if (this != &other) { close(); state_ = std::move(other.state_); @@ -1016,7 +1019,7 @@ auto ligo::udp::server::bind(boost::asio::any_io_executor executor, ligo::udp::e }); } -auto ligo::udp::server::bind(boost::asio::io_context& io, ligo::udp::endpoint endpoint, ligo::udp::server_options options) -> std::expected { +auto ligo::udp::server::bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::server_options options) -> std::expected { return ligo::udp::server::bind(io.get_executor(), std::move(endpoint), options); } @@ -1054,24 +1057,25 @@ auto ligo::udp::server::async_close(std::chrono::milliseconds timeout) -> boost: co_return co_await async_close_channel(channel_state(state_), timeout); } -ligo::udp::server::server(ligo::detail::state_handle state) : state_{std::move(state)} {} +ligo::udp::server::server(ligo::detail::state_handle state) + : state_{std::move(state)} {} -auto ligo::udp::client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected { +auto ligo::udp::client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected { return endpoint_from_config(config); } -auto ligo::udp::server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected { +auto ligo::udp::server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected { return endpoint_from_config(config); } -auto ligo::udp::client_options_from_config(ligo::endpoint_config const& config) -> ligo::udp::client_options { +auto ligo::udp::client_options_from_config(ligo::endpoint_config const &config) -> ligo::udp::client_options { return { .reliability = config.udp, .security = config.security, }; } -auto ligo::udp::server_options_from_config(ligo::endpoint_config const& config) -> ligo::udp::server_options { +auto ligo::udp::server_options_from_config(ligo::endpoint_config const &config) -> ligo::udp::server_options { return { .reliability = config.udp, .security = config.security, diff --git a/tests/test.cpp b/tests/test.cpp index 9062eda..91003b0 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -45,6 +45,7 @@ #include + BOOST_AUTO_TEST_CASE(ligo_asserts_follow_build_type) { #if defined(LIGO_EXPECT_NDEBUG) && !defined(NDEBUG) BOOST_FAIL("release-style builds must define NDEBUG"); @@ -54,14 +55,13 @@ BOOST_AUTO_TEST_CASE(ligo_asserts_follow_build_type) { #endif } - namespace { -auto test_network_failure(boost::system::error_code const& error) -> modulus::error { +auto test_network_failure(boost::system::error_code const &error) -> modulus::error { return ligo::detail::make_error(ligo::detail::error_unavailable, error.message()); } -auto run_two_threads(boost::asio::io_context& io) -> void { +auto run_two_threads(boost::asio::io_context &io) -> void { auto first = std::thread{[&] { io.run(); }}; @@ -72,7 +72,7 @@ auto run_two_threads(boost::asio::io_context& io) -> void { second.join(); } -auto start_io_threads(boost::asio::io_context& io) -> std::vector { +auto start_io_threads(boost::asio::io_context &io) -> std::vector { auto threads = std::vector{}; threads.emplace_back([&] { io.run(); @@ -83,8 +83,8 @@ auto start_io_threads(boost::asio::io_context& io) -> std::vector { return threads; } -auto join_io_threads(std::vector& threads) -> void { - for (auto& thread : threads) { +auto join_io_threads(std::vector &threads) -> void { + for (auto &thread : threads) { thread.join(); } } @@ -239,7 +239,7 @@ auto test_dtls_server_verify_client_config() -> ligo::security_config { }; } -auto http_client_call(std::string host, std::uint16_t port, ligo::http::request const& request, ligo::http::client_options options = {}) -> boost::asio::awaitable> { +auto http_client_call(std::string host, std::uint16_t port, ligo::http::request const &request, ligo::http::client_options options = {}) -> boost::asio::awaitable> { auto client = ligo::http::client{ { .host = std::move(host), @@ -250,21 +250,21 @@ auto http_client_call(std::string host, std::uint16_t port, ligo::http::request return client.call(request); } -auto http_client_call_selected(ligo::http::server& server, ligo::http::request const& request, ligo::http::client_options options = {}) -> boost::asio::awaitable> { +auto http_client_call_selected(ligo::http::server &server, ligo::http::request const &request, ligo::http::client_options options = {}) -> boost::asio::awaitable> { return http_client_call("127.0.0.1", server.selected_port(), request, options); } -auto http_client_call_selected_and_stop_impl(ligo::http::server& server, std::shared_ptr request, ligo::http::client_options options) -> boost::asio::awaitable> { +auto http_client_call_selected_and_stop_impl(ligo::http::server &server, std::shared_ptr request, ligo::http::client_options options) -> boost::asio::awaitable> { auto result = co_await http_client_call_selected(server, *request, options); server.stop(); co_return result; } -auto http_client_call_selected_and_stop(ligo::http::server& server, ligo::http::request const& request, ligo::http::client_options options = {}) -> boost::asio::awaitable> { +auto http_client_call_selected_and_stop(ligo::http::server &server, ligo::http::request const &request, ligo::http::client_options options = {}) -> boost::asio::awaitable> { return http_client_call_selected_and_stop_impl(server, std::make_shared(request), options); } -auto http_async_stop_after(ligo::http::server& server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { +auto http_async_stop_after(ligo::http::server &server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { auto timer = boost::asio::steady_timer{co_await boost::asio::this_coro::executor}; timer.expires_after(delay); co_await timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable)); @@ -315,7 +315,7 @@ auto raw_http_post(std::uint16_t port, std::string target, std::string body) -> co_return modulus::success(std::move(value)); } -auto raw_http_post_selected_and_stop(ligo::http::server& server, std::string target, std::string body) -> boost::asio::awaitable> { +auto raw_http_post_selected_and_stop(ligo::http::server &server, std::string target, std::string body) -> boost::asio::awaitable> { auto result = co_await raw_http_post(server.selected_port(), std::move(target), std::move(body)); server.stop(); co_return result; @@ -357,13 +357,13 @@ auto raw_http_get(std::uint16_t port, std::string target) -> boost::asio::awaita co_return modulus::success(std::move(response)); } -auto raw_http_get_selected_and_stop(ligo::http::server& server, std::string target) -> boost::asio::awaitable, modulus::error>> { +auto raw_http_get_selected_and_stop(ligo::http::server &server, std::string target) -> boost::asio::awaitable, modulus::error>> { auto result = co_await raw_http_get(server.selected_port(), std::move(target)); server.stop(); co_return result; } -auto tcp_client_call(std::string host, std::uint16_t port, ligo::tcp::request const& request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable> { +auto tcp_client_call(std::string host, std::uint16_t port, ligo::tcp::request const &request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable> { auto client = ligo::tcp::client{ { .host = std::move(host), @@ -374,21 +374,21 @@ auto tcp_client_call(std::string host, std::uint16_t port, ligo::tcp::request co return client.call(request); } -auto tcp_client_call_selected(ligo::tcp::server& server, ligo::tcp::request const& request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable> { +auto tcp_client_call_selected(ligo::tcp::server &server, ligo::tcp::request const &request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable> { return tcp_client_call("127.0.0.1", server.selected_port(), request, options); } -auto tcp_client_call_selected_and_stop_impl(ligo::tcp::server& server, std::shared_ptr request, ligo::tcp::client_options options) -> boost::asio::awaitable> { +auto tcp_client_call_selected_and_stop_impl(ligo::tcp::server &server, std::shared_ptr request, ligo::tcp::client_options options) -> boost::asio::awaitable> { auto result = co_await tcp_client_call_selected(server, *request, options); server.stop(); co_return result; } -auto tcp_client_call_selected_and_stop(ligo::tcp::server& server, ligo::tcp::request const& request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable> { +auto tcp_client_call_selected_and_stop(ligo::tcp::server &server, ligo::tcp::request const &request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable> { return tcp_client_call_selected_and_stop_impl(server, std::make_shared(request), options); } -auto tcp_async_stop_after(ligo::tcp::server& server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { +auto tcp_async_stop_after(ligo::tcp::server &server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable> { auto timer = boost::asio::steady_timer{co_await boost::asio::this_coro::executor}; timer.expires_after(delay); co_await timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable)); @@ -405,31 +405,32 @@ auto accept_and_hold(std::shared_ptr acceptor, s co_await timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable)); } -auto make_udp_socket(boost::asio::io_context& io) -> std::unique_ptr { +auto make_udp_socket(boost::asio::io_context &io) -> std::unique_ptr { return std::make_unique(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }); + boost::asio::ip::udp::v4(), + 0, + }); } auto udp_client_adopt(std::unique_ptr socket, boost::asio::ip::udp::endpoint peer, ligo::udp_reliability_config config = {}, std::uint64_t session_id = 1) -> std::expected { return ligo::udp::client::adopt(std::move(socket), std::move(peer), { - .reliability = config, - .session_id = session_id, - }); + .reliability = config, + .session_id = session_id, + }); } -auto udp_client_bind(boost::asio::io_context& io, boost::asio::ip::udp::endpoint local, boost::asio::ip::udp::endpoint peer, ligo::udp_reliability_config config = {}, std::uint64_t session_id = 1) -> std::expected { +auto udp_client_bind(boost::asio::io_context &io, boost::asio::ip::udp::endpoint local, boost::asio::ip::udp::endpoint peer, ligo::udp_reliability_config config = {}, std::uint64_t session_id = 1) -> std::expected { return ligo::udp::client::bind(io, { - .local = std::move(local), - .peer = std::move(peer), - }, { - .reliability = config, - .session_id = session_id, - }); + .local = std::move(local), + .peer = std::move(peer), + }, + { + .reliability = config, + .session_id = session_id, + }); } -auto config_http_tcp_calls_and_stop(ligo::http::server& http_server, ligo::tcp::server& tcp_server) -> boost::asio::awaitable> { +auto config_http_tcp_calls_and_stop(ligo::http::server &http_server, ligo::tcp::server &tcp_server) -> boost::asio::awaitable> { auto tcp_payload = boost::json::object{}; tcp_payload["ok"] = true; auto tcp_request = std::make_shared(); @@ -471,8 +472,9 @@ BOOST_AUTO_TEST_CASE(ligo_config_drives_http_tcp_and_udp_setup) { udp_server_socket->local_endpoint().port(), }; auto config_text = std::string{ - "{\"endpoints\":[", - }+ "{\"name\":\"http\",\"protocol\":\"http\",\"bind\":\"127.0.0.1:0\",\"timeout_ms\":1000}," + "{\"name\":\"tcp\",\"protocol\":\"tcp\",\"bind\":\"127.0.0.1:0\",\"timeout_ms\":1000}," + "{\"name\":\"udp-client\",\"protocol\":\"udp\",\"bind\":\"127.0.0.1:" + std::to_string(udp_client_endpoint.port()) + "\",\"connect\":\"127.0.0.1:" + std::to_string(udp_server_endpoint.port()) + "\",\"udp\":{\"resend_interval_ms\":5,\"max_in_flight\":2,\"session_timeout_ms\":1000}}," + "{\"name\":\"udp-server\",\"protocol\":\"udp\",\"bind\":\"127.0.0.1:" + std::to_string(udp_server_endpoint.port()) + "\",\"connect\":\"127.0.0.1:" + std::to_string(udp_client_endpoint.port()) + "\",\"udp\":{\"resend_interval_ms\":5,\"max_in_flight\":2,\"session_timeout_ms\":1000}}" + "]}"; + "{\"endpoints\":[", + } + + "{\"name\":\"http\",\"protocol\":\"http\",\"bind\":\"127.0.0.1:0\",\"timeout_ms\":1000}," + "{\"name\":\"tcp\",\"protocol\":\"tcp\",\"bind\":\"127.0.0.1:0\",\"timeout_ms\":1000}," + "{\"name\":\"udp-client\",\"protocol\":\"udp\",\"bind\":\"127.0.0.1:" + std::to_string(udp_client_endpoint.port()) + "\",\"connect\":\"127.0.0.1:" + std::to_string(udp_server_endpoint.port()) + "\",\"udp\":{\"resend_interval_ms\":5,\"max_in_flight\":2,\"session_timeout_ms\":1000}}," + "{\"name\":\"udp-server\",\"protocol\":\"udp\",\"bind\":\"127.0.0.1:" + std::to_string(udp_server_endpoint.port()) + "\",\"connect\":\"127.0.0.1:" + std::to_string(udp_client_endpoint.port()) + "\",\"udp\":{\"resend_interval_ms\":5,\"max_in_flight\":2,\"session_timeout_ms\":1000}}" + "]}"; auto configs = ligo::parse_endpoint_configs(boost::json::parse(config_text)); BOOST_REQUIRE(configs); BOOST_REQUIRE((configs->size()) == (4u)); @@ -625,8 +627,7 @@ BOOST_AUTO_TEST_CASE(ligo_http_post_round_trip_dispatches_json_handler) { { .target = "/echo", .payload = boost::json::parse(R"json({"ok":true})json"), - } - ), + }), boost::asio::use_future); io.run(); auto result = future.get(); @@ -690,8 +691,7 @@ BOOST_AUTO_TEST_CASE(ligo_http_tls_post_round_trip_dispatches_json_handler) { { .timeout = std::chrono::milliseconds{1000}, .security = test_tls_client_config(), - } - ), + }), boost::asio::use_future); io.run(); auto result = future.get(); @@ -764,9 +764,10 @@ BOOST_AUTO_TEST_CASE(ligo_http_get_round_trip_dispatches_method_and_route) { }; BOOST_REQUIRE(server.start()); auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, { - .method = ligo::http::method::GET, - .target = "/method", - }), boost::asio::use_future); + .method = ligo::http::method::GET, + .target = "/method", + }), + boost::asio::use_future); io.run(); auto result = future.get(); BOOST_REQUIRE(result); @@ -786,9 +787,10 @@ BOOST_AUTO_TEST_CASE(ligo_http_missing_route_returns_status) { }; BOOST_REQUIRE(server.start()); auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, { - .target = "/missing", - .payload = boost::json::object{}, - }), boost::asio::use_future); + .target = "/missing", + .payload = boost::json::object{}, + }), + boost::asio::use_future); io.run(); auto result = future.get(); BOOST_CHECK(!(result)); @@ -811,9 +813,10 @@ BOOST_AUTO_TEST_CASE(ligo_http_handler_failure_returns_status) { }; BOOST_REQUIRE(server.start()); auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, { - .target = "/boom", - .payload = boost::json::object{}, - }), boost::asio::use_future); + .target = "/boom", + .payload = boost::json::object{}, + }), + boost::asio::use_future); io.run(); auto result = future.get(); BOOST_CHECK(!(result)); @@ -895,8 +898,7 @@ BOOST_AUTO_TEST_CASE(ligo_http_client_rejects_oversized_response_body) { { .timeout = std::chrono::milliseconds{1000}, .max_body_size = 32, - } - ), + }), boost::asio::use_future); io.run(); auto result = future.get(); @@ -932,11 +934,12 @@ BOOST_AUTO_TEST_CASE(ligo_http_concurrent_client_calls_succeed) { auto payload = boost::json::object{}; payload["index"] = index; futures.push_back(boost::asio::co_spawn(io, client.call({ - .target = "/echo", - .payload = std::move(payload), - }), boost::asio::use_future)); + .target = "/echo", + .payload = std::move(payload), + }), + boost::asio::use_future)); } - for (auto& future : futures) { + for (auto &future : futures) { auto result = future.get(); BOOST_REQUIRE(result); BOOST_CHECK(result->is_object()); @@ -971,8 +974,7 @@ BOOST_AUTO_TEST_CASE(ligo_http_async_stop_cancels_active_session) { }, { .timeout = std::chrono::milliseconds{200}, - } - ), + }), boost::asio::use_future); auto stopped = boost::asio::co_spawn(io, http_async_stop_after(server, std::chrono::milliseconds{5}, std::chrono::milliseconds{200}), boost::asio::use_future); run_two_threads(io); @@ -1002,8 +1004,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_round_trip_dispatches_json_handler) { { .route = "echo", .payload = boost::json::parse(R"json({"ok":true})json"), - } - ), + }), boost::asio::use_future); io.run(); auto result = future.get(); @@ -1043,8 +1044,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_round_trip_dispatches_json_handler) { { .timeout = std::chrono::milliseconds{1000}, .security = test_tls_client_config(), - } - ), + }), boost::asio::use_future); io.run(); auto result = future.get(); @@ -1085,12 +1085,11 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_verified_peer_succeeds) { { .timeout = std::chrono::milliseconds{1000}, .security = test_tls_verified_client_config("localhost"), - } - ), + }), boost::asio::use_future); auto stopper = boost::asio::steady_timer{io}; stopper.expires_after(std::chrono::milliseconds{200}); - stopper.async_wait([&server](boost::system::error_code const&) { + stopper.async_wait([&server](boost::system::error_code const &) { server.stop(); }); io.run(); @@ -1132,12 +1131,11 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_hostname_mismatch_fails) { { .timeout = std::chrono::milliseconds{1000}, .security = test_tls_verified_client_config("wrong.local"), - } - ), + }), boost::asio::use_future); auto stopper = boost::asio::steady_timer{io}; stopper.expires_after(std::chrono::milliseconds{200}); - stopper.async_wait([&server](boost::system::error_code const&) { + stopper.async_wait([&server](boost::system::error_code const &) { server.stop(); }); io.run(); @@ -1204,9 +1202,10 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_missing_route_returns_status) { }; BOOST_REQUIRE(server.start()); auto future = boost::asio::co_spawn(io, tcp_client_call_selected_and_stop(server, { - .route = "missing", - .payload = boost::json::object{}, - }), boost::asio::use_future); + .route = "missing", + .payload = boost::json::object{}, + }), + boost::asio::use_future); io.run(); auto result = future.get(); BOOST_CHECK(!(result)); @@ -1229,9 +1228,10 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_handler_failure_returns_status) { }; BOOST_REQUIRE(server.start()); auto future = boost::asio::co_spawn(io, tcp_client_call_selected_and_stop(server, { - .route = "boom", - .payload = boost::json::object{}, - }), boost::asio::use_future); + .route = "boom", + .payload = boost::json::object{}, + }), + boost::asio::use_future); io.run(); auto result = future.get(); BOOST_CHECK(!(result)); @@ -1241,9 +1241,10 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_handler_failure_returns_status) { BOOST_AUTO_TEST_CASE(ligo_tcp_connection_refused_returns_unavailable) { auto io = boost::asio::io_context{}; auto future = boost::asio::co_spawn(io, tcp_client_call("127.0.0.1", 9, { - .route = "echo", - .payload = boost::json::object{}, - }), boost::asio::use_future); + .route = "echo", + .payload = boost::json::object{}, + }), + boost::asio::use_future); io.run(); auto result = future.get(); BOOST_CHECK(!(result)); @@ -1253,9 +1254,9 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_connection_refused_returns_unavailable) { BOOST_AUTO_TEST_CASE(ligo_tcp_stalled_peer_times_out) { auto io = boost::asio::io_context{}; auto acceptor = std::make_shared(io, boost::asio::ip::tcp::endpoint{ - boost::asio::ip::tcp::v4(), - 0, - }); + boost::asio::ip::tcp::v4(), + 0, + }); auto held_socket = std::make_shared(io); boost::asio::co_spawn(io, accept_and_hold(acceptor, held_socket, std::chrono::milliseconds{50}), boost::asio::detached); auto future = boost::asio::co_spawn( @@ -1269,8 +1270,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_stalled_peer_times_out) { }, { .timeout = std::chrono::milliseconds{20}, - } - ), + }), boost::asio::use_future); io.run(); auto result = future.get(); @@ -1306,11 +1306,12 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_concurrent_client_calls_succeed) { auto payload = boost::json::object{}; payload["index"] = index; futures.push_back(boost::asio::co_spawn(io, client.call({ - .route = "echo", - .payload = std::move(payload), - }), boost::asio::use_future)); + .route = "echo", + .payload = std::move(payload), + }), + boost::asio::use_future)); } - for (auto& future : futures) { + for (auto &future : futures) { auto result = future.get(); BOOST_REQUIRE(result); BOOST_CHECK(result->is_object()); @@ -1345,8 +1346,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_async_stop_cancels_active_session) { }, { .timeout = std::chrono::milliseconds{200}, - } - ), + }), boost::asio::use_future); auto stopped = boost::asio::co_spawn(io, tcp_async_stop_after(server, std::chrono::milliseconds{5}, std::chrono::milliseconds{200}), boost::asio::use_future); run_two_threads(io); @@ -1357,9 +1357,9 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_async_stop_cancels_active_session) { BOOST_AUTO_TEST_CASE(ligo_tcp_connect_returns_connected_socket) { auto io = boost::asio::io_context{}; auto acceptor = std::make_shared(io, boost::asio::ip::tcp::endpoint{ - boost::asio::ip::tcp::v4(), - 0, - }); + boost::asio::ip::tcp::v4(), + 0, + }); auto held_socket = std::make_shared(io); boost::asio::co_spawn(io, accept_and_hold(acceptor, held_socket, std::chrono::milliseconds{10}), boost::asio::detached); auto result = boost::asio::co_spawn( @@ -1372,8 +1372,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_connect_returns_connected_socket) { }, { .timeout = std::chrono::milliseconds{1000}, - } - ), + }), boost::asio::use_future); io.run(); auto socket = result.get(); @@ -1386,9 +1385,9 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_connect_returns_connected_socket) { BOOST_AUTO_TEST_CASE(ligo_net_connect_returns_connected_socket) { auto io = boost::asio::io_context{}; auto acceptor = std::make_shared(io, boost::asio::ip::tcp::endpoint{ - boost::asio::ip::tcp::v4(), - 0, - }); + boost::asio::ip::tcp::v4(), + 0, + }); auto held_socket = std::make_shared(io); boost::asio::co_spawn(io, accept_and_hold(acceptor, held_socket, std::chrono::milliseconds{10}), boost::asio::detached); auto result = boost::asio::co_spawn( @@ -1401,8 +1400,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_connect_returns_connected_socket) { }, { .timeout = std::chrono::milliseconds{1000}, - } - ), + }), boost::asio::use_future); io.run(); auto socket = result.get(); @@ -1415,9 +1413,9 @@ BOOST_AUTO_TEST_CASE(ligo_net_connect_returns_connected_socket) { BOOST_AUTO_TEST_CASE(ligo_net_listener_accept_returns_socket) { auto io = boost::asio::io_context{}; auto listener_result = ligo::net::listener::bind(io.get_executor(), { - .host = "127.0.0.1", - .port = 0, - }); + .host = "127.0.0.1", + .port = 0, + }); BOOST_REQUIRE(listener_result); auto listener = std::move(*listener_result); BOOST_CHECK((listener.selected_port()) != (0)); @@ -1432,8 +1430,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_listener_accept_returns_socket) { }, { .timeout = std::chrono::milliseconds{1000}, - } - ), + }), boost::asio::use_future); io.run(); auto accepted_socket = accepted.get(); @@ -1451,9 +1448,9 @@ BOOST_AUTO_TEST_CASE(ligo_net_listener_accept_returns_socket) { BOOST_AUTO_TEST_CASE(ligo_net_byte_stream_round_trips_over_tcp) { auto io = boost::asio::io_context{}; auto listener_result = ligo::net::listener::bind(io.get_executor(), { - .host = "127.0.0.1", - .port = 0, - }); + .host = "127.0.0.1", + .port = 0, + }); BOOST_REQUIRE(listener_result); auto listener = std::move(*listener_result); auto accepted = boost::asio::co_spawn(io, listener.async_accept(), boost::asio::use_future); @@ -1467,8 +1464,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_byte_stream_round_trips_over_tcp) { }, { .timeout = std::chrono::milliseconds{1000}, - } - ), + }), boost::asio::use_future); io.run(); auto accepted_socket = accepted.get(); @@ -1499,14 +1495,16 @@ BOOST_AUTO_TEST_CASE(ligo_net_byte_stream_round_trips_over_tcp) { BOOST_AUTO_TEST_CASE(ligo_net_listener_tls_accept_rejects_non_tls_security_modes) { auto io = boost::asio::io_context{}; auto listener_result = ligo::net::listener::bind(io.get_executor(), { - .host = "127.0.0.1", - .port = 0, - }); + .host = "127.0.0.1", + .port = 0, + }); BOOST_REQUIRE(listener_result); auto listener = std::move(*listener_result); auto none = boost::asio::co_spawn(io, listener.async_accept_tls_configured({ - .mode = ligo::security_mode::NONE, - }, std::chrono::milliseconds{1000}), boost::asio::use_future); + .mode = ligo::security_mode::NONE, + }, + std::chrono::milliseconds{1000}), + boost::asio::use_future); io.run(); auto result = none.get(); BOOST_CHECK(!result); @@ -1517,9 +1515,9 @@ BOOST_AUTO_TEST_CASE(ligo_net_listener_tls_accept_rejects_non_tls_security_modes BOOST_AUTO_TEST_CASE(ligo_net_listener_tls_handshake_succeeds) { auto io = boost::asio::io_context{}; auto listener_result = ligo::net::listener::bind(io.get_executor(), { - .host = "127.0.0.1", - .port = 0, - }); + .host = "127.0.0.1", + .port = 0, + }); BOOST_REQUIRE(listener_result); auto listener = std::move(*listener_result); auto accepted = boost::asio::co_spawn(io, listener.async_accept_tls_handshaken(test_tls_server_config(), std::chrono::milliseconds{1000}), boost::asio::use_future); @@ -1534,8 +1532,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_listener_tls_handshake_succeeds) { { .timeout = std::chrono::milliseconds{1000}, }, - test_tls_client_config() - ), + test_tls_client_config()), boost::asio::use_future); io.run(); auto accepted_socket = accepted.get(); @@ -1565,8 +1562,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_raw_connect_rejects_secure_modes) { .security = { .mode = ligo::security_mode::TLS, }, - } - ), + }), boost::asio::use_future); io.run(); auto result = future.get(); @@ -1589,8 +1585,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_connect_rejects_non_tls_security_modes) { }, { .mode = ligo::security_mode::NONE, - } - ), + }), boost::asio::use_future); auto dtls = boost::asio::co_spawn( io, @@ -1605,8 +1600,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_connect_rejects_non_tls_security_modes) { }, { .mode = ligo::security_mode::DTLS, - } - ), + }), boost::asio::use_future); io.run(); auto none_result = none.get(); @@ -1685,15 +1679,15 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_reliable_round_trip_succeeds) { .session_timeout = std::chrono::milliseconds{1000}, }; auto client_result = ligo::udp::client::adopt(std::move(client_socket), server_endpoint, { - .reliability = config, - .security = test_dtls_client_config(), - .session_id = 142, - }); + .reliability = config, + .security = test_dtls_client_config(), + .session_id = 142, + }); auto server_result = ligo::udp::server::adopt(std::move(server_socket), client_endpoint, { - .reliability = config, - .security = test_dtls_server_config(), - .session_id = 142, - }); + .reliability = config, + .security = test_dtls_server_config(), + .session_id = 142, + }); BOOST_REQUIRE(client_result); BOOST_REQUIRE(server_result); auto client = std::move(*client_result); @@ -1726,15 +1720,15 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_verified_peer_succeeds) { .session_timeout = std::chrono::milliseconds{1000}, }; auto client_result = ligo::udp::client::adopt(std::move(client_socket), server_endpoint, { - .reliability = config, - .security = test_dtls_verified_client_config("localhost"), - .session_id = 143, - }); + .reliability = config, + .security = test_dtls_verified_client_config("localhost"), + .session_id = 143, + }); auto server_result = ligo::udp::server::adopt(std::move(server_socket), client_endpoint, { - .reliability = config, - .security = test_dtls_server_config(), - .session_id = 143, - }); + .reliability = config, + .security = test_dtls_server_config(), + .session_id = 143, + }); BOOST_REQUIRE(client_result); BOOST_REQUIRE(server_result); auto client = std::move(*client_result); @@ -1767,15 +1761,15 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_server_peer_verification_succeeds_with_client .session_timeout = std::chrono::milliseconds{1000}, }; auto client_result = ligo::udp::client::adopt(std::move(client_socket), server_endpoint, { - .reliability = config, - .security = test_dtls_identified_client_config(), - .session_id = 145, - }); + .reliability = config, + .security = test_dtls_identified_client_config(), + .session_id = 145, + }); auto server_result = ligo::udp::server::adopt(std::move(server_socket), client_endpoint, { - .reliability = config, - .security = test_dtls_server_verify_client_config(), - .session_id = 145, - }); + .reliability = config, + .security = test_dtls_server_verify_client_config(), + .session_id = 145, + }); BOOST_REQUIRE(client_result); BOOST_REQUIRE(server_result); auto client = std::move(*client_result); @@ -1808,15 +1802,15 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_server_peer_verification_fails_without_client .session_timeout = std::chrono::milliseconds{100}, }; auto client_result = ligo::udp::client::adopt(std::move(client_socket), server_endpoint, { - .reliability = config, - .security = test_dtls_client_config(), - .session_id = 146, - }); + .reliability = config, + .security = test_dtls_client_config(), + .session_id = 146, + }); auto server_result = ligo::udp::server::adopt(std::move(server_socket), client_endpoint, { - .reliability = config, - .security = test_dtls_server_verify_client_config(), - .session_id = 146, - }); + .reliability = config, + .security = test_dtls_server_verify_client_config(), + .session_id = 146, + }); BOOST_REQUIRE(client_result); BOOST_REQUIRE(server_result); auto client = std::move(*client_result); @@ -1825,7 +1819,7 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_server_peer_verification_fails_without_client auto received = boost::asio::co_spawn(io, server.receive(), boost::asio::use_future); auto stopper = boost::asio::steady_timer{io}; stopper.expires_after(std::chrono::milliseconds{200}); - stopper.async_wait([&client, &server](boost::system::error_code const&) { + stopper.async_wait([&client, &server](boost::system::error_code const &) { client.close(); server.close(); }); @@ -1854,19 +1848,19 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_untrusted_peer_fails) { .session_timeout = std::chrono::milliseconds{100}, }; auto client_result = ligo::udp::client::adopt(std::move(client_socket), server_endpoint, { - .reliability = config, - .security = { - .mode = ligo::security_mode::DTLS, - .verify = ligo::verify_mode::PEER, - .peer_name = "localhost", - }, - .session_id = 144, - }); + .reliability = config, + .security = { + .mode = ligo::security_mode::DTLS, + .verify = ligo::verify_mode::PEER, + .peer_name = "localhost", + }, + .session_id = 144, + }); auto server_result = ligo::udp::server::adopt(std::move(server_socket), client_endpoint, { - .reliability = config, - .security = test_dtls_server_config(), - .session_id = 144, - }); + .reliability = config, + .security = test_dtls_server_config(), + .session_id = 144, + }); BOOST_REQUIRE(client_result); BOOST_REQUIRE(server_result); auto client = std::move(*client_result); @@ -1875,7 +1869,7 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_untrusted_peer_fails) { auto received = boost::asio::co_spawn(io, server.receive(), boost::asio::use_future); auto stopper = boost::asio::steady_timer{io}; stopper.expires_after(std::chrono::milliseconds{200}); - stopper.async_wait([&client, &server](boost::system::error_code const&) { + stopper.async_wait([&client, &server](boost::system::error_code const &) { client.close(); server.close(); }); @@ -1893,16 +1887,17 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_server_requires_identity) { 9, }; auto server = ligo::udp::server::bind(io.get_executor(), { - .local = { - boost::asio::ip::udp::v4(), - 0, - }, - .peer = peer, - }, { - .security = { - .mode = ligo::security_mode::DTLS, - }, - }); + .local = { + boost::asio::ip::udp::v4(), + 0, + }, + .peer = peer, + }, + { + .security = { + .mode = ligo::security_mode::DTLS, + }, + }); BOOST_CHECK(!server); BOOST_CHECK((server.error().code()) == (ligo::detail::error_invalid_argument)); } @@ -1996,9 +1991,10 @@ BOOST_AUTO_TEST_CASE(ligo_udp_wrong_session_times_out) { .session_timeout = std::chrono::milliseconds{20}, }; auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }, receiver_endpoint, config, 7); + boost::asio::ip::udp::v4(), + 0, + }, + receiver_endpoint, config, 7); BOOST_REQUIRE(channel_result); auto channel = std::move(*channel_result); auto future = boost::asio::co_spawn(io, channel.send(boost::json::object{}), boost::asio::use_future); @@ -2022,9 +2018,10 @@ BOOST_AUTO_TEST_CASE(ligo_udp_oversized_payload_returns_invalid_argument) { receiver.local_endpoint().port(), }; auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }, receiver_endpoint); + boost::asio::ip::udp::v4(), + 0, + }, + receiver_endpoint); BOOST_REQUIRE(channel_result); auto channel = std::move(*channel_result); auto payload = boost::json::value{ @@ -2051,15 +2048,16 @@ BOOST_AUTO_TEST_CASE(ligo_udp_close_wakes_pending_receive) { right_socket.local_endpoint().port(), }; auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }, right_endpoint); + boost::asio::ip::udp::v4(), + 0, + }, + right_endpoint); BOOST_REQUIRE(channel_result); auto channel = std::move(*channel_result); auto received = boost::asio::co_spawn(io, channel.receive(), boost::asio::use_future); auto timer = boost::asio::steady_timer{io}; timer.expires_after(std::chrono::milliseconds{5}); - timer.async_wait([&channel](boost::system::error_code const&) { + timer.async_wait([&channel](boost::system::error_code const &) { channel.close(); }); io.run(); @@ -2082,9 +2080,10 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_drains_pending_receive) { right_socket.local_endpoint().port(), }; auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }, right_endpoint); + boost::asio::ip::udp::v4(), + 0, + }, + right_endpoint); BOOST_REQUIRE(channel_result); auto channel = std::move(*channel_result); auto received = boost::asio::co_spawn(io, channel.receive(), boost::asio::use_future); @@ -2115,9 +2114,10 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_drains_pending_send) { .session_timeout = std::chrono::milliseconds{1000}, }; auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }, receiver_endpoint, config, 171); + boost::asio::ip::udp::v4(), + 0, + }, + receiver_endpoint, config, 171); BOOST_REQUIRE(channel_result); auto channel = std::move(*channel_result); auto sent = boost::asio::co_spawn(io, channel.send(boost::json::object{}), boost::asio::use_future); @@ -2143,9 +2143,10 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_moved_from_channel_is_ok) { right_socket.local_endpoint().port(), }; auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }, right_endpoint); + boost::asio::ip::udp::v4(), + 0, + }, + right_endpoint); BOOST_REQUIRE(channel_result); auto channel = std::move(*channel_result); auto moved = std::move(channel); @@ -2169,9 +2170,10 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_rejects_invalid_timeout) { right_socket.local_endpoint().port(), }; auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{ - boost::asio::ip::udp::v4(), - 0, - }, right_endpoint); + boost::asio::ip::udp::v4(), + 0, + }, + right_endpoint); BOOST_REQUIRE(channel_result); auto channel = std::move(*channel_result); auto closed = boost::asio::co_spawn(io, channel.async_close(std::chrono::milliseconds{0}), boost::asio::use_future);