@@ -48,6 +48,10 @@ jobs:
|
|||||||
restore-keys: conan-${{ runner.os }}-
|
restore-keys: conan-${{ runner.os }}-
|
||||||
- name: Configure native release
|
- name: Configure native release
|
||||||
run: python3 modulus.py configure --target x86_64_gcc12_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
|
- name: Build native release
|
||||||
run: python3 modulus.py build --target x86_64_gcc12_release
|
run: python3 modulus.py build --target x86_64_gcc12_release
|
||||||
- name: Test native release
|
- name: Test native release
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ Ligo uses Modulus for shared build tooling, Boost.JSON, and OpenSSL integration.
|
|||||||
|
|
||||||
## Build
|
## 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:
|
Configure, build, and test the default target:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -41,15 +41,12 @@ class ligo_conan(conan.ConanFile):
|
|||||||
"tests/*.cpp",
|
"tests/*.cpp",
|
||||||
"tests/*.hpp",
|
"tests/*.hpp",
|
||||||
)
|
)
|
||||||
|
|
||||||
def config_options(self):
|
def config_options(self):
|
||||||
if self.settings.os == "Windows":
|
if self.settings.os == "Windows":
|
||||||
del self.options.fPIC
|
del self.options.fPIC
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
if self.options.shared:
|
if self.options.shared:
|
||||||
del self.options.fPIC
|
del self.options.fPIC
|
||||||
|
|
||||||
def requirements(self):
|
def requirements(self):
|
||||||
self.requires(
|
self.requires(
|
||||||
"modulus/latest",
|
"modulus/latest",
|
||||||
@@ -59,7 +56,6 @@ class ligo_conan(conan.ConanFile):
|
|||||||
"with_openssl": True,
|
"with_openssl": True,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
deps = conan.tools.cmake.CMakeDeps(self)
|
deps = conan.tools.cmake.CMakeDeps(self)
|
||||||
deps.generate()
|
deps.generate()
|
||||||
@@ -69,14 +65,12 @@ class ligo_conan(conan.ConanFile):
|
|||||||
toolchain.variables["BUILD_SHARED_LIBS"] = bool(self.options.shared)
|
toolchain.variables["BUILD_SHARED_LIBS"] = bool(self.options.shared)
|
||||||
toolchain.variables["BUILD_TESTING"] = bool(self.options.with_tests)
|
toolchain.variables["BUILD_TESTING"] = bool(self.options.with_tests)
|
||||||
toolchain.generate()
|
toolchain.generate()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
cmake = conan.tools.cmake.CMake(self)
|
cmake = conan.tools.cmake.CMake(self)
|
||||||
cmake.configure()
|
cmake.configure()
|
||||||
cmake.build()
|
cmake.build()
|
||||||
if self.options.with_tests and conan.tools.build.can_run(self):
|
if self.options.with_tests and conan.tools.build.can_run(self):
|
||||||
cmake.test(target="check")
|
cmake.test(target="check")
|
||||||
|
|
||||||
def package_id(self):
|
def package_id(self):
|
||||||
self.info.options.rm_safe("with_tests")
|
self.info.options.rm_safe("with_tests")
|
||||||
for requirement in (
|
for requirement in (
|
||||||
@@ -88,11 +82,9 @@ class ligo_conan(conan.ConanFile):
|
|||||||
):
|
):
|
||||||
if requirement in self.info.requires.pkg_names:
|
if requirement in self.info.requires.pkg_names:
|
||||||
self.info.requires.remove(requirement)
|
self.info.requires.remove(requirement)
|
||||||
|
|
||||||
def package(self):
|
def package(self):
|
||||||
cmake = conan.tools.cmake.CMake(self)
|
cmake = conan.tools.cmake.CMake(self)
|
||||||
cmake.install()
|
cmake.install()
|
||||||
|
|
||||||
def package_info(self):
|
def package_info(self):
|
||||||
self.cpp_info.set_property(
|
self.cpp_info.set_property(
|
||||||
"cmake_file_name",
|
"cmake_file_name",
|
||||||
|
|||||||
+10
-9
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <ligo/security.hpp>
|
#include <ligo/security.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace ligo {
|
namespace ligo {
|
||||||
|
|
||||||
enum class protocol {
|
enum class protocol {
|
||||||
@@ -41,14 +42,14 @@ struct endpoint_config {
|
|||||||
ligo::udp_reliability_config udp{};
|
ligo::udp_reliability_config udp{};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto validate(ligo::endpoint_config const& config) -> std::expected<void, modulus::error>;
|
auto validate(ligo::endpoint_config const &config) -> std::expected<void, modulus::error>;
|
||||||
auto parse_endpoint_config(boost::json::value const& value) -> std::expected<ligo::endpoint_config, modulus::error>;
|
auto parse_endpoint_config(boost::json::value const &value) -> std::expected<ligo::endpoint_config, modulus::error>;
|
||||||
auto parse_endpoint_configs(boost::json::value const& value) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error>;
|
auto parse_endpoint_configs(boost::json::value const &value) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error>;
|
||||||
auto load_endpoint_configs(std::string const& path) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error>;
|
auto load_endpoint_configs(std::string const &path) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error>;
|
||||||
auto to_json(ligo::udp_reliability_config const& config) -> boost::json::value;
|
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::http_config const &config) -> boost::json::value;
|
||||||
auto to_json(ligo::security_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(ligo::endpoint_config const &config) -> boost::json::value;
|
||||||
auto to_json(std::vector<ligo::endpoint_config> const& configs) -> boost::json::value;
|
auto to_json(std::vector<ligo::endpoint_config> const &configs) -> boost::json::value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,26 +8,27 @@
|
|||||||
|
|
||||||
#include <modulus.hpp>
|
#include <modulus.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace ligo::detail {
|
namespace ligo::detail {
|
||||||
|
|
||||||
constexpr std::int32_t error_ok{0};
|
constexpr std::int32_t error_ok{0};
|
||||||
constexpr std::int32_t error_invalid_argument{1};
|
constexpr std::int32_t error_invalid_argument{1};
|
||||||
constexpr std::int32_t error_not_found{2};
|
constexpr std::int32_t error_not_found{2};
|
||||||
constexpr std::int32_t error_unavailable{3};
|
constexpr std::int32_t error_unavailable{3};
|
||||||
constexpr std::int32_t error_timeout{4};
|
constexpr std::int32_t error_timeout{4};
|
||||||
constexpr std::int32_t error_internal{5};
|
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 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<void, modulus::error>;
|
auto fail_void(modulus::error error) -> std::expected<void, modulus::error>;
|
||||||
|
|
||||||
template <typename VALUE>
|
template <typename VALUE>
|
||||||
auto fail(modulus::error error) -> std::expected<VALUE, modulus::error>;
|
auto fail(modulus::error error) -> std::expected<VALUE, modulus::error>;
|
||||||
template <typename VALUE>
|
template <typename VALUE>
|
||||||
auto fail(std::expected<void, modulus::error> const& result) -> std::expected<VALUE, modulus::error>;
|
auto fail(std::expected<void, modulus::error> const &result) -> std::expected<VALUE, modulus::error>;
|
||||||
template <typename VALUE, typename MESSAGE>
|
template <typename VALUE, typename MESSAGE>
|
||||||
auto fail(std::int32_t code, MESSAGE&& message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected<VALUE, modulus::error>;
|
auto fail(std::int32_t code, MESSAGE &&message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected<VALUE, modulus::error>;
|
||||||
template <typename MESSAGE>
|
template <typename MESSAGE>
|
||||||
auto fail_void(std::int32_t code, MESSAGE&& message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected<void, modulus::error>;
|
auto fail_void(std::int32_t code, MESSAGE &&message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected<void, modulus::error>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,17 +38,17 @@ auto ligo::detail::fail(modulus::error error) -> std::expected<VALUE, modulus::e
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename VALUE>
|
template <typename VALUE>
|
||||||
auto ligo::detail::fail(std::expected<void, modulus::error> const& result) -> std::expected<VALUE, modulus::error> {
|
auto ligo::detail::fail(std::expected<void, modulus::error> const &result) -> std::expected<VALUE, modulus::error> {
|
||||||
assert(!result);
|
assert(!result);
|
||||||
return ligo::detail::fail<VALUE>(result.error());
|
return ligo::detail::fail<VALUE>(result.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename VALUE, typename MESSAGE>
|
template <typename VALUE, typename MESSAGE>
|
||||||
auto ligo::detail::fail(std::int32_t code, MESSAGE&& message, modulus::source_location location) -> std::expected<VALUE, modulus::error> {
|
auto ligo::detail::fail(std::int32_t code, MESSAGE &&message, modulus::source_location location) -> std::expected<VALUE, modulus::error> {
|
||||||
return modulus::fail<VALUE>(ligo::detail::make_error(code, std::string{std::forward<MESSAGE>(message)}, location));
|
return modulus::fail<VALUE>(ligo::detail::make_error(code, std::string{std::forward<MESSAGE>(message)}, location));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename MESSAGE>
|
template <typename MESSAGE>
|
||||||
auto ligo::detail::fail_void(std::int32_t code, MESSAGE&& message, modulus::source_location location) -> std::expected<void, modulus::error> {
|
auto ligo::detail::fail_void(std::int32_t code, MESSAGE &&message, modulus::source_location location) -> std::expected<void, modulus::error> {
|
||||||
return modulus::fail<void>(ligo::detail::make_error(code, std::string{std::forward<MESSAGE>(message)}, location));
|
return modulus::fail<void>(ligo::detail::make_error(code, std::string{std::forward<MESSAGE>(message)}, location));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,17 +25,18 @@
|
|||||||
#include <ligo/detail/errors.hpp>
|
#include <ligo/detail/errors.hpp>
|
||||||
#include <ligo/detail/transport.hpp>
|
#include <ligo/detail/transport.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace ligo::detail {
|
namespace ligo::detail {
|
||||||
|
|
||||||
auto cancel_session_stream(boost::beast::tcp_stream& stream) -> void;
|
auto cancel_session_stream(boost::beast::tcp_stream &stream) -> void;
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto cancel_session_stream(boost::asio::ssl::stream<NEXT_LAYER>& stream) -> void;
|
auto cancel_session_stream(boost::asio::ssl::stream<NEXT_LAYER> &stream) -> void;
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
struct session_registry {
|
struct session_registry {
|
||||||
static auto cancel_waiters(std::vector<std::shared_ptr<boost::asio::steady_timer>> const& live) -> void;
|
static auto cancel_waiters(std::vector<std::shared_ptr<boost::asio::steady_timer>> const &live) -> void;
|
||||||
auto add(std::shared_ptr<S> const& stream) -> void;
|
auto add(std::shared_ptr<S> const &stream) -> void;
|
||||||
auto remove(std::shared_ptr<S> const& stream) -> void;
|
auto remove(std::shared_ptr<S> const &stream) -> void;
|
||||||
auto cancel_all() -> void;
|
auto cancel_all() -> void;
|
||||||
auto empty() const -> std::bool_t;
|
auto empty() const -> std::bool_t;
|
||||||
auto wait_empty(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto wait_empty(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
@@ -57,34 +58,34 @@ struct session_guard {
|
|||||||
template <typename S>
|
template <typename S>
|
||||||
auto stop_accepting_server(std::shared_ptr<S> state) -> void;
|
auto stop_accepting_server(std::shared_ptr<S> state) -> void;
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto stop_accepting_server_now(std::shared_ptr<S> const& state) -> void;
|
auto stop_accepting_server_now(std::shared_ptr<S> const &state) -> void;
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto async_stop_accepting_server(std::shared_ptr<S> state, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto async_stop_accepting_server(std::shared_ptr<S> state, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto ligo::detail::cancel_session_stream(boost::asio::ssl::stream<NEXT_LAYER>& stream) -> void {
|
auto ligo::detail::cancel_session_stream(boost::asio::ssl::stream<NEXT_LAYER> &stream) -> void {
|
||||||
auto ignored = boost::system::error_code{};
|
auto ignored = boost::system::error_code{};
|
||||||
stream.lowest_layer().cancel(ignored);
|
stream.lowest_layer().cancel(ignored);
|
||||||
stream.lowest_layer().close(ignored);
|
stream.lowest_layer().close(ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto ligo::detail::session_registry<S>::cancel_waiters(std::vector<std::shared_ptr<boost::asio::steady_timer>> const& live) -> void {
|
auto ligo::detail::session_registry<S>::cancel_waiters(std::vector<std::shared_ptr<boost::asio::steady_timer>> const &live) -> void {
|
||||||
for (auto& waiter : live) {
|
for (auto &waiter : live) {
|
||||||
waiter->cancel();
|
waiter->cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto ligo::detail::session_registry<S>::add(std::shared_ptr<S> const& stream) -> void {
|
auto ligo::detail::session_registry<S>::add(std::shared_ptr<S> const &stream) -> void {
|
||||||
auto lock = std::scoped_lock{mutex};
|
auto lock = std::scoped_lock{mutex};
|
||||||
sessions.insert(stream);
|
sessions.insert(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto ligo::detail::session_registry<S>::remove(std::shared_ptr<S> const& stream) -> void {
|
auto ligo::detail::session_registry<S>::remove(std::shared_ptr<S> const &stream) -> void {
|
||||||
auto live = std::vector<std::shared_ptr<boost::asio::steady_timer>>{};
|
auto live = std::vector<std::shared_ptr<boost::asio::steady_timer>>{};
|
||||||
{
|
{
|
||||||
auto lock = std::scoped_lock{mutex};
|
auto lock = std::scoped_lock{mutex};
|
||||||
@@ -101,7 +102,7 @@ auto ligo::detail::session_registry<S>::cancel_all() -> void {
|
|||||||
auto lock = std::scoped_lock{mutex};
|
auto lock = std::scoped_lock{mutex};
|
||||||
copy.assign(sessions.begin(), sessions.end());
|
copy.assign(sessions.begin(), sessions.end());
|
||||||
}
|
}
|
||||||
for (auto& stream : copy) {
|
for (auto &stream : copy) {
|
||||||
boost::asio::post(stream->get_executor(), [stream] {
|
boost::asio::post(stream->get_executor(), [stream] {
|
||||||
ligo::detail::cancel_session_stream(*stream);
|
ligo::detail::cancel_session_stream(*stream);
|
||||||
});
|
});
|
||||||
@@ -132,7 +133,7 @@ auto ligo::detail::session_registry<S>::wait_empty(std::chrono::milliseconds tim
|
|||||||
waiters.push_back(notify_timer);
|
waiters.push_back(notify_timer);
|
||||||
}
|
}
|
||||||
deadline_timer->expires_after(timeout);
|
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) {
|
if (!error) {
|
||||||
timed_out->store(true, std::memory_order_relaxed);
|
timed_out->store(true, std::memory_order_relaxed);
|
||||||
notify_timer->cancel();
|
notify_timer->cancel();
|
||||||
@@ -168,7 +169,7 @@ template <typename S>
|
|||||||
auto ligo::detail::session_registry<S>::live_waiters_locked() -> std::vector<std::shared_ptr<boost::asio::steady_timer>> {
|
auto ligo::detail::session_registry<S>::live_waiters_locked() -> std::vector<std::shared_ptr<boost::asio::steady_timer>> {
|
||||||
auto live = std::vector<std::shared_ptr<boost::asio::steady_timer>>{};
|
auto live = std::vector<std::shared_ptr<boost::asio::steady_timer>>{};
|
||||||
auto retained = std::vector<std::weak_ptr<boost::asio::steady_timer>>{};
|
auto retained = std::vector<std::weak_ptr<boost::asio::steady_timer>>{};
|
||||||
for (auto& waiter : waiters) {
|
for (auto &waiter : waiters) {
|
||||||
if (auto locked = waiter.lock()) {
|
if (auto locked = waiter.lock()) {
|
||||||
live.push_back(locked);
|
live.push_back(locked);
|
||||||
retained.push_back(locked);
|
retained.push_back(locked);
|
||||||
@@ -209,7 +210,7 @@ auto ligo::detail::stop_accepting_server(std::shared_ptr<S> state) -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto ligo::detail::stop_accepting_server_now(std::shared_ptr<S> const& state) -> void {
|
auto ligo::detail::stop_accepting_server_now(std::shared_ptr<S> const &state) -> void {
|
||||||
auto lock = std::scoped_lock{state->lifecycle_mutex};
|
auto lock = std::scoped_lock{state->lifecycle_mutex};
|
||||||
if (state->stopped.exchange(true)) {
|
if (state->stopped.exchange(true)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -7,16 +7,17 @@
|
|||||||
|
|
||||||
#include <modulus.hpp>
|
#include <modulus.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace ligo::detail {
|
namespace ligo::detail {
|
||||||
|
|
||||||
class state_handle {
|
class state_handle {
|
||||||
public:
|
public:
|
||||||
state_handle() = default;
|
state_handle() = default;
|
||||||
state_handle(ligo::detail::state_handle const&) = delete;
|
state_handle(ligo::detail::state_handle const &) = delete;
|
||||||
state_handle(ligo::detail::state_handle&& other) noexcept;
|
state_handle(ligo::detail::state_handle &&other) noexcept;
|
||||||
~state_handle() = default;
|
~state_handle() = default;
|
||||||
auto operator=(ligo::detail::state_handle const&) -> ligo::detail::state_handle& = delete;
|
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 &&other) noexcept -> ligo::detail::state_handle &;
|
||||||
explicit operator std::bool_t() const noexcept;
|
explicit operator std::bool_t() const noexcept;
|
||||||
template <typename S>
|
template <typename S>
|
||||||
explicit state_handle(std::shared_ptr<S> state);
|
explicit state_handle(std::shared_ptr<S> state);
|
||||||
@@ -29,27 +30,28 @@ private:
|
|||||||
class unique_state {
|
class unique_state {
|
||||||
public:
|
public:
|
||||||
unique_state() noexcept = default;
|
unique_state() noexcept = default;
|
||||||
unique_state(ligo::detail::unique_state const&) = delete;
|
unique_state(ligo::detail::unique_state const &) = delete;
|
||||||
unique_state(ligo::detail::unique_state&&) noexcept = default;
|
unique_state(ligo::detail::unique_state &&) noexcept = default;
|
||||||
~unique_state() = default;
|
~unique_state() = default;
|
||||||
auto operator=(ligo::detail::unique_state const&) -> ligo::detail::unique_state& = delete;
|
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 &&) noexcept -> ligo::detail::unique_state & = default;
|
||||||
explicit operator std::bool_t() const noexcept;
|
explicit operator std::bool_t() const noexcept;
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
explicit unique_state(std::unique_ptr<STATE> state);
|
explicit unique_state(std::unique_ptr<STATE> state);
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
auto as() const noexcept -> STATE*;
|
auto as() const noexcept -> STATE *;
|
||||||
private:
|
private:
|
||||||
static auto ignore_state(void* state) -> void;
|
static auto ignore_state(void *state) -> void;
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
static auto delete_state(void* state) -> void;
|
static auto delete_state(void *state) -> void;
|
||||||
std::unique_ptr<void, std::function<void(void*)>> state_{nullptr, ignore_state};
|
std::unique_ptr<void, std::function<void(void *)>> state_{nullptr, ignore_state};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
ligo::detail::state_handle::state_handle(std::shared_ptr<STATE> state) : state_{std::shared_ptr<void>{std::move(state)}} {}
|
ligo::detail::state_handle::state_handle(std::shared_ptr<STATE> state)
|
||||||
|
: state_{std::shared_ptr<void>{std::move(state)}} {}
|
||||||
|
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
auto ligo::detail::state_handle::as() const -> std::shared_ptr<STATE> {
|
auto ligo::detail::state_handle::as() const -> std::shared_ptr<STATE> {
|
||||||
@@ -57,14 +59,15 @@ auto ligo::detail::state_handle::as() const -> std::shared_ptr<STATE> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
ligo::detail::unique_state::unique_state(std::unique_ptr<STATE> state) : state_{state.release(), delete_state<STATE>} {}
|
ligo::detail::unique_state::unique_state(std::unique_ptr<STATE> state)
|
||||||
|
: state_{state.release(), delete_state<STATE>} {}
|
||||||
|
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
auto ligo::detail::unique_state::as() const noexcept -> STATE* {
|
auto ligo::detail::unique_state::as() const noexcept -> STATE * {
|
||||||
return static_cast<STATE*>(state_.get());
|
return static_cast<STATE *>(state_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename STATE>
|
template <typename STATE>
|
||||||
auto ligo::detail::unique_state::delete_state(void* state) -> void {
|
auto ligo::detail::unique_state::delete_state(void *state) -> void {
|
||||||
delete static_cast<STATE*>(state);
|
delete static_cast<STATE *>(state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <ligo/detail/errors.hpp>
|
#include <ligo/detail/errors.hpp>
|
||||||
#include <ligo/service.hpp>
|
#include <ligo/service.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace ligo::detail {
|
namespace ligo::detail {
|
||||||
|
|
||||||
struct endpoint_parts {
|
struct endpoint_parts {
|
||||||
@@ -37,13 +38,13 @@ struct endpoint_parts {
|
|||||||
|
|
||||||
auto status_name(std::int32_t code) -> std::string;
|
auto status_name(std::int32_t code) -> std::string;
|
||||||
auto parse_status_code(std::string_view value) -> std::int32_t;
|
auto parse_status_code(std::string_view value) -> std::int32_t;
|
||||||
auto network_failure(boost::system::error_code const& error) -> 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 operation_failure(boost::system::error_code const &error, std::string timeout_message) -> modulus::error;
|
||||||
auto invalid_argument(std::string message) -> modulus::error;
|
auto invalid_argument(std::string message) -> modulus::error;
|
||||||
auto unavailable(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<void, modulus::error>;
|
auto validate_positive_timeout(std::chrono::milliseconds timeout, std::string_view name) -> std::expected<void, modulus::error>;
|
||||||
auto report_error(std::function<void(modulus::error)> const& on_error, modulus::error error) -> void;
|
auto report_error(std::function<void(modulus::error)> const &on_error, modulus::error error) -> void;
|
||||||
auto report_error(std::function<void(modulus::error)> const& on_error, std::expected<void, modulus::error> status) -> void;
|
auto report_error(std::function<void(modulus::error)> const &on_error, std::expected<void, modulus::error> status) -> void;
|
||||||
auto response_envelope(std::expected<boost::json::value, modulus::error> result) -> boost::json::value;
|
auto response_envelope(std::expected<boost::json::value, modulus::error> result) -> boost::json::value;
|
||||||
auto serialize_response_envelope(std::expected<boost::json::value, modulus::error> result) -> std::string;
|
auto serialize_response_envelope(std::expected<boost::json::value, modulus::error> result) -> std::string;
|
||||||
auto unwrap_response_envelope(boost::json::value value, std::string_view protocol_name) -> std::expected<boost::json::value, modulus::error>;
|
auto unwrap_response_envelope(boost::json::value value, std::string_view protocol_name) -> std::expected<boost::json::value, modulus::error>;
|
||||||
@@ -51,10 +52,10 @@ auto parse_port(std::string_view text) -> std::expected<std::uint16_t, modulus::
|
|||||||
auto parse_endpoint_text(std::string_view text, std::uint16_t fallback_port) -> std::expected<ligo::detail::endpoint_parts, modulus::error>;
|
auto parse_endpoint_text(std::string_view text, std::uint16_t fallback_port) -> std::expected<ligo::detail::endpoint_parts, modulus::error>;
|
||||||
auto parse_client_endpoint_text(std::string_view text) -> std::expected<ligo::detail::endpoint_parts, modulus::error>;
|
auto parse_client_endpoint_text(std::string_view text) -> std::expected<ligo::detail::endpoint_parts, modulus::error>;
|
||||||
auto parse_server_endpoint_text(std::string_view text) -> std::expected<ligo::detail::endpoint_parts, modulus::error>;
|
auto parse_server_endpoint_text(std::string_view text) -> std::expected<ligo::detail::endpoint_parts, modulus::error>;
|
||||||
auto start_tcp_acceptor(boost::asio::ip::tcp::acceptor& acceptor, std::string const& host, std::uint16_t port) -> std::expected<std::uint16_t, modulus::error>;
|
auto start_tcp_acceptor(boost::asio::ip::tcp::acceptor &acceptor, std::string const &host, std::uint16_t port) -> std::expected<std::uint16_t, modulus::error>;
|
||||||
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<std::expected<boost::asio::ip::tcp::resolver::results_type, modulus::error>>;
|
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<std::expected<boost::asio::ip::tcp::resolver::results_type, modulus::error>>;
|
||||||
auto call_handler(ligo::service_router const& router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
auto call_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
||||||
auto call_response_handler(ligo::service_router const& router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable<std::expected<ligo::service_response, modulus::error>>;
|
auto call_response_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable<std::expected<ligo::service_response, modulus::error>>;
|
||||||
|
|
||||||
struct stream_deadline {
|
struct stream_deadline {
|
||||||
std::shared_ptr<boost::asio::steady_timer> timer{};
|
std::shared_ptr<boost::asio::steady_timer> timer{};
|
||||||
@@ -63,29 +64,29 @@ struct stream_deadline {
|
|||||||
std::shared_ptr<boost::asio::cancellation_signal> cancellation{};
|
std::shared_ptr<boost::asio::cancellation_signal> cancellation{};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto start_stream_deadline(boost::beast::tcp_stream& stream, 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;
|
auto start_stream_deadline(boost::asio::ip::tcp::socket &socket, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline;
|
||||||
|
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto start_stream_deadline(boost::asio::ssl::stream<NEXT_LAYER>& stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline;
|
auto start_stream_deadline(boost::asio::ssl::stream<NEXT_LAYER> &stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline;
|
||||||
|
|
||||||
auto cancel_stream_deadline(ligo::detail::stream_deadline& deadline) -> void;
|
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::cancellation_slot>(), boost::asio::as_tuple(boost::asio::use_awaitable)));
|
auto deadline_token(ligo::detail::stream_deadline &deadline) -> decltype(boost::asio::bind_cancellation_slot(std::declval<boost::asio::cancellation_slot>(), 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 operation_failure(boost::system::error_code const &error, ligo::detail::stream_deadline const &deadline, std::string timeout_message) -> modulus::error;
|
||||||
|
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto async_tls_handshake(boost::asio::ssl::stream<NEXT_LAYER>& stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto async_tls_handshake(boost::asio::ssl::stream<NEXT_LAYER> &stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
|
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto async_tls_shutdown(boost::asio::ssl::stream<NEXT_LAYER>& stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto async_tls_shutdown(boost::asio::ssl::stream<NEXT_LAYER> &stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto ligo::detail::start_stream_deadline(boost::asio::ssl::stream<NEXT_LAYER>& stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline {
|
auto ligo::detail::start_stream_deadline(boost::asio::ssl::stream<NEXT_LAYER> &stream, std::chrono::milliseconds timeout) -> ligo::detail::stream_deadline {
|
||||||
auto deadline = ligo::detail::stream_deadline{.timer = std::make_shared<boost::asio::steady_timer>(stream.get_executor()), .timed_out = std::make_shared<std::atomic<std::bool_t>>(false), .active = std::make_shared<std::atomic<std::bool_t>>(true), .cancellation = std::make_shared<boost::asio::cancellation_signal>()};
|
auto deadline = ligo::detail::stream_deadline{.timer = std::make_shared<boost::asio::steady_timer>(stream.get_executor()), .timed_out = std::make_shared<std::atomic<std::bool_t>>(false), .active = std::make_shared<std::atomic<std::bool_t>>(true), .cancellation = std::make_shared<boost::asio::cancellation_signal>()};
|
||||||
deadline.timer->expires_after(timeout);
|
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)) {
|
if (!error && active->exchange(false, std::memory_order_acq_rel)) {
|
||||||
timed_out->store(true, std::memory_order_release);
|
timed_out->store(true, std::memory_order_release);
|
||||||
cancellation->emit(boost::asio::cancellation_type::terminal);
|
cancellation->emit(boost::asio::cancellation_type::terminal);
|
||||||
@@ -95,7 +96,7 @@ auto ligo::detail::start_stream_deadline(boost::asio::ssl::stream<NEXT_LAYER>& s
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto ligo::detail::async_tls_handshake(boost::asio::ssl::stream<NEXT_LAYER>& stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto ligo::detail::async_tls_handshake(boost::asio::ssl::stream<NEXT_LAYER> &stream, boost::asio::ssl::stream_base::handshake_type type, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
auto deadline = ligo::detail::start_stream_deadline(stream, timeout);
|
auto deadline = ligo::detail::start_stream_deadline(stream, timeout);
|
||||||
auto [error] = co_await stream.async_handshake(type, ligo::detail::deadline_token(deadline));
|
auto [error] = co_await stream.async_handshake(type, ligo::detail::deadline_token(deadline));
|
||||||
ligo::detail::cancel_stream_deadline(deadline);
|
ligo::detail::cancel_stream_deadline(deadline);
|
||||||
@@ -106,7 +107,7 @@ auto ligo::detail::async_tls_handshake(boost::asio::ssl::stream<NEXT_LAYER>& str
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename NEXT_LAYER>
|
template <typename NEXT_LAYER>
|
||||||
auto ligo::detail::async_tls_shutdown(boost::asio::ssl::stream<NEXT_LAYER>& stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto ligo::detail::async_tls_shutdown(boost::asio::ssl::stream<NEXT_LAYER> &stream, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
auto deadline = ligo::detail::start_stream_deadline(stream, timeout);
|
auto deadline = ligo::detail::start_stream_deadline(stream, timeout);
|
||||||
auto [error] = co_await stream.async_shutdown(ligo::detail::deadline_token(deadline));
|
auto [error] = co_await stream.async_shutdown(ligo::detail::deadline_token(deadline));
|
||||||
ligo::detail::cancel_stream_deadline(deadline);
|
ligo::detail::cancel_stream_deadline(deadline);
|
||||||
|
|||||||
+10
-10
@@ -55,7 +55,7 @@ struct server_options {
|
|||||||
class client {
|
class client {
|
||||||
public:
|
public:
|
||||||
explicit client(ligo::http::endpoint endpoint, ligo::http::client_options options = {});
|
explicit client(ligo::http::endpoint endpoint, ligo::http::client_options options = {});
|
||||||
auto call(ligo::http::request const& request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
auto call(ligo::http::request const &request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
||||||
private:
|
private:
|
||||||
ligo::http::endpoint endpoint_{};
|
ligo::http::endpoint endpoint_{};
|
||||||
ligo::http::client_options options_{};
|
ligo::http::client_options options_{};
|
||||||
@@ -63,13 +63,13 @@ private:
|
|||||||
|
|
||||||
class server {
|
class server {
|
||||||
public:
|
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(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 const &) = delete;
|
||||||
server(ligo::http::server&&) noexcept = default;
|
server(ligo::http::server &&) noexcept = default;
|
||||||
~server();
|
~server();
|
||||||
auto operator=(ligo::http::server const&) -> ligo::http::server& = delete;
|
auto operator=(ligo::http::server const &) -> ligo::http::server & = delete;
|
||||||
auto operator=(ligo::http::server&&) noexcept -> ligo::http::server&;
|
auto operator=(ligo::http::server &&) noexcept -> ligo::http::server &;
|
||||||
auto start() -> std::expected<void, modulus::error>;
|
auto start() -> std::expected<void, modulus::error>;
|
||||||
auto stop() -> void;
|
auto stop() -> void;
|
||||||
auto async_stop(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto async_stop(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
@@ -78,9 +78,9 @@ private:
|
|||||||
ligo::detail::state_handle state_{};
|
ligo::detail::state_handle state_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::http::endpoint, modulus::error>;
|
auto client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::http::endpoint, modulus::error>;
|
||||||
auto server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::http::endpoint, modulus::error>;
|
auto server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::http::endpoint, modulus::error>;
|
||||||
auto client_options_from_config(ligo::endpoint_config const& config) -> ligo::http::client_options;
|
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 server_options_from_config(ligo::endpoint_config const &config) -> ligo::http::server_options;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -25,18 +25,18 @@ class byte_stream_state;
|
|||||||
class byte_stream {
|
class byte_stream {
|
||||||
public:
|
public:
|
||||||
byte_stream() = default;
|
byte_stream() = default;
|
||||||
byte_stream(ligo::net::byte_stream const&) = delete;
|
byte_stream(ligo::net::byte_stream const &) = delete;
|
||||||
byte_stream(ligo::net::byte_stream&&) noexcept = default;
|
byte_stream(ligo::net::byte_stream &&) noexcept = default;
|
||||||
~byte_stream();
|
~byte_stream();
|
||||||
auto operator=(ligo::net::byte_stream const&) -> ligo::net::byte_stream& = delete;
|
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 &&) noexcept -> ligo::net::byte_stream &;
|
||||||
static auto from_socket(ligo::tcp::socket_handle socket) -> std::expected<ligo::net::byte_stream, modulus::error>;
|
static auto from_socket(ligo::tcp::socket_handle socket) -> std::expected<ligo::net::byte_stream, modulus::error>;
|
||||||
static auto from_tls_socket(ligo::tcp::tls_socket socket) -> std::expected<ligo::net::byte_stream, modulus::error>;
|
static auto from_tls_socket(ligo::tcp::tls_socket socket) -> std::expected<ligo::net::byte_stream, modulus::error>;
|
||||||
auto async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>>;
|
auto async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>>;
|
||||||
auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>>;
|
auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>>;
|
||||||
auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
auto async_shutdown(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto async_shutdown(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
auto close(boost::system::error_code& error) -> void;
|
auto close(boost::system::error_code &error) -> void;
|
||||||
auto is_open() const -> std::bool_t;
|
auto is_open() const -> std::bool_t;
|
||||||
private:
|
private:
|
||||||
explicit byte_stream(std::shared_ptr<ligo::net::byte_stream_state> state);
|
explicit byte_stream(std::shared_ptr<ligo::net::byte_stream_state> state);
|
||||||
@@ -46,11 +46,11 @@ private:
|
|||||||
class listener {
|
class listener {
|
||||||
public:
|
public:
|
||||||
listener() = default;
|
listener() = default;
|
||||||
listener(ligo::net::listener const&) = delete;
|
listener(ligo::net::listener const &) = delete;
|
||||||
listener(ligo::net::listener&&) noexcept = default;
|
listener(ligo::net::listener &&) noexcept = default;
|
||||||
~listener();
|
~listener();
|
||||||
auto operator=(ligo::net::listener const&) -> ligo::net::listener& = delete;
|
auto operator=(ligo::net::listener const &) -> ligo::net::listener & = delete;
|
||||||
auto operator=(ligo::net::listener&&) noexcept -> ligo::net::listener&;
|
auto operator=(ligo::net::listener &&) noexcept -> ligo::net::listener &;
|
||||||
static auto bind(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint) -> std::expected<ligo::net::listener, modulus::error>;
|
static auto bind(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint) -> std::expected<ligo::net::listener, modulus::error>;
|
||||||
auto selected_port() const -> std::uint16_t;
|
auto selected_port() const -> std::uint16_t;
|
||||||
auto async_accept() -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
auto async_accept() -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
||||||
@@ -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<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
auto connect_tcp(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
||||||
auto connect(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
auto connect(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
||||||
auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const& config) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
||||||
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
||||||
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <modulus.hpp>
|
#include <modulus.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace ligo {
|
namespace ligo {
|
||||||
|
|
||||||
enum class security_mode {
|
enum class security_mode {
|
||||||
@@ -35,12 +36,12 @@ struct security_config {
|
|||||||
std::shared_ptr<boost::asio::ssl::context> tls_context{};
|
std::shared_ptr<boost::asio::ssl::context> tls_context{};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto make_tls_client_context(ligo::security_config const& config) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error>;
|
auto make_tls_client_context(ligo::security_config const &config) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error>;
|
||||||
auto make_tls_server_context(ligo::security_config const& config) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error>;
|
auto make_tls_server_context(ligo::security_config const &config) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error>;
|
||||||
auto apply_tls_client_verification(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& stream, std::string const& host, ligo::security_config const& config) -> std::expected<void, modulus::error>;
|
auto apply_tls_client_verification(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &stream, std::string const &host, ligo::security_config const &config) -> std::expected<void, modulus::error>;
|
||||||
auto configure_tls_client_stream(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& stream, std::string const& host, ligo::security_config const& config) -> std::expected<void, modulus::error>;
|
auto configure_tls_client_stream(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &stream, std::string const &host, ligo::security_config const &config) -> std::expected<void, modulus::error>;
|
||||||
auto validate_tls_server_config(std::string_view protocol, ligo::security_config const& config) -> std::expected<void, modulus::error>;
|
auto validate_tls_server_config(std::string_view protocol, ligo::security_config const &config) -> std::expected<void, modulus::error>;
|
||||||
auto validate_tls_server_context(std::shared_ptr<boost::asio::ssl::context> const& context) -> std::expected<void, modulus::error>;
|
auto validate_tls_server_context(std::shared_ptr<boost::asio::ssl::context> const &context) -> std::expected<void, modulus::error>;
|
||||||
auto unsupported_security(std::string_view protocol, ligo::security_mode mode) -> modulus::error;
|
auto unsupported_security(std::string_view protocol, ligo::security_mode mode) -> modulus::error;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <modulus.hpp>
|
#include <modulus.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace ligo {
|
namespace ligo {
|
||||||
|
|
||||||
struct request_context {
|
struct request_context {
|
||||||
@@ -29,11 +30,11 @@ struct service_response {
|
|||||||
class service_router {
|
class service_router {
|
||||||
public:
|
public:
|
||||||
service_router() = default;
|
service_router() = default;
|
||||||
service_router(ligo::service_router const& other);
|
service_router(ligo::service_router const &other);
|
||||||
service_router(ligo::service_router&& other);
|
service_router(ligo::service_router &&other);
|
||||||
~service_router() = default;
|
~service_router() = default;
|
||||||
auto operator=(ligo::service_router const& other) -> ligo::service_router&;
|
auto operator=(ligo::service_router const &other) -> ligo::service_router &;
|
||||||
auto operator=(ligo::service_router&& other) -> ligo::service_router&;
|
auto operator=(ligo::service_router &&other) -> ligo::service_router &;
|
||||||
auto add_route(std::string method, std::string route, std::function<boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>(ligo::request_context, boost::json::value)> handler) -> void;
|
auto add_route(std::string method, std::string route, std::function<boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>(ligo::request_context, boost::json::value)> handler) -> void;
|
||||||
auto add_response_route(std::string method, std::string route, std::function<boost::asio::awaitable<std::expected<ligo::service_response, modulus::error>>(ligo::request_context, boost::json::value)> handler) -> void;
|
auto add_response_route(std::string method, std::string route, std::function<boost::asio::awaitable<std::expected<ligo::service_response, modulus::error>>(ligo::request_context, boost::json::value)> handler) -> void;
|
||||||
auto call(ligo::request_context context, boost::json::value payload) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
auto call(ligo::request_context context, boost::json::value payload) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
||||||
|
|||||||
+23
-22
@@ -33,16 +33,16 @@ struct endpoint {
|
|||||||
|
|
||||||
struct socket_handle {
|
struct socket_handle {
|
||||||
socket_handle() = default;
|
socket_handle() = default;
|
||||||
socket_handle(ligo::tcp::socket_handle const&) = delete;
|
socket_handle(ligo::tcp::socket_handle const &) = delete;
|
||||||
socket_handle(ligo::tcp::socket_handle&&) noexcept = default;
|
socket_handle(ligo::tcp::socket_handle &&) noexcept = default;
|
||||||
explicit socket_handle(boost::asio::ip::tcp::socket socket);
|
explicit socket_handle(boost::asio::ip::tcp::socket socket);
|
||||||
explicit socket_handle(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
explicit socket_handle(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||||
auto operator=(ligo::tcp::socket_handle const&) -> ligo::tcp::socket_handle& = delete;
|
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 &&) noexcept -> ligo::tcp::socket_handle & = default;
|
||||||
auto socket() -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket>, modulus::error>;
|
auto socket() -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket>, modulus::error>;
|
||||||
auto socket() const -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket const>, modulus::error>;
|
auto socket() const -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket const>, modulus::error>;
|
||||||
auto is_open() const -> std::bool_t;
|
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<boost::asio::ip::tcp::socket, modulus::error>;
|
auto release_socket() -> std::expected<boost::asio::ip::tcp::socket, modulus::error>;
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket_{};
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket_{};
|
||||||
@@ -55,17 +55,17 @@ struct tls_socket {
|
|||||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream;
|
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream;
|
||||||
};
|
};
|
||||||
tls_socket() = default;
|
tls_socket() = default;
|
||||||
tls_socket(ligo::tcp::tls_socket const&) = delete;
|
tls_socket(ligo::tcp::tls_socket const &) = delete;
|
||||||
tls_socket(ligo::tcp::tls_socket&&) noexcept = default;
|
tls_socket(ligo::tcp::tls_socket &&) noexcept = default;
|
||||||
tls_socket(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ip::tcp::socket socket);
|
tls_socket(std::shared_ptr<boost::asio::ssl::context> 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 const &) -> ligo::tcp::tls_socket & = delete;
|
||||||
auto operator=(ligo::tcp::tls_socket&&) noexcept -> ligo::tcp::tls_socket& = default;
|
auto operator=(ligo::tcp::tls_socket &&) noexcept -> ligo::tcp::tls_socket & = default;
|
||||||
auto stream() -> std::expected<std::reference_wrapper<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>, modulus::error>;
|
auto stream() -> std::expected<std::reference_wrapper<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>, modulus::error>;
|
||||||
auto stream() const -> std::expected<std::reference_wrapper<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> const>, modulus::error>;
|
auto stream() const -> std::expected<std::reference_wrapper<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> const>, modulus::error>;
|
||||||
auto context() -> std::expected<std::reference_wrapper<boost::asio::ssl::context>, modulus::error>;
|
auto context() -> std::expected<std::reference_wrapper<boost::asio::ssl::context>, modulus::error>;
|
||||||
auto context() const -> std::expected<std::reference_wrapper<boost::asio::ssl::context const>, modulus::error>;
|
auto context() const -> std::expected<std::reference_wrapper<boost::asio::ssl::context const>, modulus::error>;
|
||||||
auto is_open() const -> std::bool_t;
|
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<ligo::tcp::tls_socket::released_stream, modulus::error>;
|
auto release_stream() -> std::expected<ligo::tcp::tls_socket::released_stream, modulus::error>;
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<boost::asio::ssl::context> context_{};
|
std::shared_ptr<boost::asio::ssl::context> context_{};
|
||||||
@@ -91,7 +91,7 @@ struct server_options {
|
|||||||
class client {
|
class client {
|
||||||
public:
|
public:
|
||||||
explicit client(ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {});
|
explicit client(ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {});
|
||||||
auto call(ligo::tcp::request const& request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
auto call(ligo::tcp::request const &request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>>;
|
||||||
private:
|
private:
|
||||||
ligo::tcp::endpoint endpoint_{};
|
ligo::tcp::endpoint endpoint_{};
|
||||||
ligo::tcp::client_options options_{};
|
ligo::tcp::client_options options_{};
|
||||||
@@ -99,13 +99,13 @@ private:
|
|||||||
|
|
||||||
class server {
|
class server {
|
||||||
public:
|
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(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 const &) = delete;
|
||||||
server(ligo::tcp::server&&) noexcept = default;
|
server(ligo::tcp::server &&) noexcept = default;
|
||||||
~server();
|
~server();
|
||||||
auto operator=(ligo::tcp::server const&) -> ligo::tcp::server& = delete;
|
auto operator=(ligo::tcp::server const &) -> ligo::tcp::server & = delete;
|
||||||
auto operator=(ligo::tcp::server&&) noexcept -> ligo::tcp::server&;
|
auto operator=(ligo::tcp::server &&) noexcept -> ligo::tcp::server &;
|
||||||
auto start() -> std::expected<void, modulus::error>;
|
auto start() -> std::expected<void, modulus::error>;
|
||||||
auto stop() -> void;
|
auto stop() -> void;
|
||||||
auto async_stop(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto async_stop(std::chrono::milliseconds timeout = std::chrono::milliseconds{5000}) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
@@ -114,15 +114,16 @@ private:
|
|||||||
ligo::detail::state_handle state_{};
|
ligo::detail::state_handle state_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::tcp::endpoint, modulus::error>;
|
auto client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::tcp::endpoint, modulus::error>;
|
||||||
auto server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::tcp::endpoint, modulus::error>;
|
auto server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::tcp::endpoint, modulus::error>;
|
||||||
auto client_options_from_config(ligo::endpoint_config const& config) -> ligo::tcp::client_options;
|
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 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<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
auto connect(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
||||||
auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const& config) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
auto connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>>;
|
||||||
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
||||||
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
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<std::expected<ligo::tcp::tls_socket, modulus::error>>;
|
||||||
|
|
||||||
inline tls_socket::released_stream::released_stream(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream) : context{std::move(context)}, stream{std::move(stream)} {}
|
inline tls_socket::released_stream::released_stream(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream)
|
||||||
|
: context{std::move(context)}, stream{std::move(stream)} {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -42,15 +42,15 @@ struct server_options {
|
|||||||
|
|
||||||
class client {
|
class client {
|
||||||
public:
|
public:
|
||||||
client(ligo::udp::client const&) = delete;
|
client(ligo::udp::client const &) = delete;
|
||||||
client(ligo::udp::client&&) noexcept = default;
|
client(ligo::udp::client &&) noexcept = default;
|
||||||
~client();
|
~client();
|
||||||
auto operator=(ligo::udp::client const&) -> ligo::udp::client& = delete;
|
auto operator=(ligo::udp::client const &) -> ligo::udp::client & = delete;
|
||||||
auto operator=(ligo::udp::client&&) noexcept -> ligo::udp::client&;
|
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<ligo::udp::client, modulus::error>;
|
static auto open(boost::asio::any_io_executor executor, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
||||||
static auto open(boost::asio::io_context& io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
static auto open(boost::asio::io_context &io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
||||||
static auto bind(boost::asio::any_io_executor executor, ligo::udp::endpoint endpoint, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
static auto bind(boost::asio::any_io_executor executor, ligo::udp::endpoint endpoint, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
||||||
static auto bind(boost::asio::io_context& io, ligo::udp::endpoint endpoint, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
static auto bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
||||||
static auto adopt(std::unique_ptr<boost::asio::ip::udp::socket> socket, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
static auto adopt(std::unique_ptr<boost::asio::ip::udp::socket> socket, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options = {}) -> std::expected<ligo::udp::client, modulus::error>;
|
||||||
auto send(boost::json::value payload) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto send(boost::json::value payload) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
auto send(ligo::udp::message message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto send(ligo::udp::message message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
@@ -65,13 +65,13 @@ private:
|
|||||||
|
|
||||||
class server {
|
class server {
|
||||||
public:
|
public:
|
||||||
server(ligo::udp::server const&) = delete;
|
server(ligo::udp::server const &) = delete;
|
||||||
server(ligo::udp::server&&) noexcept = default;
|
server(ligo::udp::server &&) noexcept = default;
|
||||||
~server();
|
~server();
|
||||||
auto operator=(ligo::udp::server const&) -> ligo::udp::server& = delete;
|
auto operator=(ligo::udp::server const &) -> ligo::udp::server & = delete;
|
||||||
auto operator=(ligo::udp::server&&) noexcept -> ligo::udp::server&;
|
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<ligo::udp::server, modulus::error>;
|
static auto bind(boost::asio::any_io_executor executor, ligo::udp::endpoint endpoint, ligo::udp::server_options options = {}) -> std::expected<ligo::udp::server, modulus::error>;
|
||||||
static auto bind(boost::asio::io_context& io, ligo::udp::endpoint endpoint, ligo::udp::server_options options = {}) -> std::expected<ligo::udp::server, modulus::error>;
|
static auto bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::server_options options = {}) -> std::expected<ligo::udp::server, modulus::error>;
|
||||||
static auto adopt(std::unique_ptr<boost::asio::ip::udp::socket> socket, boost::asio::ip::udp::endpoint peer, ligo::udp::server_options options = {}) -> std::expected<ligo::udp::server, modulus::error>;
|
static auto adopt(std::unique_ptr<boost::asio::ip::udp::socket> socket, boost::asio::ip::udp::endpoint peer, ligo::udp::server_options options = {}) -> std::expected<ligo::udp::server, modulus::error>;
|
||||||
auto send(boost::json::value payload) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto send(boost::json::value payload) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
auto send(ligo::udp::message message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
auto send(ligo::udp::message message) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||||
@@ -84,9 +84,9 @@ private:
|
|||||||
ligo::detail::state_handle state_{};
|
ligo::detail::state_handle state_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::udp::endpoint, modulus::error>;
|
auto client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::udp::endpoint, modulus::error>;
|
||||||
auto server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::udp::endpoint, modulus::error>;
|
auto server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::udp::endpoint, modulus::error>;
|
||||||
auto client_options_from_config(ligo::endpoint_config const& config) -> ligo::udp::client_options;
|
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 server_options_from_config(ligo::endpoint_config const &config) -> ligo::udp::server_options;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -16,6 +16,7 @@ COMMANDS = (
|
|||||||
"package",
|
"package",
|
||||||
"lsp",
|
"lsp",
|
||||||
"clangd",
|
"clangd",
|
||||||
|
"format",
|
||||||
)
|
)
|
||||||
COMMON_DIR = pathlib.Path("build") / "build_common"
|
COMMON_DIR = pathlib.Path("build") / "build_common"
|
||||||
TOOLS_DIR = pathlib.Path("build") / "build_tools"
|
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 / TOOLS_DIR / "clangd.py").is_file()
|
||||||
and (root / RUNTIME_DIR / "modulus" / "cli.py").is_file()
|
and (root / RUNTIME_DIR / "modulus" / "cli.py").is_file()
|
||||||
and (root / RUNTIME_DIR / "modulus" / "export.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():
|
def optional_credentials():
|
||||||
@@ -340,9 +344,9 @@ def ensure_runtime(root):
|
|||||||
|
|
||||||
def delegate(command, argv):
|
def delegate(command, argv):
|
||||||
root = repo_root()
|
root = repo_root()
|
||||||
if command == "clangd":
|
if command in {"clangd", "format"}:
|
||||||
if not runtime_ready(root):
|
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
|
return 1
|
||||||
else:
|
else:
|
||||||
ensure_runtime(root)
|
ensure_runtime(root)
|
||||||
|
|||||||
+26
-20
@@ -17,13 +17,13 @@
|
|||||||
#include <ligo/detail/errors.hpp>
|
#include <ligo/detail/errors.hpp>
|
||||||
#include <ligo/security.hpp>
|
#include <ligo/security.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto json_options = modulus::json_config::options{
|
constexpr auto json_options = modulus::json_config::options{
|
||||||
.category = "ligo",
|
.category = "ligo",
|
||||||
.invalid_argument_code = ligo::detail::error_invalid_argument,
|
.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 {
|
auto protocol_name(ligo::protocol value) -> std::string_view {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
@@ -61,7 +61,7 @@ auto verify_mode_name(ligo::verify_mode value) -> std::string_view {
|
|||||||
return "defaulted";
|
return "defaulted";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parse_security_config(boost::json::value const& value) -> std::expected<ligo::security_config, modulus::error> {
|
auto parse_security_config(boost::json::value const &value) -> std::expected<ligo::security_config, modulus::error> {
|
||||||
auto object = modulus::json_config::require_object(value, "endpoint security", json_options);
|
auto object = modulus::json_config::require_object(value, "endpoint security", json_options);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
return ligo::detail::fail<ligo::security_config>(object.error());
|
return ligo::detail::fail<ligo::security_config>(object.error());
|
||||||
@@ -73,7 +73,8 @@ auto parse_security_config(boost::json::value const& value) -> std::expected<lig
|
|||||||
"ca_file",
|
"ca_file",
|
||||||
"certificate_chain_file",
|
"certificate_chain_file",
|
||||||
"private_key_file",
|
"private_key_file",
|
||||||
}, "endpoint security", json_options);
|
},
|
||||||
|
"endpoint security", json_options);
|
||||||
if (!unknown) {
|
if (!unknown) {
|
||||||
return ligo::detail::fail<ligo::security_config>(unknown.error());
|
return ligo::detail::fail<ligo::security_config>(unknown.error());
|
||||||
}
|
}
|
||||||
@@ -91,7 +92,8 @@ auto parse_security_config(boost::json::value const& value) -> std::expected<lig
|
|||||||
.name = "dtls",
|
.name = "dtls",
|
||||||
.value = ligo::security_mode::DTLS,
|
.value = ligo::security_mode::DTLS,
|
||||||
},
|
},
|
||||||
}, "endpoint security mode must be none, tls, or dtls", json_options);
|
},
|
||||||
|
"endpoint security mode must be none, tls, or dtls", json_options);
|
||||||
if (!mode) {
|
if (!mode) {
|
||||||
return ligo::detail::fail<ligo::security_config>(mode.error());
|
return ligo::detail::fail<ligo::security_config>(mode.error());
|
||||||
}
|
}
|
||||||
@@ -108,7 +110,8 @@ auto parse_security_config(boost::json::value const& value) -> std::expected<lig
|
|||||||
.name = "peer",
|
.name = "peer",
|
||||||
.value = ligo::verify_mode::PEER,
|
.value = ligo::verify_mode::PEER,
|
||||||
},
|
},
|
||||||
}, "endpoint security verify must be defaulted, none, or peer", json_options);
|
},
|
||||||
|
"endpoint security verify must be defaulted, none, or peer", json_options);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
return ligo::detail::fail<ligo::security_config>(verify.error());
|
return ligo::detail::fail<ligo::security_config>(verify.error());
|
||||||
}
|
}
|
||||||
@@ -139,7 +142,7 @@ auto parse_security_config(boost::json::value const& value) -> std::expected<lig
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::validate(ligo::endpoint_config const& config) -> std::expected<void, modulus::error> {
|
auto ligo::validate(ligo::endpoint_config const &config) -> std::expected<void, modulus::error> {
|
||||||
if (config.name.empty()) {
|
if (config.name.empty()) {
|
||||||
return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "endpoint name is required");
|
return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "endpoint name is required");
|
||||||
}
|
}
|
||||||
@@ -161,7 +164,7 @@ auto ligo::validate(ligo::endpoint_config const& config) -> std::expected<void,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::parse_endpoint_config(boost::json::value const& value) -> std::expected<ligo::endpoint_config, modulus::error> {
|
auto ligo::parse_endpoint_config(boost::json::value const &value) -> std::expected<ligo::endpoint_config, modulus::error> {
|
||||||
auto object = modulus::json_config::require_object(value, "endpoint", json_options);
|
auto object = modulus::json_config::require_object(value, "endpoint", json_options);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
return ligo::detail::fail<ligo::endpoint_config>(object.error());
|
return ligo::detail::fail<ligo::endpoint_config>(object.error());
|
||||||
@@ -175,7 +178,8 @@ auto ligo::parse_endpoint_config(boost::json::value const& value) -> std::expect
|
|||||||
"security",
|
"security",
|
||||||
"http",
|
"http",
|
||||||
"udp",
|
"udp",
|
||||||
}, "endpoint", json_options);
|
},
|
||||||
|
"endpoint", json_options);
|
||||||
if (!unknown) {
|
if (!unknown) {
|
||||||
return ligo::detail::fail<ligo::endpoint_config>(unknown.error());
|
return ligo::detail::fail<ligo::endpoint_config>(unknown.error());
|
||||||
}
|
}
|
||||||
@@ -197,7 +201,8 @@ auto ligo::parse_endpoint_config(boost::json::value const& value) -> std::expect
|
|||||||
.name = "udp",
|
.name = "udp",
|
||||||
.value = ligo::protocol::UDP,
|
.value = ligo::protocol::UDP,
|
||||||
},
|
},
|
||||||
}, "endpoint protocol must be http, tcp, or udp", json_options);
|
},
|
||||||
|
"endpoint protocol must be http, tcp, or udp", json_options);
|
||||||
if (!protocol) {
|
if (!protocol) {
|
||||||
return ligo::detail::fail<ligo::endpoint_config>(protocol.error());
|
return ligo::detail::fail<ligo::endpoint_config>(protocol.error());
|
||||||
}
|
}
|
||||||
@@ -249,7 +254,8 @@ auto ligo::parse_endpoint_config(boost::json::value const& value) -> std::expect
|
|||||||
"resend_interval_ms",
|
"resend_interval_ms",
|
||||||
"max_in_flight",
|
"max_in_flight",
|
||||||
"session_timeout_ms",
|
"session_timeout_ms",
|
||||||
}, "endpoint udp", json_options);
|
},
|
||||||
|
"endpoint udp", json_options);
|
||||||
if (!udp_unknown) {
|
if (!udp_unknown) {
|
||||||
return ligo::detail::fail<ligo::endpoint_config>(udp_unknown.error());
|
return ligo::detail::fail<ligo::endpoint_config>(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));
|
return modulus::success(std::move(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::parse_endpoint_configs(boost::json::value const& value) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error> {
|
auto ligo::parse_endpoint_configs(boost::json::value const &value) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error> {
|
||||||
auto object = modulus::json_config::require_object(value, "config root", json_options);
|
auto object = modulus::json_config::require_object(value, "config root", json_options);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(object.error());
|
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(object.error());
|
||||||
@@ -290,7 +296,7 @@ auto ligo::parse_endpoint_configs(boost::json::value const& value) -> std::expec
|
|||||||
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(ligo::detail::error_invalid_argument, "config endpoints array is required");
|
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(ligo::detail::error_invalid_argument, "config endpoints array is required");
|
||||||
}
|
}
|
||||||
auto configs = std::vector<ligo::endpoint_config>{};
|
auto configs = std::vector<ligo::endpoint_config>{};
|
||||||
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);
|
auto parsed = ligo::parse_endpoint_config(endpoint_value);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(parsed.error());
|
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(parsed.error());
|
||||||
@@ -300,7 +306,7 @@ auto ligo::parse_endpoint_configs(boost::json::value const& value) -> std::expec
|
|||||||
return modulus::success(std::move(configs));
|
return modulus::success(std::move(configs));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::load_endpoint_configs(std::string const& path) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error> {
|
auto ligo::load_endpoint_configs(std::string const &path) -> std::expected<std::vector<ligo::endpoint_config>, modulus::error> {
|
||||||
auto value = modulus::json_config::load_value(path, json_options);
|
auto value = modulus::json_config::load_value(path, json_options);
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(value.error());
|
return ligo::detail::fail<std::vector<ligo::endpoint_config>>(value.error());
|
||||||
@@ -308,7 +314,7 @@ auto ligo::load_endpoint_configs(std::string const& path) -> std::expected<std::
|
|||||||
return ligo::parse_endpoint_configs(*value);
|
return ligo::parse_endpoint_configs(*value);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::to_json(ligo::udp_reliability_config const& config) -> boost::json::value {
|
auto ligo::to_json(ligo::udp_reliability_config const &config) -> boost::json::value {
|
||||||
return boost::json::object{
|
return boost::json::object{
|
||||||
{
|
{
|
||||||
"resend_interval_ms",
|
"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{
|
return boost::json::object{
|
||||||
{
|
{
|
||||||
"max_body_size",
|
"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{
|
return boost::json::object{
|
||||||
{
|
{
|
||||||
"mode",
|
"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{
|
return boost::json::object{
|
||||||
{
|
{
|
||||||
"name",
|
"name",
|
||||||
@@ -400,9 +406,9 @@ auto ligo::to_json(ligo::endpoint_config const& config) -> boost::json::value {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::to_json(std::vector<ligo::endpoint_config> const& configs) -> boost::json::value {
|
auto ligo::to_json(std::vector<ligo::endpoint_config> const &configs) -> boost::json::value {
|
||||||
auto endpoints = boost::json::array{};
|
auto endpoints = boost::json::array{};
|
||||||
for (auto const& config : configs) {
|
for (auto const &config : configs) {
|
||||||
endpoints.push_back(ligo::to_json(config));
|
endpoints.push_back(ligo::to_json(config));
|
||||||
}
|
}
|
||||||
return boost::json::object{
|
return boost::json::object{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <modulus.hpp>
|
#include <modulus.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
auto ligo::detail::make_error(std::int32_t code, std::string message, modulus::source_location location) -> modulus::error {
|
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);
|
return modulus::make_error("ligo", code, std::move(message), location);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
#include <boost/beast/core.hpp>
|
#include <boost/beast/core.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
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{};
|
auto ignored = boost::system::error_code{};
|
||||||
stream.socket().cancel(ignored);
|
stream.socket().cancel(ignored);
|
||||||
stream.socket().close(ignored);
|
stream.socket().close(ignored);
|
||||||
|
|||||||
+25
-23
@@ -30,9 +30,10 @@
|
|||||||
#include <ligo/detail/state.hpp>
|
#include <ligo/detail/state.hpp>
|
||||||
#include <ligo/service.hpp>
|
#include <ligo/service.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
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) {
|
if (!error) {
|
||||||
return ligo::detail::error_ok;
|
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) {
|
if (this != &other) {
|
||||||
state_.store(other.state_.exchange(nullptr));
|
state_.store(other.state_.exchange(nullptr));
|
||||||
}
|
}
|
||||||
@@ -64,7 +66,7 @@ ligo::detail::unique_state::operator std::bool_t() const noexcept {
|
|||||||
return static_cast<std::bool_t>(state_);
|
return static_cast<std::bool_t>(state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::detail::unique_state::ignore_state(void* state) -> void {
|
auto ligo::detail::unique_state::ignore_state(void *state) -> void {
|
||||||
static_cast<void>(state);
|
static_cast<void>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,25 +107,25 @@ auto ligo::detail::parse_status_code(std::string_view value) -> std::int32_t {
|
|||||||
return ligo::detail::error_internal;
|
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());
|
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) {
|
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::make_error(ligo::detail::error_timeout, std::move(timeout_message));
|
||||||
}
|
}
|
||||||
return ligo::detail::network_failure(error);
|
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);
|
stream.expires_after(timeout);
|
||||||
return {
|
return {
|
||||||
.cancellation = std::make_shared<boost::asio::cancellation_signal>(),
|
.cancellation = std::make_shared<boost::asio::cancellation_signal>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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{
|
auto deadline = ligo::detail::stream_deadline{
|
||||||
.timer = std::make_shared<boost::asio::steady_timer>(socket.get_executor()),
|
.timer = std::make_shared<boost::asio::steady_timer>(socket.get_executor()),
|
||||||
.timed_out = std::make_shared<std::atomic<std::bool_t>>(false),
|
.timed_out = std::make_shared<std::atomic<std::bool_t>>(false),
|
||||||
@@ -131,7 +133,7 @@ auto ligo::detail::start_stream_deadline(boost::asio::ip::tcp::socket& socket, s
|
|||||||
.cancellation = std::make_shared<boost::asio::cancellation_signal>(),
|
.cancellation = std::make_shared<boost::asio::cancellation_signal>(),
|
||||||
};
|
};
|
||||||
deadline.timer->expires_after(timeout);
|
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)) {
|
if (!error && active->exchange(false, std::memory_order_acq_rel)) {
|
||||||
timed_out->store(true, std::memory_order_release);
|
timed_out->store(true, std::memory_order_release);
|
||||||
cancellation->emit(boost::asio::cancellation_type::terminal);
|
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;
|
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) {
|
if (deadline.active) {
|
||||||
deadline.active->store(false, std::memory_order_release);
|
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::cancellation_slot>(), 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::cancellation_slot>(), 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));
|
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)) {
|
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));
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::detail::report_error(std::function<void(modulus::error)> const& on_error, modulus::error error) -> void {
|
auto ligo::detail::report_error(std::function<void(modulus::error)> const &on_error, modulus::error error) -> void {
|
||||||
if (!on_error) {
|
if (!on_error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -185,7 +187,7 @@ auto ligo::detail::report_error(std::function<void(modulus::error)> const& on_er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::detail::report_error(std::function<void(modulus::error)> const& on_error, std::expected<void, modulus::error> status) -> void {
|
auto ligo::detail::report_error(std::function<void(modulus::error)> const &on_error, std::expected<void, modulus::error> status) -> void {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
ligo::detail::report_error(on_error, status.error());
|
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()) {
|
if (!value.is_object()) {
|
||||||
return ligo::detail::fail<boost::json::value>(ligo::detail::error_invalid_argument, prefix + " response must be an object");
|
return ligo::detail::fail<boost::json::value>(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");
|
auto ok = object.find("ok");
|
||||||
if (ok == object.end() || !ok->value().is_bool()) {
|
if (ok == object.end() || !ok->value().is_bool()) {
|
||||||
return ligo::detail::fail<boost::json::value>(ligo::detail::error_invalid_argument, prefix + " response missing ok flag");
|
return ligo::detail::fail<boost::json::value>(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<std::uint1
|
|||||||
return ligo::detail::fail<std::uint16_t>(ligo::detail::error_invalid_argument, "endpoint port is required");
|
return ligo::detail::fail<std::uint16_t>(ligo::detail::error_invalid_argument, "endpoint port is required");
|
||||||
}
|
}
|
||||||
auto parsed = 0U;
|
auto parsed = 0U;
|
||||||
auto const* begin = text.data();
|
auto const *begin = text.data();
|
||||||
auto const* end = text.data() + text.size();
|
auto const *end = text.data() + text.size();
|
||||||
auto [ptr, error] = std::from_chars(begin, end, parsed);
|
auto [ptr, error] = std::from_chars(begin, end, parsed);
|
||||||
if (error != std::errc{} || ptr != end || parsed > std::numeric_limits<std::uint16_t>::max()) {
|
if (error != std::errc{} || ptr != end || parsed > std::numeric_limits<std::uint16_t>::max()) {
|
||||||
return ligo::detail::fail<std::uint16_t>(ligo::detail::error_invalid_argument, "endpoint port is invalid");
|
return ligo::detail::fail<std::uint16_t>(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);
|
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<std::uint16_t, modulus::error> {
|
auto ligo::detail::start_tcp_acceptor(boost::asio::ip::tcp::acceptor &acceptor, std::string const &host, std::uint16_t port) -> std::expected<std::uint16_t, modulus::error> {
|
||||||
auto close_on_failure = [&acceptor] {
|
auto close_on_failure = [&acceptor] {
|
||||||
auto ignored = boost::system::error_code{};
|
auto ignored = boost::system::error_code{};
|
||||||
acceptor.close(ignored);
|
acceptor.close(ignored);
|
||||||
@@ -361,7 +363,7 @@ auto ligo::detail::start_tcp_acceptor(boost::asio::ip::tcp::acceptor& acceptor,
|
|||||||
return ligo::detail::fail<std::uint16_t>(ligo::detail::error_unavailable, error.message());
|
return ligo::detail::fail<std::uint16_t>(ligo::detail::error_unavailable, error.message());
|
||||||
}
|
}
|
||||||
auto last_error = ligo::detail::unavailable("no TCP bind endpoint resolved");
|
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());
|
auto selected = bind_endpoint(endpoint.endpoint());
|
||||||
if (selected) {
|
if (selected) {
|
||||||
return selected;
|
return selected;
|
||||||
@@ -371,12 +373,12 @@ auto ligo::detail::start_tcp_acceptor(boost::asio::ip::tcp::acceptor& acceptor,
|
|||||||
return ligo::detail::fail<std::uint16_t>(last_error);
|
return ligo::detail::fail<std::uint16_t>(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<std::expected<boost::asio::ip::tcp::resolver::results_type, modulus::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<std::expected<boost::asio::ip::tcp::resolver::results_type, modulus::error>> {
|
||||||
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(executor);
|
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(executor);
|
||||||
auto timer = std::make_shared<boost::asio::steady_timer>(executor);
|
auto timer = std::make_shared<boost::asio::steady_timer>(executor);
|
||||||
auto timed_out = std::make_shared<std::atomic<std::bool_t>>(false);
|
auto timed_out = std::make_shared<std::atomic<std::bool_t>>(false);
|
||||||
timer->expires_after(timeout);
|
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) {
|
if (!error) {
|
||||||
timed_out->store(true, std::memory_order_release);
|
timed_out->store(true, std::memory_order_release);
|
||||||
resolver->cancel();
|
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));
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto ligo::detail::call_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
co_return co_await router.call(std::move(context), std::move(payload));
|
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<std::expected<ligo::service_response, modulus::error>> {
|
auto ligo::detail::call_response_handler(ligo::service_router const &router, ligo::request_context context, boost::json::value payload) -> boost::asio::awaitable<std::expected<ligo::service_response, modulus::error>> {
|
||||||
co_return co_await router.call_response(std::move(context), std::move(payload));
|
co_return co_await router.call_response(std::move(context), std::move(payload));
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-27
@@ -43,6 +43,7 @@
|
|||||||
#include <ligo/security.hpp>
|
#include <ligo/security.hpp>
|
||||||
#include <ligo/service.hpp>
|
#include <ligo/service.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct http_server_state {
|
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;
|
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;
|
return error == boost::beast::http::error::body_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ auto http_verb(ligo::http::method method) -> std::expected<boost::beast::http::v
|
|||||||
return ligo::detail::fail<boost::beast::http::verb>(ligo::detail::error_invalid_argument, "HTTP method is invalid");
|
return ligo::detail::fail<boost::beast::http::verb>(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) {
|
if (request.method != ligo::http::method::GET) {
|
||||||
return true;
|
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();
|
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{};
|
auto value = std::string{};
|
||||||
if (!host.empty() && host.front() == '[' && host.back() == ']') {
|
if (!host.empty() && host.front() == '[' && host.back() == ']') {
|
||||||
value = host;
|
value = host;
|
||||||
@@ -128,30 +129,30 @@ auto host_header(std::string const& host, std::uint16_t port) -> std::string {
|
|||||||
return value;
|
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 endpoint_error = boost::system::error_code{};
|
||||||
auto remote_endpoint = stream.socket().remote_endpoint(endpoint_error);
|
auto remote_endpoint = stream.socket().remote_endpoint(endpoint_error);
|
||||||
return endpoint_error ? std::string{} : remote_endpoint.address().to_string();
|
return endpoint_error ? std::string{} : remote_endpoint.address().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_peer(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& stream) -> std::string {
|
auto remote_peer(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &stream) -> std::string {
|
||||||
auto endpoint_error = boost::system::error_code{};
|
auto endpoint_error = boost::system::error_code{};
|
||||||
auto remote_endpoint = stream.next_layer().remote_endpoint(endpoint_error);
|
auto remote_endpoint = stream.next_layer().remote_endpoint(endpoint_error);
|
||||||
return endpoint_error ? std::string{} : remote_endpoint.address().to_string();
|
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<void> {
|
auto close_http_session(boost::beast::tcp_stream &stream, std::chrono::milliseconds) -> boost::asio::awaitable<void> {
|
||||||
auto ignored = boost::beast::error_code{};
|
auto ignored = boost::beast::error_code{};
|
||||||
stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ignored);
|
stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ignored);
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto close_http_session(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable<void> {
|
auto close_http_session(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable<void> {
|
||||||
static_cast<void>(co_await ligo::detail::async_tls_shutdown(stream, timeout, "HTTP TLS shutdown timed out"));
|
static_cast<void>(co_await ligo::detail::async_tls_shutdown(stream, timeout, "HTTP TLS shutdown timed out"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename STREAM>
|
template <typename STREAM>
|
||||||
auto write_http_failure_response(STREAM& stream, modulus::error status, std::chrono::milliseconds timeout, std::function<void(modulus::error)> const& on_error) -> boost::asio::awaitable<void> {
|
auto write_http_failure_response(STREAM &stream, modulus::error status, std::chrono::milliseconds timeout, std::function<void(modulus::error)> const &on_error) -> boost::asio::awaitable<void> {
|
||||||
auto response = boost::beast::http::response<boost::beast::http::string_body>{};
|
auto response = boost::beast::http::response<boost::beast::http::string_body>{};
|
||||||
response.version(11);
|
response.version(11);
|
||||||
response.set(boost::beast::http::field::content_type, "application/json");
|
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 <typename STREAM>
|
template <typename STREAM>
|
||||||
auto handle_session(STREAM& stream, std::shared_ptr<ligo::service_router const> router, ligo::http::server_options options) -> boost::asio::awaitable<void> {
|
auto handle_session(STREAM &stream, std::shared_ptr<ligo::service_router const> router, ligo::http::server_options options) -> boost::asio::awaitable<void> {
|
||||||
assert(router != nullptr);
|
assert(router != nullptr);
|
||||||
auto buffer = boost::beast::flat_buffer{};
|
auto buffer = boost::beast::flat_buffer{};
|
||||||
auto parser = boost::beast::http::request_parser<boost::beast::http::string_body>{};
|
auto parser = boost::beast::http::request_parser<boost::beast::http::string_body>{};
|
||||||
@@ -287,7 +288,7 @@ auto accept_tls_loop(std::shared_ptr<http_server_state> state) -> boost::asio::a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto http_state(ligo::detail::state_handle const& state) -> std::shared_ptr<http_server_state> {
|
auto http_state(ligo::detail::state_handle const &state) -> std::shared_ptr<http_server_state> {
|
||||||
return state.as<http_server_state>();
|
return state.as<http_server_state>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +296,7 @@ auto uninitialized_http_server() -> std::expected<void, modulus::error> {
|
|||||||
return ligo::detail::fail_void(ligo::detail::unavailable("HTTP server is not initialized"));
|
return ligo::detail::fail_void(ligo::detail::unavailable("HTTP server is not initialized"));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto start_http_server(std::shared_ptr<http_server_state> const& state) -> std::expected<void, modulus::error> {
|
auto start_http_server(std::shared_ptr<http_server_state> const &state) -> std::expected<void, modulus::error> {
|
||||||
assert(!state || state->acceptor != nullptr);
|
assert(!state || state->acceptor != nullptr);
|
||||||
assert(!state || state->router != nullptr);
|
assert(!state || state->router != nullptr);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
@@ -363,7 +364,7 @@ auto stop_http_server(std::shared_ptr<http_server_state> state) -> void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto stop_http_server_now(std::shared_ptr<http_server_state> const& state) -> void {
|
auto stop_http_server_now(std::shared_ptr<http_server_state> const &state) -> void {
|
||||||
auto lock = std::scoped_lock{state->lifecycle_mutex};
|
auto lock = std::scoped_lock{state->lifecycle_mutex};
|
||||||
if (state->stopped.exchange(true)) {
|
if (state->stopped.exchange(true)) {
|
||||||
return;
|
return;
|
||||||
@@ -403,14 +404,14 @@ auto async_stop_http_server(std::shared_ptr<http_server_state> state, std::chron
|
|||||||
co_return co_await state->tls_sessions->wait_empty(timeout);
|
co_return co_await state->tls_sessions->wait_empty(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto selected_http_port(std::shared_ptr<http_server_state> const& state) -> std::uint16_t {
|
auto selected_http_port(std::shared_ptr<http_server_state> const &state) -> std::uint16_t {
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return state->selected_port.load();
|
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<boost::beast::http::string_body> {
|
auto make_http_request_message(ligo::http::endpoint const &endpoint, ligo::http::request const &request, boost::beast::http::verb verb) -> boost::beast::http::request<boost::beast::http::string_body> {
|
||||||
auto http_request = boost::beast::http::request<boost::beast::http::string_body>{
|
auto http_request = boost::beast::http::request<boost::beast::http::string_body>{
|
||||||
verb,
|
verb,
|
||||||
request.target,
|
request.target,
|
||||||
@@ -426,7 +427,7 @@ auto make_http_request_message(ligo::http::endpoint const& endpoint, ligo::http:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename STREAM>
|
template <typename STREAM>
|
||||||
auto read_http_response(STREAM& stream, std::chrono::milliseconds timeout, std::uint64_t max_body_size) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
auto read_http_response(STREAM &stream, std::chrono::milliseconds timeout, std::uint64_t max_body_size) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto buffer = boost::beast::flat_buffer{};
|
auto buffer = boost::beast::flat_buffer{};
|
||||||
auto parser = boost::beast::http::response_parser<boost::beast::http::string_body>{};
|
auto parser = boost::beast::http::response_parser<boost::beast::http::string_body>{};
|
||||||
parser.body_limit(max_body_size);
|
parser.body_limit(max_body_size);
|
||||||
@@ -544,19 +545,23 @@ auto call_http_endpoint(ligo::http::endpoint endpoint, std::shared_ptr<ligo::htt
|
|||||||
co_return co_await read_http_response(stream, options.timeout, options.max_body_size);
|
co_return co_await read_http_response(stream, options.timeout, options.max_body_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
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<boost::asio::ip::tcp::acceptor>(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared<ligo::service_router>(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<boost::asio::ip::tcp::acceptor>(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared<ligo::service_router>(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<std::expected<boost::json::value, modulus::error>> {
|
auto ligo::http::client::call(ligo::http::request const &request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
return call_http_endpoint(endpoint_, std::make_shared<ligo::http::request const>(request), options_);
|
return call_http_endpoint(endpoint_, std::make_shared<ligo::http::request const>(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<http_server_state>(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<http_server_state>(std::move(executor), std::move(endpoint), std::move(router), options)}} {}
|
||||||
|
|
||||||
ligo::http::server::~server() {
|
ligo::http::server::~server() {
|
||||||
if (auto state = http_state(state_)) {
|
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 (this != &other) {
|
||||||
if (auto state = http_state(state_)) {
|
if (auto state = http_state(state_)) {
|
||||||
stop_http_server_now(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_));
|
return selected_http_port(http_state(state_));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::http::client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::http::endpoint, modulus::error> {
|
auto ligo::http::client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::http::endpoint, modulus::error> {
|
||||||
auto parsed = ligo::detail::parse_client_endpoint_text(config.connect);
|
auto parsed = ligo::detail::parse_client_endpoint_text(config.connect);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
return ligo::detail::fail<ligo::http::endpoint>(parsed.error());
|
return ligo::detail::fail<ligo::http::endpoint>(parsed.error());
|
||||||
}
|
}
|
||||||
return modulus::success(ligo::http::endpoint{
|
return modulus::success(ligo::http::endpoint{
|
||||||
.host = std::move(parsed->host),
|
.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<ligo::http::endpoint, modulus::error> {
|
auto ligo::http::server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::http::endpoint, modulus::error> {
|
||||||
auto parsed = ligo::detail::parse_server_endpoint_text(config.bind);
|
auto parsed = ligo::detail::parse_server_endpoint_text(config.bind);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
return ligo::detail::fail<ligo::http::endpoint>(parsed.error());
|
return ligo::detail::fail<ligo::http::endpoint>(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 {
|
return {
|
||||||
.timeout = config.timeout,
|
.timeout = config.timeout,
|
||||||
.max_body_size = config.http.max_body_size,
|
.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 {
|
return {
|
||||||
.timeout = config.timeout,
|
.timeout = config.timeout,
|
||||||
.max_body_size = config.http.max_body_size,
|
.max_body_size = config.http.max_body_size,
|
||||||
|
|||||||
+32
-27
@@ -37,23 +37,23 @@
|
|||||||
#include <ligo/tcp.hpp>
|
#include <ligo/tcp.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
class ligo::net::byte_stream_state {
|
class ligo::net::byte_stream_state {
|
||||||
public:
|
public:
|
||||||
byte_stream_state() = default;
|
byte_stream_state() = default;
|
||||||
byte_stream_state(ligo::net::byte_stream_state const&) = delete;
|
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 &&) noexcept = delete;
|
||||||
virtual ~byte_stream_state() = default;
|
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 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 &&) noexcept -> ligo::net::byte_stream_state & = delete;
|
||||||
virtual auto async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> = 0;
|
virtual auto async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> = 0;
|
||||||
virtual auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> = 0;
|
virtual auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> = 0;
|
||||||
virtual auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> = 0;
|
virtual auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> = 0;
|
||||||
virtual auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> = 0;
|
virtual auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> = 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;
|
virtual auto is_open() const -> std::bool_t = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct net_listener_state {
|
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<std::expected<std::size_t, modulus::error>> override;
|
auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> override;
|
||||||
auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> override;
|
auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> override;
|
||||||
auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> override;
|
auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> 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;
|
auto is_open() const -> std::bool_t override;
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket_{};
|
std::shared_ptr<boost::asio::ip::tcp::socket> socket_{};
|
||||||
@@ -84,18 +84,18 @@ public:
|
|||||||
auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> override;
|
auto async_write_some(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> override;
|
||||||
auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> override;
|
auto async_write_all(boost::asio::const_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> override;
|
||||||
auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> override;
|
auto async_shutdown(std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> 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;
|
auto is_open() const -> std::bool_t override;
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<boost::asio::ssl::context> context_{};
|
std::shared_ptr<boost::asio::ssl::context> context_{};
|
||||||
std::unique_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> stream_{};
|
std::unique_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> stream_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto listener_state(ligo::detail::state_handle const& state) -> std::shared_ptr<net_listener_state> {
|
auto listener_state(ligo::detail::state_handle const &state) -> std::shared_ptr<net_listener_state> {
|
||||||
return state.as<net_listener_state>();
|
return state.as<net_listener_state>();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto close_listener(std::shared_ptr<net_listener_state> const& state) -> void {
|
auto close_listener(std::shared_ptr<net_listener_state> const &state) -> void {
|
||||||
if (!state || state->closed.exchange(true)) {
|
if (!state || state->closed.exchange(true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ auto close_listener(std::shared_ptr<net_listener_state> const& state) -> void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto validate_tls_accept_security(ligo::security_config const& security) -> std::expected<void, modulus::error> {
|
auto validate_tls_accept_security(ligo::security_config const &security) -> std::expected<void, modulus::error> {
|
||||||
if (security.mode != ligo::security_mode::TLS) {
|
if (security.mode != ligo::security_mode::TLS) {
|
||||||
return ligo::detail::fail_void(ligo::unsupported_security("TCP TLS accept", security.mode));
|
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 <typename STREAM>
|
template <typename STREAM>
|
||||||
auto read_some_from(STREAM& stream, boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
auto read_some_from(STREAM &stream, boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
||||||
auto valid = validate_stream_timeout(timeout);
|
auto valid = validate_stream_timeout(timeout);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
co_return ligo::detail::fail<std::size_t>(valid.error());
|
co_return ligo::detail::fail<std::size_t>(valid.error());
|
||||||
@@ -134,7 +134,7 @@ auto read_some_from(STREAM& stream, boost::asio::mutable_buffer buffer, std::chr
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename STREAM>
|
template <typename STREAM>
|
||||||
auto write_some_to(STREAM& stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
auto write_some_to(STREAM &stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
||||||
auto valid = validate_stream_timeout(timeout);
|
auto valid = validate_stream_timeout(timeout);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
co_return ligo::detail::fail<std::size_t>(valid.error());
|
co_return ligo::detail::fail<std::size_t>(valid.error());
|
||||||
@@ -150,7 +150,7 @@ auto write_some_to(STREAM& stream, boost::asio::const_buffer buffer, std::chrono
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename STREAM>
|
template <typename STREAM>
|
||||||
auto write_all_to(STREAM& stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto write_all_to(STREAM &stream, boost::asio::const_buffer buffer, std::chrono::milliseconds timeout, std::string timeout_message) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
auto valid = validate_stream_timeout(timeout);
|
auto valid = validate_stream_timeout(timeout);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
co_return valid;
|
co_return valid;
|
||||||
@@ -185,7 +185,7 @@ auto accept_socket(std::shared_ptr<net_listener_state> state, std::optional<std:
|
|||||||
if (timeout.has_value()) {
|
if (timeout.has_value()) {
|
||||||
timer = std::make_shared<boost::asio::steady_timer>(state->strand);
|
timer = std::make_shared<boost::asio::steady_timer>(state->strand);
|
||||||
timer->expires_after(*timeout);
|
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) {
|
if (!error) {
|
||||||
timed_out->store(true, std::memory_order_release);
|
timed_out->store(true, std::memory_order_release);
|
||||||
auto ignored = boost::system::error_code{};
|
auto ignored = boost::system::error_code{};
|
||||||
@@ -207,7 +207,7 @@ auto accept_socket(std::shared_ptr<net_listener_state> state, std::optional<std:
|
|||||||
co_return modulus::success(ligo::tcp::socket_handle{std::move(socket)});
|
co_return modulus::success(ligo::tcp::socket_handle{std::move(socket)});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto make_server_tls_context(ligo::security_config const& security) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
auto make_server_tls_context(ligo::security_config const &security) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
||||||
auto valid_security = validate_tls_accept_security(security);
|
auto valid_security = validate_tls_accept_security(security);
|
||||||
if (!valid_security) {
|
if (!valid_security) {
|
||||||
return ligo::detail::fail<std::shared_ptr<boost::asio::ssl::context>>(valid_security.error());
|
return ligo::detail::fail<std::shared_ptr<boost::asio::ssl::context>>(valid_security.error());
|
||||||
@@ -227,9 +227,11 @@ auto make_server_tls_context(ligo::security_config const& security) -> std::expe
|
|||||||
return context;
|
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<boost::asio::ip::tcp::socket>(std::move(socket))} {}
|
tcp_byte_stream_state::tcp_byte_stream_state(boost::asio::ip::tcp::socket socket)
|
||||||
|
: socket_{std::make_shared<boost::asio::ip::tcp::socket>(std::move(socket))} {}
|
||||||
|
|
||||||
auto tcp_byte_stream_state::async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
auto tcp_byte_stream_state::async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
||||||
if (!is_open()) {
|
if (!is_open()) {
|
||||||
@@ -272,7 +274,7 @@ auto tcp_byte_stream_state::async_shutdown(std::chrono::milliseconds timeout) ->
|
|||||||
co_return std::expected<void, modulus::error>{};
|
co_return std::expected<void, modulus::error>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
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_) {
|
if (socket_) {
|
||||||
socket_->close(error);
|
socket_->close(error);
|
||||||
}
|
}
|
||||||
@@ -282,7 +284,8 @@ auto tcp_byte_stream_state::is_open() const -> std::bool_t {
|
|||||||
return socket_ && socket_->is_open();
|
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<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(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<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(std::move(released.stream))} {}
|
||||||
|
|
||||||
auto tls_byte_stream_state::async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
auto tls_byte_stream_state::async_read_some(boost::asio::mutable_buffer buffer, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<std::size_t, modulus::error>> {
|
||||||
if (!is_open()) {
|
if (!is_open()) {
|
||||||
@@ -315,7 +318,7 @@ auto tls_byte_stream_state::async_shutdown(std::chrono::milliseconds timeout) ->
|
|||||||
co_return status;
|
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_) {
|
if (stream_) {
|
||||||
stream_->lowest_layer().close(error);
|
stream_->lowest_layer().close(error);
|
||||||
}
|
}
|
||||||
@@ -332,7 +335,7 @@ ligo::net::byte_stream::~byte_stream() {
|
|||||||
close(error);
|
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) {
|
if (this != &other) {
|
||||||
auto error = boost::system::error_code{};
|
auto error = boost::system::error_code{};
|
||||||
close(error);
|
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);
|
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_) {
|
if (state_) {
|
||||||
state_->close(error);
|
state_->close(error);
|
||||||
}
|
}
|
||||||
@@ -402,13 +405,14 @@ auto ligo::net::byte_stream::is_open() const -> std::bool_t {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ligo::net::byte_stream::byte_stream(std::shared_ptr<ligo::net::byte_stream_state> state) : state_{std::move(state)} {}
|
ligo::net::byte_stream::byte_stream(std::shared_ptr<ligo::net::byte_stream_state> state)
|
||||||
|
: state_{std::move(state)} {}
|
||||||
|
|
||||||
ligo::net::listener::~listener() {
|
ligo::net::listener::~listener() {
|
||||||
close();
|
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) {
|
if (this != &other) {
|
||||||
close();
|
close();
|
||||||
state_ = std::move(other.state_);
|
state_ = std::move(other.state_);
|
||||||
@@ -487,7 +491,8 @@ auto ligo::net::listener::close() -> void {
|
|||||||
close_listener(listener_state(state_));
|
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<std::expected<ligo::tcp::socket_handle, modulus::error>> {
|
auto ligo::net::connect_tcp(boost::asio::any_io_executor executor, ligo::tcp::endpoint endpoint, ligo::tcp::client_options options) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>> {
|
||||||
co_return co_await ligo::tcp::connect(std::move(executor), std::move(endpoint), options);
|
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);
|
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<std::expected<ligo::tcp::socket_handle, modulus::error>> {
|
auto ligo::net::connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>> {
|
||||||
co_return co_await ligo::tcp::connect(std::move(executor), config);
|
co_return co_await ligo::tcp::connect(std::move(executor), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -19,6 +19,7 @@
|
|||||||
#include <ligo/detail/errors.hpp>
|
#include <ligo/detail/errors.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
auto ssl_failure(std::int32_t code, std::string message) -> modulus::error {
|
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));
|
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<void, modulus::error> {
|
auto apply_verify_mode(boost::asio::ssl::context &context, ligo::verify_mode verify) -> std::expected<void, modulus::error> {
|
||||||
auto const mode = verify == ligo::verify_mode::PEER || verify == ligo::verify_mode::DEFAULTED ? boost::asio::ssl::verify_peer : boost::asio::ssl::verify_none;
|
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{};
|
auto error = boost::system::error_code{};
|
||||||
context.set_verify_mode(mode, error);
|
context.set_verify_mode(mode, error);
|
||||||
@@ -44,7 +45,7 @@ auto apply_verify_mode(boost::asio::ssl::context& context, ligo::verify_mode ver
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto apply_server_verify_mode(boost::asio::ssl::context& context, ligo::verify_mode verify) -> std::expected<void, modulus::error> {
|
auto apply_server_verify_mode(boost::asio::ssl::context &context, ligo::verify_mode verify) -> std::expected<void, modulus::error> {
|
||||||
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 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{};
|
auto error = boost::system::error_code{};
|
||||||
context.set_verify_mode(mode, error);
|
context.set_verify_mode(mode, error);
|
||||||
@@ -54,7 +55,7 @@ auto apply_server_verify_mode(boost::asio::ssl::context& context, ligo::verify_m
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto load_verify_paths(boost::asio::ssl::context& context, ligo::security_config const& config) -> std::expected<void, modulus::error> {
|
auto load_verify_paths(boost::asio::ssl::context &context, ligo::security_config const &config) -> std::expected<void, modulus::error> {
|
||||||
if (config.verify == ligo::verify_mode::NONE) {
|
if (config.verify == ligo::verify_mode::NONE) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -70,7 +71,7 @@ auto load_verify_paths(boost::asio::ssl::context& context, ligo::security_config
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto load_server_identity(boost::asio::ssl::context& context, ligo::security_config const& config) -> std::expected<void, modulus::error> {
|
auto load_server_identity(boost::asio::ssl::context &context, ligo::security_config const &config) -> std::expected<void, modulus::error> {
|
||||||
if (config.certificate_chain_file.empty() && config.private_key_file.empty()) {
|
if (config.certificate_chain_file.empty() && config.private_key_file.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -92,7 +93,7 @@ auto load_server_identity(boost::asio::ssl::context& context, ligo::security_con
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto make_context(boost::asio::ssl::context::method method, ligo::security_config const& config, std::bool_t server) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
auto make_context(boost::asio::ssl::context::method method, ligo::security_config const &config, std::bool_t server) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
||||||
if (config.mode == ligo::security_mode::DTLS) {
|
if (config.mode == ligo::security_mode::DTLS) {
|
||||||
return ligo::detail::fail<std::shared_ptr<boost::asio::ssl::context>>(ligo::detail::error_invalid_argument, "DTLS config cannot create a TLS context");
|
return ligo::detail::fail<std::shared_ptr<boost::asio::ssl::context>>(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<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
auto ligo::make_tls_client_context(ligo::security_config const &config) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
||||||
return make_context(boost::asio::ssl::context::tls_client, config, false);
|
return make_context(boost::asio::ssl::context::tls_client, config, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::make_tls_server_context(ligo::security_config const& config) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
auto ligo::make_tls_server_context(ligo::security_config const &config) -> std::expected<std::shared_ptr<boost::asio::ssl::context>, modulus::error> {
|
||||||
return make_context(boost::asio::ssl::context::tls_server, config, true);
|
return make_context(boost::asio::ssl::context::tls_server, config, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::apply_tls_client_verification(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& stream, std::string const& host, ligo::security_config const& config) -> std::expected<void, modulus::error> {
|
auto ligo::apply_tls_client_verification(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &stream, std::string const &host, ligo::security_config const &config) -> std::expected<void, modulus::error> {
|
||||||
return ligo::configure_tls_client_stream(stream, host, config);
|
return ligo::configure_tls_client_stream(stream, host, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::configure_tls_client_stream(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& stream, std::string const& host, ligo::security_config const& config) -> std::expected<void, modulus::error> {
|
auto ligo::configure_tls_client_stream(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &stream, std::string const &host, ligo::security_config const &config) -> std::expected<void, modulus::error> {
|
||||||
auto const identity = config.peer_name.empty() ? host : config.peer_name;
|
auto const identity = config.peer_name.empty() ? host : config.peer_name;
|
||||||
if (!identity.empty()) {
|
if (!identity.empty()) {
|
||||||
if (SSL_set_tlsext_host_name(stream.native_handle(), identity.c_str()) != 1) {
|
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<boost::asio::ip:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::validate_tls_server_config(std::string_view protocol, ligo::security_config const& config) -> std::expected<void, modulus::error> {
|
auto ligo::validate_tls_server_config(std::string_view protocol, ligo::security_config const &config) -> std::expected<void, modulus::error> {
|
||||||
if (config.mode != ligo::security_mode::TLS) {
|
if (config.mode != ligo::security_mode::TLS) {
|
||||||
return {};
|
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");
|
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<boost::asio::ssl::context> const& context) -> std::expected<void, modulus::error> {
|
auto ligo::validate_tls_server_context(std::shared_ptr<boost::asio::ssl::context> const &context) -> std::expected<void, modulus::error> {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "TLS server requires an SSL context");
|
return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "TLS server requires an SSL context");
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -18,25 +18,26 @@
|
|||||||
#include <ligo/detail/errors.hpp>
|
#include <ligo/detail/errors.hpp>
|
||||||
#include <ligo/detail/transport.hpp>
|
#include <ligo/detail/transport.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
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;");
|
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_};
|
auto lock = std::scoped_lock{other.mutex_};
|
||||||
handlers_ = other.handlers_;
|
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_};
|
auto lock = std::scoped_lock{other.mutex_};
|
||||||
handlers_ = std::move(other.handlers_);
|
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) {
|
if (this != &other) {
|
||||||
auto lock = std::scoped_lock{
|
auto lock = std::scoped_lock{
|
||||||
mutex_,
|
mutex_,
|
||||||
@@ -47,7 +48,7 @@ auto ligo::service_router::operator=(ligo::service_router const& other) -> ligo:
|
|||||||
return *this;
|
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) {
|
if (this != &other) {
|
||||||
auto lock = std::scoped_lock{
|
auto lock = std::scoped_lock{
|
||||||
mutex_,
|
mutex_,
|
||||||
@@ -109,7 +110,7 @@ auto ligo::service_router::call_response(ligo::request_context context, boost::j
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
co_return co_await (*handler)(std::move(context), std::move(payload));
|
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::service_response>(ligo::detail::error_internal, std::string{"handler failed: "} + error.what());
|
co_return ligo::detail::fail<ligo::service_response>(ligo::detail::error_internal, std::string{"handler failed: "} + error.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
co_return ligo::detail::fail<ligo::service_response>(ligo::detail::error_internal, "handler failed");
|
co_return ligo::detail::fail<ligo::service_response>(ligo::detail::error_internal, "handler failed");
|
||||||
|
|||||||
+38
-30
@@ -46,6 +46,7 @@
|
|||||||
#include <ligo/security.hpp>
|
#include <ligo/security.hpp>
|
||||||
#include <ligo/service.hpp>
|
#include <ligo/service.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct tcp_server_state {
|
struct tcp_server_state {
|
||||||
@@ -81,12 +82,12 @@ auto encode_size(std::uint32_t size) -> std::array<std::uchar_t, 4> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto decode_size(std::array<std::uchar_t, 4> const& bytes) -> std::uint32_t {
|
auto decode_size(std::array<std::uchar_t, 4> const &bytes) -> std::uint32_t {
|
||||||
return (static_cast<std::uint32_t>(bytes[0]) << 24U) | (static_cast<std::uint32_t>(bytes[1]) << 16U) | (static_cast<std::uint32_t>(bytes[2]) << 8U) | static_cast<std::uint32_t>(bytes[3]);
|
return (static_cast<std::uint32_t>(bytes[0]) << 24U) | (static_cast<std::uint32_t>(bytes[1]) << 16U) | (static_cast<std::uint32_t>(bytes[2]) << 8U) | static_cast<std::uint32_t>(bytes[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto read_frame_from(S& stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
auto read_frame_from(S &stream, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto header = std::array<std::uchar_t, 4>{};
|
auto header = std::array<std::uchar_t, 4>{};
|
||||||
auto header_deadline = ligo::detail::start_stream_deadline(stream, timeout);
|
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));
|
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 <typename S>
|
template <typename S>
|
||||||
auto write_frame_to(S& stream, std::string body, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto write_frame_to(S &stream, std::string body, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
if (body.size() > max_frame_size) {
|
if (body.size() > max_frame_size) {
|
||||||
co_return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "frame too large");
|
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<void, modulus::error>{};
|
co_return std::expected<void, modulus::error>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parse_tcp_request(boost::json::value const& value) -> std::expected<parsed_tcp_request, modulus::error> {
|
auto parse_tcp_request(boost::json::value const &value) -> std::expected<parsed_tcp_request, modulus::error> {
|
||||||
if (!value.is_object()) {
|
if (!value.is_object()) {
|
||||||
return ligo::detail::fail<parsed_tcp_request>(ligo::detail::error_invalid_argument, "TCP request must be an object");
|
return ligo::detail::fail<parsed_tcp_request>(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 route = object.find("route");
|
||||||
auto payload = object.find("payload");
|
auto payload = object.find("payload");
|
||||||
if (route == object.end() || !route->value().is_string() || payload == object.end()) {
|
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<parsed_
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto serialize_tcp_request(ligo::tcp::request const& request) -> std::expected<std::string, modulus::error> {
|
auto serialize_tcp_request(ligo::tcp::request const &request) -> std::expected<std::string, modulus::error> {
|
||||||
auto envelope = boost::json::object{};
|
auto envelope = boost::json::object{};
|
||||||
envelope["route"] = request.route;
|
envelope["route"] = request.route;
|
||||||
envelope["payload"] = request.payload;
|
envelope["payload"] = request.payload;
|
||||||
@@ -175,20 +176,20 @@ auto serialize_tcp_request(ligo::tcp::request const& request) -> std::expected<s
|
|||||||
return modulus::success(std::move(body));
|
return modulus::success(std::move(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
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 endpoint_error = boost::system::error_code{};
|
||||||
auto remote_endpoint = stream.socket().remote_endpoint(endpoint_error);
|
auto remote_endpoint = stream.socket().remote_endpoint(endpoint_error);
|
||||||
return endpoint_error ? std::string{} : remote_endpoint.address().to_string();
|
return endpoint_error ? std::string{} : remote_endpoint.address().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_peer(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& stream) -> std::string {
|
auto remote_peer(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &stream) -> std::string {
|
||||||
auto endpoint_error = boost::system::error_code{};
|
auto endpoint_error = boost::system::error_code{};
|
||||||
auto remote_endpoint = stream.next_layer().remote_endpoint(endpoint_error);
|
auto remote_endpoint = stream.next_layer().remote_endpoint(endpoint_error);
|
||||||
return endpoint_error ? std::string{} : remote_endpoint.address().to_string();
|
return endpoint_error ? std::string{} : remote_endpoint.address().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename STREAM>
|
template <typename STREAM>
|
||||||
auto handle_session(STREAM& stream, std::shared_ptr<ligo::service_router const> router, ligo::tcp::server_options options) -> boost::asio::awaitable<void> {
|
auto handle_session(STREAM &stream, std::shared_ptr<ligo::service_router const> router, ligo::tcp::server_options options) -> boost::asio::awaitable<void> {
|
||||||
assert(router != nullptr);
|
assert(router != nullptr);
|
||||||
auto request_value = co_await read_frame_from(stream, options.timeout);
|
auto request_value = co_await read_frame_from(stream, options.timeout);
|
||||||
if (!request_value) {
|
if (!request_value) {
|
||||||
@@ -273,7 +274,7 @@ auto accept_tls_loop(std::shared_ptr<tcp_server_state> state) -> boost::asio::aw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tcp_state(ligo::detail::state_handle const& state) -> std::shared_ptr<tcp_server_state> {
|
auto tcp_state(ligo::detail::state_handle const &state) -> std::shared_ptr<tcp_server_state> {
|
||||||
return state.as<tcp_server_state>();
|
return state.as<tcp_server_state>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +282,7 @@ auto uninitialized_tcp_server() -> std::expected<void, modulus::error> {
|
|||||||
return ligo::detail::fail_void(ligo::detail::unavailable("TCP server is not initialized"));
|
return ligo::detail::fail_void(ligo::detail::unavailable("TCP server is not initialized"));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto start_tcp_server(std::shared_ptr<tcp_server_state> const& state) -> std::expected<void, modulus::error> {
|
auto start_tcp_server(std::shared_ptr<tcp_server_state> const &state) -> std::expected<void, modulus::error> {
|
||||||
assert(!state || state->acceptor != nullptr);
|
assert(!state || state->acceptor != nullptr);
|
||||||
assert(!state || state->router != nullptr);
|
assert(!state || state->router != nullptr);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
@@ -349,7 +350,7 @@ auto stop_tcp_server(std::shared_ptr<tcp_server_state> state) -> void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto stop_tcp_server_now(std::shared_ptr<tcp_server_state> const& state) -> void {
|
auto stop_tcp_server_now(std::shared_ptr<tcp_server_state> const &state) -> void {
|
||||||
auto lock = std::scoped_lock{state->lifecycle_mutex};
|
auto lock = std::scoped_lock{state->lifecycle_mutex};
|
||||||
if (state->stopped.exchange(true)) {
|
if (state->stopped.exchange(true)) {
|
||||||
return;
|
return;
|
||||||
@@ -389,7 +390,7 @@ auto async_stop_tcp_server(std::shared_ptr<tcp_server_state> state, std::chrono:
|
|||||||
co_return co_await state->tls_sessions->wait_empty(timeout);
|
co_return co_await state->tls_sessions->wait_empty(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto selected_tcp_port(std::shared_ptr<tcp_server_state> const& state) -> std::uint16_t {
|
auto selected_tcp_port(std::shared_ptr<tcp_server_state> const &state) -> std::uint16_t {
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return 0;
|
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()});
|
co_return modulus::success(ligo::tcp::socket_handle{stream.release_socket()});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto validate_tls_connect_security(ligo::security_config const& security) -> std::expected<void, modulus::error> {
|
auto validate_tls_connect_security(ligo::security_config const &security) -> std::expected<void, modulus::error> {
|
||||||
if (security.mode == ligo::security_mode::TLS) {
|
if (security.mode == ligo::security_mode::TLS) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return ligo::detail::fail_void(ligo::detail::error_invalid_argument, "TLS connect requires TLS security mode");
|
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<boost::asio::ip::tcp::acceptor>(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared<ligo::service_router>(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<boost::asio::ip::tcp::acceptor>(strand)}, endpoint{std::move(endpoint)}, options{options}, router{std::make_shared<ligo::service_router>(std::move(router))} {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ligo::tcp::socket_handle::socket_handle(boost::asio::ip::tcp::socket socket) : socket_{std::make_shared<boost::asio::ip::tcp::socket>(std::move(socket))} {}
|
ligo::tcp::socket_handle::socket_handle(boost::asio::ip::tcp::socket socket)
|
||||||
|
: socket_{std::make_shared<boost::asio::ip::tcp::socket>(std::move(socket))} {}
|
||||||
|
|
||||||
ligo::tcp::socket_handle::socket_handle(std::shared_ptr<boost::asio::ip::tcp::socket> socket) : socket_{std::move(socket)} {}
|
ligo::tcp::socket_handle::socket_handle(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||||
|
: socket_{std::move(socket)} {}
|
||||||
|
|
||||||
auto ligo::tcp::socket_handle::socket() -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket>, modulus::error> {
|
auto ligo::tcp::socket_handle::socket() -> std::expected<std::reference_wrapper<boost::asio::ip::tcp::socket>, modulus::error> {
|
||||||
if (!socket_) {
|
if (!socket_) {
|
||||||
@@ -522,7 +526,7 @@ auto ligo::tcp::socket_handle::is_open() const -> std::bool_t {
|
|||||||
return socket_ && socket_->is_open();
|
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_) {
|
if (socket_) {
|
||||||
socket_->close(error);
|
socket_->close(error);
|
||||||
}
|
}
|
||||||
@@ -540,7 +544,8 @@ auto ligo::tcp::socket_handle::release_socket() -> std::expected<boost::asio::ip
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ligo::tcp::tls_socket::tls_socket(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ip::tcp::socket socket) : context_{std::move(context)} {
|
ligo::tcp::tls_socket::tls_socket(std::shared_ptr<boost::asio::ssl::context> context, boost::asio::ip::tcp::socket socket)
|
||||||
|
: context_{std::move(context)} {
|
||||||
if (context_) {
|
if (context_) {
|
||||||
stream_ = std::make_unique<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(std::move(socket), *context_);
|
stream_ = std::make_unique<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(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();
|
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_) {
|
if (stream_) {
|
||||||
stream_->lowest_layer().close(error);
|
stream_->lowest_layer().close(error);
|
||||||
}
|
}
|
||||||
@@ -597,9 +602,10 @@ auto ligo::tcp::tls_socket::release_stream() -> std::expected<ligo::tcp::tls_soc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ligo::tcp::client::client(ligo::tcp::endpoint endpoint, ligo::tcp::client_options options) : endpoint_{std::move(endpoint)}, options_{options} {}
|
ligo::tcp::client::client(ligo::tcp::endpoint endpoint, ligo::tcp::client_options options)
|
||||||
|
: endpoint_{std::move(endpoint)}, options_{options} {}
|
||||||
|
|
||||||
auto ligo::tcp::client::call(ligo::tcp::request const& request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
auto ligo::tcp::client::call(ligo::tcp::request const &request) const -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto body = serialize_tcp_request(request);
|
auto body = serialize_tcp_request(request);
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return failed_tcp_call(body.error());
|
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::string const>(std::move(*body)), options_);
|
return call_tcp_endpoint(endpoint_, std::make_shared<std::string const>(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<tcp_server_state>(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<tcp_server_state>(std::move(executor), std::move(endpoint), std::move(router), options)}} {}
|
||||||
|
|
||||||
ligo::tcp::server::~server() {
|
ligo::tcp::server::~server() {
|
||||||
if (auto state = tcp_state(state_)) {
|
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 (this != &other) {
|
||||||
if (auto state = tcp_state(state_)) {
|
if (auto state = tcp_state(state_)) {
|
||||||
stop_tcp_server_now(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_));
|
return selected_tcp_port(tcp_state(state_));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::tcp::client_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::tcp::endpoint, modulus::error> {
|
auto ligo::tcp::client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::tcp::endpoint, modulus::error> {
|
||||||
auto parsed = ligo::detail::parse_client_endpoint_text(config.connect);
|
auto parsed = ligo::detail::parse_client_endpoint_text(config.connect);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
return ligo::detail::fail<ligo::tcp::endpoint>(parsed.error());
|
return ligo::detail::fail<ligo::tcp::endpoint>(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<ligo::tcp::endpoint, modulus::error> {
|
auto ligo::tcp::server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::tcp::endpoint, modulus::error> {
|
||||||
auto parsed = ligo::detail::parse_server_endpoint_text(config.bind);
|
auto parsed = ligo::detail::parse_server_endpoint_text(config.bind);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
return ligo::detail::fail<ligo::tcp::endpoint>(parsed.error());
|
return ligo::detail::fail<ligo::tcp::endpoint>(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 {
|
return {
|
||||||
.timeout = config.timeout,
|
.timeout = config.timeout,
|
||||||
.security = config.security,
|
.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 {
|
return {
|
||||||
.timeout = config.timeout,
|
.timeout = config.timeout,
|
||||||
.on_error = {},
|
.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);
|
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<std::expected<ligo::tcp::socket_handle, modulus::error>> {
|
auto ligo::tcp::connect(boost::asio::any_io_executor executor, ligo::endpoint_config const &config) -> boost::asio::awaitable<std::expected<ligo::tcp::socket_handle, modulus::error>> {
|
||||||
auto endpoint = ligo::tcp::client_endpoint_from_config(config);
|
auto endpoint = ligo::tcp::client_endpoint_from_config(config);
|
||||||
if (!endpoint) {
|
if (!endpoint) {
|
||||||
co_return ligo::detail::fail<ligo::tcp::socket_handle>(endpoint.error());
|
co_return ligo::detail::fail<ligo::tcp::socket_handle>(endpoint.error());
|
||||||
|
|||||||
+61
-57
@@ -48,18 +48,19 @@
|
|||||||
#include <ligo/config.hpp>
|
#include <ligo/config.hpp>
|
||||||
#include <ligo/security.hpp>
|
#include <ligo/security.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct ssl_ctx_deleter {
|
struct ssl_ctx_deleter {
|
||||||
auto operator()(SSL_CTX* context) const noexcept -> void;
|
auto operator()(SSL_CTX *context) const noexcept -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssl_deleter {
|
struct ssl_deleter {
|
||||||
auto operator()(SSL* ssl) const noexcept -> void;
|
auto operator()(SSL *ssl) const noexcept -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bio_deleter {
|
struct bio_deleter {
|
||||||
auto operator()(BIO* bio) const noexcept -> void;
|
auto operator()(BIO *bio) const noexcept -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dtls_state {
|
struct dtls_state {
|
||||||
@@ -108,11 +109,11 @@ struct reliable_channel_state {
|
|||||||
constexpr auto max_datagram_size = std::size_t{65507};
|
constexpr auto max_datagram_size = std::size_t{65507};
|
||||||
constexpr auto max_dtls_plaintext_size = std::size_t{12000};
|
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();
|
return left.address() == right.address() && left.port() == right.port();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto uint_member(boost::json::object const& object, std::string_view name) -> std::optional<std::uint64_t> {
|
auto uint_member(boost::json::object const &object, std::string_view name) -> std::optional<std::uint64_t> {
|
||||||
auto found = object.find(name);
|
auto found = object.find(name);
|
||||||
if (found == object.end() || !found->value().is_number()) {
|
if (found == object.end() || !found->value().is_number()) {
|
||||||
return std::nullopt;
|
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<std::uint64_t>(found->value().as_int64());
|
return found->value().is_uint64() ? found->value().as_uint64() : static_cast<std::uint64_t>(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);
|
auto found = object.find(name);
|
||||||
if (found == object.end() || !found->value().is_string()) {
|
if (found == object.end() || !found->value().is_string()) {
|
||||||
return {};
|
return {};
|
||||||
@@ -151,7 +152,7 @@ auto make_ack(std::uint64_t session_id, std::uint64_t sequence) -> std::string {
|
|||||||
return boost::json::serialize(envelope);
|
return boost::json::serialize(envelope);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto validate_config(ligo::udp_reliability_config const& config) -> std::expected<void, modulus::error> {
|
auto validate_config(ligo::udp_reliability_config const &config) -> std::expected<void, modulus::error> {
|
||||||
if (config.resend_interval <= std::chrono::milliseconds{0}) {
|
if (config.resend_interval <= std::chrono::milliseconds{0}) {
|
||||||
return ligo::detail::fail_void(ligo::detail::invalid_argument("UDP resend_interval must be positive"));
|
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));
|
return dtls_failure(ligo::detail::error_unavailable, std::move(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto validate_security(ligo::security_config const& config, std::bool_t server) -> std::expected<void, modulus::error> {
|
auto validate_security(ligo::security_config const &config, std::bool_t server) -> std::expected<void, modulus::error> {
|
||||||
if (config.mode == ligo::security_mode::TLS) {
|
if (config.mode == ligo::security_mode::TLS) {
|
||||||
return ligo::detail::fail_void(ligo::unsupported_security("UDP", config.mode));
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto load_dtls_verify_paths(SSL_CTX* context, ligo::security_config const& config) -> std::expected<void, modulus::error> {
|
auto load_dtls_verify_paths(SSL_CTX *context, ligo::security_config const &config) -> std::expected<void, modulus::error> {
|
||||||
if (config.verify == ligo::verify_mode::NONE) {
|
if (config.verify == ligo::verify_mode::NONE) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -212,7 +213,7 @@ auto load_dtls_verify_paths(SSL_CTX* context, ligo::security_config const& confi
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto load_dtls_identity(SSL_CTX* context, ligo::security_config const& config) -> std::expected<void, modulus::error> {
|
auto load_dtls_identity(SSL_CTX *context, ligo::security_config const &config) -> std::expected<void, modulus::error> {
|
||||||
if (config.certificate_chain_file.empty() && config.private_key_file.empty()) {
|
if (config.certificate_chain_file.empty() && config.private_key_file.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -228,7 +229,7 @@ auto load_dtls_identity(SSL_CTX* context, ligo::security_config const& config) -
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto make_dtls_state(ligo::security_config const& config, std::bool_t server) -> std::expected<std::unique_ptr<dtls_state>, modulus::error> {
|
auto make_dtls_state(ligo::security_config const &config, std::bool_t server) -> std::expected<std::unique_ptr<dtls_state>, modulus::error> {
|
||||||
if (config.mode != ligo::security_mode::DTLS) {
|
if (config.mode != ligo::security_mode::DTLS) {
|
||||||
return modulus::success(std::unique_ptr<dtls_state>{});
|
return modulus::success(std::unique_ptr<dtls_state>{});
|
||||||
}
|
}
|
||||||
@@ -265,8 +266,8 @@ auto make_dtls_state(ligo::security_config const& config, std::bool_t server) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SSL_set_mtu(ssl.get(), 1200);
|
SSL_set_mtu(ssl.get(), 1200);
|
||||||
auto* ssl_bio = static_cast<BIO*>(nullptr);
|
auto *ssl_bio = static_cast<BIO *>(nullptr);
|
||||||
auto* network_bio = static_cast<BIO*>(nullptr);
|
auto *network_bio = static_cast<BIO *>(nullptr);
|
||||||
if (BIO_new_bio_dgram_pair(&ssl_bio, 0, &network_bio, 0) != 1 || ssl_bio == nullptr || network_bio == 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(ssl_bio);
|
||||||
BIO_free(network_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<std::vector<std::string>, modulus::error> {
|
auto drain_dtls_output(dtls_state &state) -> std::expected<std::vector<std::string>, modulus::error> {
|
||||||
auto output = std::vector<std::string>{};
|
auto output = std::vector<std::string>{};
|
||||||
auto* bio = state.network_bio.get();
|
auto *bio = state.network_bio.get();
|
||||||
while (BIO_ctrl_pending(bio) > 0) {
|
while (BIO_ctrl_pending(bio) > 0) {
|
||||||
auto const pending = static_cast<std::size_t>(BIO_ctrl_pending(bio));
|
auto const pending = static_cast<std::size_t>(BIO_ctrl_pending(bio));
|
||||||
auto datagram = std::string(std::min(pending, max_datagram_size), '\0');
|
auto datagram = std::string(std::min(pending, max_datagram_size), '\0');
|
||||||
@@ -303,18 +304,18 @@ auto drain_dtls_output(dtls_state& state) -> std::expected<std::vector<std::stri
|
|||||||
return modulus::success(std::move(output));
|
return modulus::success(std::move(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto append_dtls_output(std::vector<std::string>& target, dtls_state& state) -> std::expected<void, modulus::error> {
|
auto append_dtls_output(std::vector<std::string> &target, dtls_state &state) -> std::expected<void, modulus::error> {
|
||||||
auto drained = drain_dtls_output(state);
|
auto drained = drain_dtls_output(state);
|
||||||
if (!drained) {
|
if (!drained) {
|
||||||
return ligo::detail::fail_void(drained.error());
|
return ligo::detail::fail_void(drained.error());
|
||||||
}
|
}
|
||||||
for (auto& datagram : *drained) {
|
for (auto &datagram : *drained) {
|
||||||
target.push_back(std::move(datagram));
|
target.push_back(std::move(datagram));
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto run_dtls_handshake(dtls_state& state, std::vector<std::string>& output) -> std::expected<void, modulus::error> {
|
auto run_dtls_handshake(dtls_state &state, std::vector<std::string> &output) -> std::expected<void, modulus::error> {
|
||||||
if (state.handshake_complete) {
|
if (state.handshake_complete) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -331,7 +332,7 @@ auto run_dtls_handshake(dtls_state& state, std::vector<std::string>& output) ->
|
|||||||
return ligo::detail::fail_void(dtls_failure("UDP DTLS handshake failed"));
|
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<std::vector<std::string>, modulus::error> {
|
auto protect_dtls_payload(reliable_channel_state &state, std::string_view plaintext) -> std::expected<std::vector<std::string>, modulus::error> {
|
||||||
if (!state.dtls) {
|
if (!state.dtls) {
|
||||||
return modulus::success(std::vector<std::string>{
|
return modulus::success(std::vector<std::string>{
|
||||||
std::string{plaintext},
|
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));
|
return modulus::success(std::move(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto process_dtls_input(reliable_channel_state& state, std::string_view datagram) -> std::expected<dtls_processed, modulus::error> {
|
auto process_dtls_input(reliable_channel_state &state, std::string_view datagram) -> std::expected<dtls_processed, modulus::error> {
|
||||||
auto processed = dtls_processed{};
|
auto processed = dtls_processed{};
|
||||||
if (!state.dtls) {
|
if (!state.dtls) {
|
||||||
processed.plaintext.push_back(std::string{datagram});
|
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));
|
return modulus::success(std::move(processed));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto channel_state(ligo::detail::state_handle const& handle) -> std::shared_ptr<reliable_channel_state> {
|
auto channel_state(ligo::detail::state_handle const &handle) -> std::shared_ptr<reliable_channel_state> {
|
||||||
return handle.as<reliable_channel_state>();
|
return handle.as<reliable_channel_state>();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto notify_waiters(std::shared_ptr<reliable_channel_state> const& state) -> void {
|
auto notify_waiters(std::shared_ptr<reliable_channel_state> const &state) -> void {
|
||||||
state->notify_timer.cancel();
|
state->notify_timer.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto notify_close_waiters(std::shared_ptr<reliable_channel_state> const& state) -> void {
|
auto notify_close_waiters(std::shared_ptr<reliable_channel_state> const &state) -> void {
|
||||||
state->close_timer.cancel();
|
state->close_timer.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto notify_send_waiters(std::shared_ptr<reliable_channel_state> const& state) -> void {
|
auto notify_send_waiters(std::shared_ptr<reliable_channel_state> const &state) -> void {
|
||||||
for (auto& [_, waiter] : state->ack_waiters) {
|
for (auto &[_, waiter] : state->ack_waiters) {
|
||||||
if (auto timer = waiter.lock()) {
|
if (auto timer = waiter.lock()) {
|
||||||
timer->cancel();
|
timer->cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto send_wire_datagrams(std::shared_ptr<reliable_channel_state> const& state, std::vector<std::string> const& datagrams) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto send_wire_datagrams(std::shared_ptr<reliable_channel_state> const &state, std::vector<std::string> const &datagrams) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
for (auto const& datagram : datagrams) {
|
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)));
|
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) {
|
if (send_error) {
|
||||||
co_return ligo::detail::fail_void(ligo::detail::network_failure(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<reliable_channel_state> const& state, s
|
|||||||
co_return std::expected<void, modulus::error>{};
|
co_return std::expected<void, modulus::error>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto send_ack(std::shared_ptr<reliable_channel_state> const& state, std::uint64_t sequence) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto send_ack(std::shared_ptr<reliable_channel_state> const &state, std::uint64_t sequence) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
auto ack_body = make_ack(state->session_id, sequence);
|
auto ack_body = make_ack(state->session_id, sequence);
|
||||||
auto datagrams = protect_dtls_payload(*state, ack_body);
|
auto datagrams = protect_dtls_payload(*state, ack_body);
|
||||||
if (!datagrams) {
|
if (!datagrams) {
|
||||||
@@ -439,7 +440,7 @@ auto send_ack(std::shared_ptr<reliable_channel_state> const& state, std::uint64_
|
|||||||
co_return co_await send_wire_datagrams(state, *datagrams);
|
co_return co_await send_wire_datagrams(state, *datagrams);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto close_state(std::shared_ptr<reliable_channel_state> const& state) -> void {
|
auto close_state(std::shared_ptr<reliable_channel_state> const &state) -> void {
|
||||||
if (!state || state->closed) {
|
if (!state || state->closed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -503,13 +504,13 @@ auto receive_loop(std::shared_ptr<reliable_channel_state> state) -> boost::asio:
|
|||||||
notify_waiters(state);
|
notify_waiters(state);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (auto& plaintext : processed->plaintext) {
|
for (auto &plaintext : processed->plaintext) {
|
||||||
auto parse_error = boost::system::error_code{};
|
auto parse_error = boost::system::error_code{};
|
||||||
auto envelope = boost::json::parse(plaintext, parse_error);
|
auto envelope = boost::json::parse(plaintext, parse_error);
|
||||||
if (parse_error || !envelope.is_object()) {
|
if (parse_error || !envelope.is_object()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const& object = envelope.as_object();
|
auto const &object = envelope.as_object();
|
||||||
auto session = uint_member(object, "session");
|
auto session = uint_member(object, "session");
|
||||||
auto sequence = uint_member(object, "sequence");
|
auto sequence = uint_member(object, "sequence");
|
||||||
if (!session.has_value() || *session != state->session_id || !sequence.has_value()) {
|
if (!session.has_value() || *session != state->session_id || !sequence.has_value()) {
|
||||||
@@ -563,7 +564,7 @@ auto receive_loop(std::shared_ptr<reliable_channel_state> state) -> boost::asio:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ensure_receive_loop(std::shared_ptr<reliable_channel_state> const& state) -> void {
|
auto ensure_receive_loop(std::shared_ptr<reliable_channel_state> const &state) -> void {
|
||||||
if (state->receive_loop_started || state->closed) {
|
if (state->receive_loop_started || state->closed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -571,7 +572,7 @@ auto ensure_receive_loop(std::shared_ptr<reliable_channel_state> const& state) -
|
|||||||
boost::asio::co_spawn(state->strand, receive_loop(state), boost::asio::detached);
|
boost::asio::co_spawn(state->strand, receive_loop(state), boost::asio::detached);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto begin_operation(std::shared_ptr<reliable_channel_state> const& state) -> std::expected<void, modulus::error> {
|
auto begin_operation(std::shared_ptr<reliable_channel_state> const &state) -> std::expected<void, modulus::error> {
|
||||||
if (state->closed || state->close_requested.load(std::memory_order_acquire)) {
|
if (state->closed || state->close_requested.load(std::memory_order_acquire)) {
|
||||||
return ligo::detail::fail_void(ligo::detail::unavailable("UDP channel closed"));
|
return ligo::detail::fail_void(ligo::detail::unavailable("UDP channel closed"));
|
||||||
}
|
}
|
||||||
@@ -580,7 +581,7 @@ auto begin_operation(std::shared_ptr<reliable_channel_state> const& state) -> st
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto finish_operation(std::shared_ptr<reliable_channel_state> const& state) -> void {
|
auto finish_operation(std::shared_ptr<reliable_channel_state> const &state) -> void {
|
||||||
if (state->active_operations > 0) {
|
if (state->active_operations > 0) {
|
||||||
--state->active_operations;
|
--state->active_operations;
|
||||||
}
|
}
|
||||||
@@ -593,7 +594,7 @@ auto finish_operation(std::shared_ptr<reliable_channel_state> const& state) -> v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto finish_send(std::shared_ptr<reliable_channel_state> const& state, std::uint64_t sequence) -> void {
|
auto finish_send(std::shared_ptr<reliable_channel_state> const &state, std::uint64_t sequence) -> void {
|
||||||
if (state->in_flight > 0) {
|
if (state->in_flight > 0) {
|
||||||
--state->in_flight;
|
--state->in_flight;
|
||||||
}
|
}
|
||||||
@@ -603,7 +604,7 @@ auto finish_send(std::shared_ptr<reliable_channel_state> const& state, std::uint
|
|||||||
finish_operation(state);
|
finish_operation(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto udp_endpoint_from_parts(ligo::detail::endpoint_parts const& parts) -> std::expected<boost::asio::ip::udp::endpoint, modulus::error> {
|
auto udp_endpoint_from_parts(ligo::detail::endpoint_parts const &parts) -> std::expected<boost::asio::ip::udp::endpoint, modulus::error> {
|
||||||
auto error = boost::system::error_code{};
|
auto error = boost::system::error_code{};
|
||||||
auto address = boost::asio::ip::make_address(parts.host, error);
|
auto address = boost::asio::ip::make_address(parts.host, error);
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -704,7 +705,6 @@ auto send_payload_on_strand(std::shared_ptr<reliable_channel_state> state, boost
|
|||||||
finish_send(state, sequence);
|
finish_send(state, sequence);
|
||||||
co_return ligo::detail::fail_void(sent.error());
|
co_return ligo::detail::fail_void(sent.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->acked.erase(sequence) > 0) {
|
if (state->acked.erase(sequence) > 0) {
|
||||||
finish_send(state, sequence);
|
finish_send(state, sequence);
|
||||||
co_return std::expected<void, modulus::error>{};
|
co_return std::expected<void, modulus::error>{};
|
||||||
@@ -813,7 +813,7 @@ auto receive_message(std::shared_ptr<reliable_channel_state> state) -> boost::as
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto local_endpoint_for(std::shared_ptr<reliable_channel_state> const& state) -> std::expected<boost::asio::ip::udp::endpoint, modulus::error> {
|
auto local_endpoint_for(std::shared_ptr<reliable_channel_state> const &state) -> std::expected<boost::asio::ip::udp::endpoint, modulus::error> {
|
||||||
if (!state || !state->socket) {
|
if (!state || !state->socket) {
|
||||||
return ligo::detail::fail<boost::asio::ip::udp::endpoint>(ligo::detail::error_unavailable, "UDP channel is not initialized");
|
return ligo::detail::fail<boost::asio::ip::udp::endpoint>(ligo::detail::error_unavailable, "UDP channel is not initialized");
|
||||||
}
|
}
|
||||||
@@ -830,7 +830,7 @@ auto close_channel(std::shared_ptr<reliable_channel_state> state) -> void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto channel_drained(std::shared_ptr<reliable_channel_state> const& state) -> std::bool_t {
|
auto channel_drained(std::shared_ptr<reliable_channel_state> const &state) -> std::bool_t {
|
||||||
return !state || (state->active_operations == 0 && !state->receive_loop_started);
|
return !state || (state->active_operations == 0 && !state->receive_loop_started);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,7 +842,7 @@ auto async_close_channel_on_strand(std::shared_ptr<reliable_channel_state> state
|
|||||||
auto deadline_timer = std::make_shared<boost::asio::steady_timer>(state->strand);
|
auto deadline_timer = std::make_shared<boost::asio::steady_timer>(state->strand);
|
||||||
auto timed_out = std::make_shared<std::atomic<std::bool_t>>(false);
|
auto timed_out = std::make_shared<std::atomic<std::bool_t>>(false);
|
||||||
deadline_timer->expires_after(timeout);
|
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) {
|
if (!error) {
|
||||||
timed_out->store(true, std::memory_order_release);
|
timed_out->store(true, std::memory_order_release);
|
||||||
notify_close_waiters(state);
|
notify_close_waiters(state);
|
||||||
@@ -876,7 +876,7 @@ auto async_close_channel(std::shared_ptr<reliable_channel_state> state, std::chr
|
|||||||
co_return co_await boost::asio::co_spawn(state->strand, async_close_channel_on_strand(state, timeout), boost::asio::use_awaitable);
|
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<ligo::udp::endpoint, modulus::error> {
|
auto endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::udp::endpoint, modulus::error> {
|
||||||
auto local_parts = ligo::detail::parse_server_endpoint_text(config.bind);
|
auto local_parts = ligo::detail::parse_server_endpoint_text(config.bind);
|
||||||
if (!local_parts) {
|
if (!local_parts) {
|
||||||
return ligo::detail::fail<ligo::udp::endpoint>(local_parts.error());
|
return ligo::detail::fail<ligo::udp::endpoint>(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);
|
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);
|
SSL_free(ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bio_deleter::operator()(BIO* bio) const noexcept -> void {
|
auto bio_deleter::operator()(BIO *bio) const noexcept -> void {
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
reliable_channel_state::reliable_channel_state(std::unique_ptr<boost::asio::ip::udp::socket> 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_state> 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<boost::asio::ip::udp::socket> 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_state> 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());
|
notify_timer.expires_at(std::chrono::steady_clock::time_point::max());
|
||||||
close_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();
|
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) {
|
if (this != &other) {
|
||||||
close();
|
close();
|
||||||
state_ = std::move(other.state_);
|
state_ = std::move(other.state_);
|
||||||
@@ -937,10 +938,11 @@ auto ligo::udp::client::open(boost::asio::any_io_executor executor, boost::asio:
|
|||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
.peer = std::move(peer),
|
.peer = std::move(peer),
|
||||||
}, options);
|
},
|
||||||
|
options);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::udp::client::open(boost::asio::io_context& io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options) -> std::expected<ligo::udp::client, modulus::error> {
|
auto ligo::udp::client::open(boost::asio::io_context &io, boost::asio::ip::udp::endpoint peer, ligo::udp::client_options options) -> std::expected<ligo::udp::client, modulus::error> {
|
||||||
return ligo::udp::client::open(io.get_executor(), std::move(peer), options);
|
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<ligo::udp::client, modulus::error> {
|
auto ligo::udp::client::bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::client_options options) -> std::expected<ligo::udp::client, modulus::error> {
|
||||||
return ligo::udp::client::bind(io.get_executor(), std::move(endpoint), options);
|
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);
|
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() {
|
ligo::udp::server::~server() {
|
||||||
close();
|
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) {
|
if (this != &other) {
|
||||||
close();
|
close();
|
||||||
state_ = std::move(other.state_);
|
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<ligo::udp::server, modulus::error> {
|
auto ligo::udp::server::bind(boost::asio::io_context &io, ligo::udp::endpoint endpoint, ligo::udp::server_options options) -> std::expected<ligo::udp::server, modulus::error> {
|
||||||
return ligo::udp::server::bind(io.get_executor(), std::move(endpoint), options);
|
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);
|
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<ligo::udp::endpoint, modulus::error> {
|
auto ligo::udp::client_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::udp::endpoint, modulus::error> {
|
||||||
return endpoint_from_config(config);
|
return endpoint_from_config(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ligo::udp::server_endpoint_from_config(ligo::endpoint_config const& config) -> std::expected<ligo::udp::endpoint, modulus::error> {
|
auto ligo::udp::server_endpoint_from_config(ligo::endpoint_config const &config) -> std::expected<ligo::udp::endpoint, modulus::error> {
|
||||||
return endpoint_from_config(config);
|
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 {
|
return {
|
||||||
.reliability = config.udp,
|
.reliability = config.udp,
|
||||||
.security = config.security,
|
.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 {
|
return {
|
||||||
.reliability = config.udp,
|
.reliability = config.udp,
|
||||||
.security = config.security,
|
.security = config.security,
|
||||||
|
|||||||
+85
-83
@@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
#include <test.hpp>
|
#include <test.hpp>
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ligo_asserts_follow_build_type) {
|
BOOST_AUTO_TEST_CASE(ligo_asserts_follow_build_type) {
|
||||||
#if defined(LIGO_EXPECT_NDEBUG) && !defined(NDEBUG)
|
#if defined(LIGO_EXPECT_NDEBUG) && !defined(NDEBUG)
|
||||||
BOOST_FAIL("release-style builds must define NDEBUG");
|
BOOST_FAIL("release-style builds must define NDEBUG");
|
||||||
@@ -54,14 +55,13 @@ BOOST_AUTO_TEST_CASE(ligo_asserts_follow_build_type) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
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());
|
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{[&] {
|
auto first = std::thread{[&] {
|
||||||
io.run();
|
io.run();
|
||||||
}};
|
}};
|
||||||
@@ -72,7 +72,7 @@ auto run_two_threads(boost::asio::io_context& io) -> void {
|
|||||||
second.join();
|
second.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto start_io_threads(boost::asio::io_context& io) -> std::vector<std::thread> {
|
auto start_io_threads(boost::asio::io_context &io) -> std::vector<std::thread> {
|
||||||
auto threads = std::vector<std::thread>{};
|
auto threads = std::vector<std::thread>{};
|
||||||
threads.emplace_back([&] {
|
threads.emplace_back([&] {
|
||||||
io.run();
|
io.run();
|
||||||
@@ -83,8 +83,8 @@ auto start_io_threads(boost::asio::io_context& io) -> std::vector<std::thread> {
|
|||||||
return threads;
|
return threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto join_io_threads(std::vector<std::thread>& threads) -> void {
|
auto join_io_threads(std::vector<std::thread> &threads) -> void {
|
||||||
for (auto& thread : threads) {
|
for (auto &thread : threads) {
|
||||||
thread.join();
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto http_client_call(std::string host, std::uint16_t port, ligo::http::request const &request, ligo::http::client_options options = {}) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto client = ligo::http::client{
|
auto client = ligo::http::client{
|
||||||
{
|
{
|
||||||
.host = std::move(host),
|
.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);
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto http_client_call_selected(ligo::http::server &server, ligo::http::request const &request, ligo::http::client_options options = {}) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
return http_client_call("127.0.0.1", server.selected_port(), request, options);
|
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<ligo::http::request const> request, ligo::http::client_options options) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
auto http_client_call_selected_and_stop_impl(ligo::http::server &server, std::shared_ptr<ligo::http::request const> request, ligo::http::client_options options) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto result = co_await http_client_call_selected(server, *request, options);
|
auto result = co_await http_client_call_selected(server, *request, options);
|
||||||
server.stop();
|
server.stop();
|
||||||
co_return result;
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto http_client_call_selected_and_stop(ligo::http::server &server, ligo::http::request const &request, ligo::http::client_options options = {}) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
return http_client_call_selected_and_stop_impl(server, std::make_shared<ligo::http::request const>(request), options);
|
return http_client_call_selected_and_stop_impl(server, std::make_shared<ligo::http::request const>(request), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto http_async_stop_after(ligo::http::server& server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto http_async_stop_after(ligo::http::server &server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
auto timer = boost::asio::steady_timer{co_await boost::asio::this_coro::executor};
|
auto timer = boost::asio::steady_timer{co_await boost::asio::this_coro::executor};
|
||||||
timer.expires_after(delay);
|
timer.expires_after(delay);
|
||||||
co_await timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable));
|
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));
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto raw_http_post_selected_and_stop(ligo::http::server &server, std::string target, std::string body) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto result = co_await raw_http_post(server.selected_port(), std::move(target), std::move(body));
|
auto result = co_await raw_http_post(server.selected_port(), std::move(target), std::move(body));
|
||||||
server.stop();
|
server.stop();
|
||||||
co_return result;
|
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));
|
co_return modulus::success(std::move(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto raw_http_get_selected_and_stop(ligo::http::server& server, std::string target) -> boost::asio::awaitable<std::expected<boost::beast::http::response<boost::beast::http::string_body>, modulus::error>> {
|
auto raw_http_get_selected_and_stop(ligo::http::server &server, std::string target) -> boost::asio::awaitable<std::expected<boost::beast::http::response<boost::beast::http::string_body>, modulus::error>> {
|
||||||
auto result = co_await raw_http_get(server.selected_port(), std::move(target));
|
auto result = co_await raw_http_get(server.selected_port(), std::move(target));
|
||||||
server.stop();
|
server.stop();
|
||||||
co_return result;
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto tcp_client_call(std::string host, std::uint16_t port, ligo::tcp::request const &request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto client = ligo::tcp::client{
|
auto client = ligo::tcp::client{
|
||||||
{
|
{
|
||||||
.host = std::move(host),
|
.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);
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto tcp_client_call_selected(ligo::tcp::server &server, ligo::tcp::request const &request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
return tcp_client_call("127.0.0.1", server.selected_port(), request, options);
|
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<ligo::tcp::request const> request, ligo::tcp::client_options options) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
auto tcp_client_call_selected_and_stop_impl(ligo::tcp::server &server, std::shared_ptr<ligo::tcp::request const> request, ligo::tcp::client_options options) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto result = co_await tcp_client_call_selected(server, *request, options);
|
auto result = co_await tcp_client_call_selected(server, *request, options);
|
||||||
server.stop();
|
server.stop();
|
||||||
co_return result;
|
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<std::expected<boost::json::value, modulus::error>> {
|
auto tcp_client_call_selected_and_stop(ligo::tcp::server &server, ligo::tcp::request const &request, ligo::tcp::client_options options = {}) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
return tcp_client_call_selected_and_stop_impl(server, std::make_shared<ligo::tcp::request const>(request), options);
|
return tcp_client_call_selected_and_stop_impl(server, std::make_shared<ligo::tcp::request const>(request), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tcp_async_stop_after(ligo::tcp::server& server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
auto tcp_async_stop_after(ligo::tcp::server &server, std::chrono::milliseconds delay, std::chrono::milliseconds timeout) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||||
auto timer = boost::asio::steady_timer{co_await boost::asio::this_coro::executor};
|
auto timer = boost::asio::steady_timer{co_await boost::asio::this_coro::executor};
|
||||||
timer.expires_after(delay);
|
timer.expires_after(delay);
|
||||||
co_await timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable));
|
co_await timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable));
|
||||||
@@ -405,7 +405,7 @@ auto accept_and_hold(std::shared_ptr<boost::asio::ip::tcp::acceptor> acceptor, s
|
|||||||
co_await timer.async_wait(boost::asio::as_tuple(boost::asio::use_awaitable));
|
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<boost::asio::ip::udp::socket> {
|
auto make_udp_socket(boost::asio::io_context &io) -> std::unique_ptr<boost::asio::ip::udp::socket> {
|
||||||
return std::make_unique<boost::asio::ip::udp::socket>(io, boost::asio::ip::udp::endpoint{
|
return std::make_unique<boost::asio::ip::udp::socket>(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
@@ -419,17 +419,18 @@ auto udp_client_adopt(std::unique_ptr<boost::asio::ip::udp::socket> socket, boos
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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<ligo::udp::client, modulus::error> {
|
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<ligo::udp::client, modulus::error> {
|
||||||
return ligo::udp::client::bind(io, {
|
return ligo::udp::client::bind(io, {
|
||||||
.local = std::move(local),
|
.local = std::move(local),
|
||||||
.peer = std::move(peer),
|
.peer = std::move(peer),
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
.reliability = config,
|
.reliability = config,
|
||||||
.session_id = session_id,
|
.session_id = session_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto config_http_tcp_calls_and_stop(ligo::http::server& http_server, ligo::tcp::server& tcp_server) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
auto config_http_tcp_calls_and_stop(ligo::http::server &http_server, ligo::tcp::server &tcp_server) -> boost::asio::awaitable<std::expected<boost::json::value, modulus::error>> {
|
||||||
auto tcp_payload = boost::json::object{};
|
auto tcp_payload = boost::json::object{};
|
||||||
tcp_payload["ok"] = true;
|
tcp_payload["ok"] = true;
|
||||||
auto tcp_request = std::make_shared<ligo::tcp::request>();
|
auto tcp_request = std::make_shared<ligo::tcp::request>();
|
||||||
@@ -472,7 +473,8 @@ BOOST_AUTO_TEST_CASE(ligo_config_drives_http_tcp_and_udp_setup) {
|
|||||||
};
|
};
|
||||||
auto config_text = std::string{
|
auto config_text = std::string{
|
||||||
"{\"endpoints\":[",
|
"{\"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}}" + "]}";
|
} +
|
||||||
|
"{\"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));
|
auto configs = ligo::parse_endpoint_configs(boost::json::parse(config_text));
|
||||||
BOOST_REQUIRE(configs);
|
BOOST_REQUIRE(configs);
|
||||||
BOOST_REQUIRE((configs->size()) == (4u));
|
BOOST_REQUIRE((configs->size()) == (4u));
|
||||||
@@ -625,8 +627,7 @@ BOOST_AUTO_TEST_CASE(ligo_http_post_round_trip_dispatches_json_handler) {
|
|||||||
{
|
{
|
||||||
.target = "/echo",
|
.target = "/echo",
|
||||||
.payload = boost::json::parse(R"json({"ok":true})json"),
|
.payload = boost::json::parse(R"json({"ok":true})json"),
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
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},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
.security = test_tls_client_config(),
|
.security = test_tls_client_config(),
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
@@ -766,7 +766,8 @@ BOOST_AUTO_TEST_CASE(ligo_http_get_round_trip_dispatches_method_and_route) {
|
|||||||
auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, {
|
auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, {
|
||||||
.method = ligo::http::method::GET,
|
.method = ligo::http::method::GET,
|
||||||
.target = "/method",
|
.target = "/method",
|
||||||
}), boost::asio::use_future);
|
}),
|
||||||
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_REQUIRE(result);
|
BOOST_REQUIRE(result);
|
||||||
@@ -788,7 +789,8 @@ BOOST_AUTO_TEST_CASE(ligo_http_missing_route_returns_status) {
|
|||||||
auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, {
|
auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, {
|
||||||
.target = "/missing",
|
.target = "/missing",
|
||||||
.payload = boost::json::object{},
|
.payload = boost::json::object{},
|
||||||
}), boost::asio::use_future);
|
}),
|
||||||
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_CHECK(!(result));
|
BOOST_CHECK(!(result));
|
||||||
@@ -813,7 +815,8 @@ BOOST_AUTO_TEST_CASE(ligo_http_handler_failure_returns_status) {
|
|||||||
auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, {
|
auto future = boost::asio::co_spawn(io, http_client_call_selected_and_stop(server, {
|
||||||
.target = "/boom",
|
.target = "/boom",
|
||||||
.payload = boost::json::object{},
|
.payload = boost::json::object{},
|
||||||
}), boost::asio::use_future);
|
}),
|
||||||
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_CHECK(!(result));
|
BOOST_CHECK(!(result));
|
||||||
@@ -895,8 +898,7 @@ BOOST_AUTO_TEST_CASE(ligo_http_client_rejects_oversized_response_body) {
|
|||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
.max_body_size = 32,
|
.max_body_size = 32,
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
@@ -934,9 +936,10 @@ BOOST_AUTO_TEST_CASE(ligo_http_concurrent_client_calls_succeed) {
|
|||||||
futures.push_back(boost::asio::co_spawn(io, client.call({
|
futures.push_back(boost::asio::co_spawn(io, client.call({
|
||||||
.target = "/echo",
|
.target = "/echo",
|
||||||
.payload = std::move(payload),
|
.payload = std::move(payload),
|
||||||
}), boost::asio::use_future));
|
}),
|
||||||
|
boost::asio::use_future));
|
||||||
}
|
}
|
||||||
for (auto& future : futures) {
|
for (auto &future : futures) {
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_REQUIRE(result);
|
BOOST_REQUIRE(result);
|
||||||
BOOST_CHECK(result->is_object());
|
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},
|
.timeout = std::chrono::milliseconds{200},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
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);
|
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);
|
run_two_threads(io);
|
||||||
@@ -1002,8 +1004,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_round_trip_dispatches_json_handler) {
|
|||||||
{
|
{
|
||||||
.route = "echo",
|
.route = "echo",
|
||||||
.payload = boost::json::parse(R"json({"ok":true})json"),
|
.payload = boost::json::parse(R"json({"ok":true})json"),
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
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},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
.security = test_tls_client_config(),
|
.security = test_tls_client_config(),
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
@@ -1085,12 +1085,11 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_verified_peer_succeeds) {
|
|||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
.security = test_tls_verified_client_config("localhost"),
|
.security = test_tls_verified_client_config("localhost"),
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
auto stopper = boost::asio::steady_timer{io};
|
auto stopper = boost::asio::steady_timer{io};
|
||||||
stopper.expires_after(std::chrono::milliseconds{200});
|
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();
|
server.stop();
|
||||||
});
|
});
|
||||||
io.run();
|
io.run();
|
||||||
@@ -1132,12 +1131,11 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_hostname_mismatch_fails) {
|
|||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
.security = test_tls_verified_client_config("wrong.local"),
|
.security = test_tls_verified_client_config("wrong.local"),
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
auto stopper = boost::asio::steady_timer{io};
|
auto stopper = boost::asio::steady_timer{io};
|
||||||
stopper.expires_after(std::chrono::milliseconds{200});
|
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();
|
server.stop();
|
||||||
});
|
});
|
||||||
io.run();
|
io.run();
|
||||||
@@ -1206,7 +1204,8 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_missing_route_returns_status) {
|
|||||||
auto future = boost::asio::co_spawn(io, tcp_client_call_selected_and_stop(server, {
|
auto future = boost::asio::co_spawn(io, tcp_client_call_selected_and_stop(server, {
|
||||||
.route = "missing",
|
.route = "missing",
|
||||||
.payload = boost::json::object{},
|
.payload = boost::json::object{},
|
||||||
}), boost::asio::use_future);
|
}),
|
||||||
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_CHECK(!(result));
|
BOOST_CHECK(!(result));
|
||||||
@@ -1231,7 +1230,8 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_handler_failure_returns_status) {
|
|||||||
auto future = boost::asio::co_spawn(io, tcp_client_call_selected_and_stop(server, {
|
auto future = boost::asio::co_spawn(io, tcp_client_call_selected_and_stop(server, {
|
||||||
.route = "boom",
|
.route = "boom",
|
||||||
.payload = boost::json::object{},
|
.payload = boost::json::object{},
|
||||||
}), boost::asio::use_future);
|
}),
|
||||||
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_CHECK(!(result));
|
BOOST_CHECK(!(result));
|
||||||
@@ -1243,7 +1243,8 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_connection_refused_returns_unavailable) {
|
|||||||
auto future = boost::asio::co_spawn(io, tcp_client_call("127.0.0.1", 9, {
|
auto future = boost::asio::co_spawn(io, tcp_client_call("127.0.0.1", 9, {
|
||||||
.route = "echo",
|
.route = "echo",
|
||||||
.payload = boost::json::object{},
|
.payload = boost::json::object{},
|
||||||
}), boost::asio::use_future);
|
}),
|
||||||
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_CHECK(!(result));
|
BOOST_CHECK(!(result));
|
||||||
@@ -1269,8 +1270,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_stalled_peer_times_out) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{20},
|
.timeout = std::chrono::milliseconds{20},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
@@ -1308,9 +1308,10 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_concurrent_client_calls_succeed) {
|
|||||||
futures.push_back(boost::asio::co_spawn(io, client.call({
|
futures.push_back(boost::asio::co_spawn(io, client.call({
|
||||||
.route = "echo",
|
.route = "echo",
|
||||||
.payload = std::move(payload),
|
.payload = std::move(payload),
|
||||||
}), boost::asio::use_future));
|
}),
|
||||||
|
boost::asio::use_future));
|
||||||
}
|
}
|
||||||
for (auto& future : futures) {
|
for (auto &future : futures) {
|
||||||
auto result = future.get();
|
auto result = future.get();
|
||||||
BOOST_REQUIRE(result);
|
BOOST_REQUIRE(result);
|
||||||
BOOST_CHECK(result->is_object());
|
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},
|
.timeout = std::chrono::milliseconds{200},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
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);
|
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);
|
run_two_threads(io);
|
||||||
@@ -1372,8 +1372,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_connect_returns_connected_socket) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto socket = result.get();
|
auto socket = result.get();
|
||||||
@@ -1401,8 +1400,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_connect_returns_connected_socket) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto socket = result.get();
|
auto socket = result.get();
|
||||||
@@ -1432,8 +1430,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_listener_accept_returns_socket) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto accepted_socket = accepted.get();
|
auto accepted_socket = accepted.get();
|
||||||
@@ -1467,8 +1464,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_byte_stream_round_trips_over_tcp) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto accepted_socket = accepted.get();
|
auto accepted_socket = accepted.get();
|
||||||
@@ -1506,7 +1502,9 @@ BOOST_AUTO_TEST_CASE(ligo_net_listener_tls_accept_rejects_non_tls_security_modes
|
|||||||
auto listener = std::move(*listener_result);
|
auto listener = std::move(*listener_result);
|
||||||
auto none = boost::asio::co_spawn(io, listener.async_accept_tls_configured({
|
auto none = boost::asio::co_spawn(io, listener.async_accept_tls_configured({
|
||||||
.mode = ligo::security_mode::NONE,
|
.mode = ligo::security_mode::NONE,
|
||||||
}, std::chrono::milliseconds{1000}), boost::asio::use_future);
|
},
|
||||||
|
std::chrono::milliseconds{1000}),
|
||||||
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = none.get();
|
auto result = none.get();
|
||||||
BOOST_CHECK(!result);
|
BOOST_CHECK(!result);
|
||||||
@@ -1534,8 +1532,7 @@ BOOST_AUTO_TEST_CASE(ligo_net_listener_tls_handshake_succeeds) {
|
|||||||
{
|
{
|
||||||
.timeout = std::chrono::milliseconds{1000},
|
.timeout = std::chrono::milliseconds{1000},
|
||||||
},
|
},
|
||||||
test_tls_client_config()
|
test_tls_client_config()),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto accepted_socket = accepted.get();
|
auto accepted_socket = accepted.get();
|
||||||
@@ -1565,8 +1562,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_raw_connect_rejects_secure_modes) {
|
|||||||
.security = {
|
.security = {
|
||||||
.mode = ligo::security_mode::TLS,
|
.mode = ligo::security_mode::TLS,
|
||||||
},
|
},
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto result = future.get();
|
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,
|
.mode = ligo::security_mode::NONE,
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
auto dtls = boost::asio::co_spawn(
|
auto dtls = boost::asio::co_spawn(
|
||||||
io,
|
io,
|
||||||
@@ -1605,8 +1600,7 @@ BOOST_AUTO_TEST_CASE(ligo_tcp_tls_connect_rejects_non_tls_security_modes) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.mode = ligo::security_mode::DTLS,
|
.mode = ligo::security_mode::DTLS,
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
boost::asio::use_future);
|
boost::asio::use_future);
|
||||||
io.run();
|
io.run();
|
||||||
auto none_result = none.get();
|
auto none_result = none.get();
|
||||||
@@ -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 received = boost::asio::co_spawn(io, server.receive(), boost::asio::use_future);
|
||||||
auto stopper = boost::asio::steady_timer{io};
|
auto stopper = boost::asio::steady_timer{io};
|
||||||
stopper.expires_after(std::chrono::milliseconds{200});
|
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();
|
client.close();
|
||||||
server.close();
|
server.close();
|
||||||
});
|
});
|
||||||
@@ -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 received = boost::asio::co_spawn(io, server.receive(), boost::asio::use_future);
|
||||||
auto stopper = boost::asio::steady_timer{io};
|
auto stopper = boost::asio::steady_timer{io};
|
||||||
stopper.expires_after(std::chrono::milliseconds{200});
|
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();
|
client.close();
|
||||||
server.close();
|
server.close();
|
||||||
});
|
});
|
||||||
@@ -1898,7 +1892,8 @@ BOOST_AUTO_TEST_CASE(ligo_udp_dtls_server_requires_identity) {
|
|||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
.peer = peer,
|
.peer = peer,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
.security = {
|
.security = {
|
||||||
.mode = ligo::security_mode::DTLS,
|
.mode = ligo::security_mode::DTLS,
|
||||||
},
|
},
|
||||||
@@ -1998,7 +1993,8 @@ BOOST_AUTO_TEST_CASE(ligo_udp_wrong_session_times_out) {
|
|||||||
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
}, receiver_endpoint, config, 7);
|
},
|
||||||
|
receiver_endpoint, config, 7);
|
||||||
BOOST_REQUIRE(channel_result);
|
BOOST_REQUIRE(channel_result);
|
||||||
auto channel = std::move(*channel_result);
|
auto channel = std::move(*channel_result);
|
||||||
auto future = boost::asio::co_spawn(io, channel.send(boost::json::object{}), boost::asio::use_future);
|
auto future = boost::asio::co_spawn(io, channel.send(boost::json::object{}), boost::asio::use_future);
|
||||||
@@ -2024,7 +2020,8 @@ BOOST_AUTO_TEST_CASE(ligo_udp_oversized_payload_returns_invalid_argument) {
|
|||||||
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
}, receiver_endpoint);
|
},
|
||||||
|
receiver_endpoint);
|
||||||
BOOST_REQUIRE(channel_result);
|
BOOST_REQUIRE(channel_result);
|
||||||
auto channel = std::move(*channel_result);
|
auto channel = std::move(*channel_result);
|
||||||
auto payload = boost::json::value{
|
auto payload = boost::json::value{
|
||||||
@@ -2053,13 +2050,14 @@ BOOST_AUTO_TEST_CASE(ligo_udp_close_wakes_pending_receive) {
|
|||||||
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
}, right_endpoint);
|
},
|
||||||
|
right_endpoint);
|
||||||
BOOST_REQUIRE(channel_result);
|
BOOST_REQUIRE(channel_result);
|
||||||
auto channel = std::move(*channel_result);
|
auto channel = std::move(*channel_result);
|
||||||
auto received = boost::asio::co_spawn(io, channel.receive(), boost::asio::use_future);
|
auto received = boost::asio::co_spawn(io, channel.receive(), boost::asio::use_future);
|
||||||
auto timer = boost::asio::steady_timer{io};
|
auto timer = boost::asio::steady_timer{io};
|
||||||
timer.expires_after(std::chrono::milliseconds{5});
|
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();
|
channel.close();
|
||||||
});
|
});
|
||||||
io.run();
|
io.run();
|
||||||
@@ -2084,7 +2082,8 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_drains_pending_receive) {
|
|||||||
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
}, right_endpoint);
|
},
|
||||||
|
right_endpoint);
|
||||||
BOOST_REQUIRE(channel_result);
|
BOOST_REQUIRE(channel_result);
|
||||||
auto channel = std::move(*channel_result);
|
auto channel = std::move(*channel_result);
|
||||||
auto received = boost::asio::co_spawn(io, channel.receive(), boost::asio::use_future);
|
auto received = boost::asio::co_spawn(io, channel.receive(), boost::asio::use_future);
|
||||||
@@ -2117,7 +2116,8 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_drains_pending_send) {
|
|||||||
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
}, receiver_endpoint, config, 171);
|
},
|
||||||
|
receiver_endpoint, config, 171);
|
||||||
BOOST_REQUIRE(channel_result);
|
BOOST_REQUIRE(channel_result);
|
||||||
auto channel = std::move(*channel_result);
|
auto channel = std::move(*channel_result);
|
||||||
auto sent = boost::asio::co_spawn(io, channel.send(boost::json::object{}), boost::asio::use_future);
|
auto sent = boost::asio::co_spawn(io, channel.send(boost::json::object{}), boost::asio::use_future);
|
||||||
@@ -2145,7 +2145,8 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_moved_from_channel_is_ok) {
|
|||||||
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
}, right_endpoint);
|
},
|
||||||
|
right_endpoint);
|
||||||
BOOST_REQUIRE(channel_result);
|
BOOST_REQUIRE(channel_result);
|
||||||
auto channel = std::move(*channel_result);
|
auto channel = std::move(*channel_result);
|
||||||
auto moved = std::move(channel);
|
auto moved = std::move(channel);
|
||||||
@@ -2171,7 +2172,8 @@ BOOST_AUTO_TEST_CASE(ligo_udp_async_close_rejects_invalid_timeout) {
|
|||||||
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
auto channel_result = udp_client_bind(io, boost::asio::ip::udp::endpoint{
|
||||||
boost::asio::ip::udp::v4(),
|
boost::asio::ip::udp::v4(),
|
||||||
0,
|
0,
|
||||||
}, right_endpoint);
|
},
|
||||||
|
right_endpoint);
|
||||||
BOOST_REQUIRE(channel_result);
|
BOOST_REQUIRE(channel_result);
|
||||||
auto channel = std::move(*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);
|
auto closed = boost::asio::co_spawn(io, channel.async_close(std::chrono::milliseconds{0}), boost::asio::use_future);
|
||||||
|
|||||||
Reference in New Issue
Block a user