From a33650f2e9727c0d23386bc03823f5249be1a34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 4 Aug 2025 22:17:49 +0100 Subject: [PATCH 01/10] started to add some TAPS classes --- examples/CMakeLists.txt | 1 + examples/taps.cpp | 17 ++++++ include/beman/net/detail/local_endpoint.hpp | 56 +++++++++++++++++++ include/beman/net/detail/preconnection.hpp | 42 ++++++++++++++ include/beman/net/detail/remote_endpoint.hpp | 50 +++++++++++++++++ include/beman/net/detail/security_props.hpp | 22 ++++++++ .../beman/net/detail/transport_preference.hpp | 13 +++++ include/beman/net/detail/transport_props.hpp | 22 ++++++++ include/beman/net/net.hpp | 7 +++ 9 files changed, 230 insertions(+) create mode 100644 examples/taps.cpp create mode 100644 include/beman/net/detail/local_endpoint.hpp create mode 100644 include/beman/net/detail/preconnection.hpp create mode 100644 include/beman/net/detail/remote_endpoint.hpp create mode 100644 include/beman/net/detail/security_props.hpp create mode 100644 include/beman/net/detail/transport_preference.hpp create mode 100644 include/beman/net/detail/transport_props.hpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b4ac76f..b0eff20 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,6 +4,7 @@ # cmake-format: on set(EXAMPLES + taps client cppcon-2024 empty diff --git a/examples/taps.cpp b/examples/taps.cpp new file mode 100644 index 0000000..7b05123 --- /dev/null +++ b/examples/taps.cpp @@ -0,0 +1,17 @@ +// examples/taps.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +namespace net = beman::net; + +// ---------------------------------------------------------------------------- + +int main(int ac, char* av[]) { + net::preconnection pre( + net::remote_endpoint().with_hostname(1 < ac ? av[1] : "example.com").with_port(2 < ac ? std::stoi(av[2]) : 80), + {}); + + // pre.connect() +} \ No newline at end of file diff --git a/include/beman/net/detail/local_endpoint.hpp b/include/beman/net/detail/local_endpoint.hpp new file mode 100644 index 0000000..dc2e117 --- /dev/null +++ b/include/beman/net/detail/local_endpoint.hpp @@ -0,0 +1,56 @@ +// include/beman/net/detail/local_endpoint.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_LOCAL_ENDPOINT +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_LOCAL_ENDPOINT + +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +class local_endpoint; +} + +class beman::net::detail::local_endpoint { + public: + local_endpoint() = default; + + auto hostname() const -> std::string { return this->_hostname; } + auto with_hostname(const std::string& hostname) -> local_endpoint& { + this->_hostname = hostname; + return *this; + } + auto port() const -> std::uint16_t { return this->_port; } + auto with_port(std::uint16_t port) -> local_endpoint& { + this->_port = port; + return *this; + } + auto service() const -> std::string { return this->_service; } + auto with_service(const std::string& service) -> local_endpoint& { + this->_service = service; + return *this; + } + auto ip_address() const -> std::string { return this->_ip_address; } + auto with_ip_address(const std::string& ip_address) -> local_endpoint& { + this->_ip_address = ip_address; + return *this; + } + + auto interface() const -> std::string { return this->_interface; } + auto with_interface(const std::string& interface) -> local_endpoint& { + this->_interface = interface; + return *this; + } + + private: + std::string _hostname; + std::uint16_t _port{}; + std::string _service{}; + std::string _ip_address{}; + std::string _interface; +}; + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/preconnection.hpp b/include/beman/net/detail/preconnection.hpp new file mode 100644 index 0000000..0922d73 --- /dev/null +++ b/include/beman/net/detail/preconnection.hpp @@ -0,0 +1,42 @@ +// include/beman/net/detail/preconnection.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_PRECONNECTION +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_PRECONNECTION + +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +class preconnection; +} +namespace beman::net { +using preconnection = beman::net::detail::preconnection; +} + +// ---------------------------------------------------------------------------- + +class beman::net::detail::preconnection { + public: + preconnection(const remote_endpoint& re, const transport_props& tp = {}, const security_props& sp = {}) + : _remote(re), _local(), _transport_props(tp), _security_props(sp) { + (void)this->_remote; + (void)this->_local; + (void)this->_transport_props; + (void)this->_security_props; + } + + private: + remote_endpoint _remote; + local_endpoint _local; + transport_props _transport_props; + security_props _security_props; +}; + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/remote_endpoint.hpp b/include/beman/net/detail/remote_endpoint.hpp new file mode 100644 index 0000000..7e95ac7 --- /dev/null +++ b/include/beman/net/detail/remote_endpoint.hpp @@ -0,0 +1,50 @@ +// include/beman/net/detail/remote_endpoint.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_REMOTE_ENDPOINT +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_REMOTE_ENDPOINT + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +class remote_endpoint; +} +namespace beman::net { +using remote_endpoint = beman::net::detail::remote_endpoint; +} + +class beman::net::detail::remote_endpoint { + public: + remote_endpoint() = default; + + auto hostname() const -> std::string { return this->_hostname; } + auto with_hostname(const std::string& hostname) -> remote_endpoint& { + this->_hostname = hostname; + return *this; + } + auto ip_address() const -> std::string { return this->_ip_address; } + auto with_ip_address(const std::string& ip_address) -> remote_endpoint& { + this->_ip_address = ip_address; + return *this; + } + auto port() const -> std::uint16_t { return this->_port; } + auto with_port(std::uint16_t port) -> remote_endpoint& { + this->_port = port; + return *this; + } + auto service() const -> std::string { return this->_service; } + auto with_service(const std::string& service) -> remote_endpoint& { + this->_service = service; + return *this; + } + + private: + std::string _hostname; + std::string _ip_address; + std::uint16_t _port{}; + std::string _service{}; +}; + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/security_props.hpp b/include/beman/net/detail/security_props.hpp new file mode 100644 index 0000000..438efe4 --- /dev/null +++ b/include/beman/net/detail/security_props.hpp @@ -0,0 +1,22 @@ +// include/beman/net/detail/security_props.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_SECURITY_PROPS +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_SECURITY_PROPS + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +class security_props; +} +namespace beman::net { +using security_props = beman::net::detail::security_props; +} + +class beman::net::detail::security_props { + public: +}; + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/transport_preference.hpp b/include/beman/net/detail/transport_preference.hpp new file mode 100644 index 0000000..42a75ce --- /dev/null +++ b/include/beman/net/detail/transport_preference.hpp @@ -0,0 +1,13 @@ +// include/beman/net/detail/transport_preference.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_TRANSPORT_PREFERENCE +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_TRANSPORT_PREFERENCE + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail {} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/transport_props.hpp b/include/beman/net/detail/transport_props.hpp new file mode 100644 index 0000000..9cfcbe5 --- /dev/null +++ b/include/beman/net/detail/transport_props.hpp @@ -0,0 +1,22 @@ +// include/beman/net/detail/transport_props.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_TRANSPORT_PROPS +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_TRANSPORT_PROPS + +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +class transport_props; +} +namespace beman::net { +using transport_props = beman::net::detail::transport_props; +} + +class beman::net::detail::transport_props {}; + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/net.hpp b/include/beman/net/net.hpp index 0566f62..70c0100 100644 --- a/include/beman/net/net.hpp +++ b/include/beman/net/net.hpp @@ -25,6 +25,13 @@ #include #include +// TAPS + +#include +#include +#include +#include + // ---------------------------------------------------------------------------- #endif From ce37a37636c8cb47d50830fdf5a7eacebcc3743a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Thu, 7 Aug 2025 01:14:55 +0100 Subject: [PATCH 02/10] moved closer to getting initiate going --- CMakeLists.txt | 9 ++- examples/CMakeLists.txt | 2 +- examples/taps.cpp | 27 ++++++- include/beman/net/detail/get_io_handle.hpp | 30 ++++++++ include/beman/net/detail/get_scope_token.hpp | 24 ++++++ include/beman/net/detail/initiate.hpp | 41 +++++++++++ include/beman/net/detail/io_context.hpp | 12 +++ include/beman/net/detail/listen.hpp | 20 +++++ include/beman/net/detail/local_endpoint.hpp | 13 ++-- include/beman/net/detail/preconnection.hpp | 2 + include/beman/net/detail/rendezvous.hpp | 20 +++++ include/beman/net/detail/scope.hpp | 73 +++++++++++++++++++ include/beman/net/detail/task.hpp | 38 ++++++++++ .../beman/net/detail/transport_preference.hpp | 4 +- include/beman/net/net.hpp | 9 ++- src/beman/net/CMakeLists.txt | 2 +- 16 files changed, 312 insertions(+), 14 deletions(-) create mode 100644 include/beman/net/detail/get_io_handle.hpp create mode 100644 include/beman/net/detail/get_scope_token.hpp create mode 100644 include/beman/net/detail/initiate.hpp create mode 100644 include/beman/net/detail/listen.hpp create mode 100644 include/beman/net/detail/rendezvous.hpp create mode 100644 include/beman/net/detail/scope.hpp create mode 100644 include/beman/net/detail/task.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ea07ff4..b7cfb12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,16 @@ FetchContent_Declare( execution # SOURCE_DIR /execution GIT_REPOSITORY https://github.com/bemanproject/execution - GIT_TAG fa6d441 + GIT_TAG 4a55162 ) FetchContent_MakeAvailable(execution) +FetchContent_Declare( + task + # SOURCE_DIR /task + GIT_REPOSITORY https://github.com/bemanproject/task + GIT_TAG be2fb72 +) +FetchContent_MakeAvailable(task) include(CTest) if(BUILD_TESTING) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b0eff20..1a2725c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,11 +14,11 @@ set(EXAMPLES server task ) +set(EXAMPLES taps) foreach(EXAMPLE ${EXAMPLES}) set(EXAMPLE_TARGET ${TARGET_PREFIX}.examples.${EXAMPLE}) add_executable(${EXAMPLE_TARGET}) target_sources(${EXAMPLE_TARGET} PRIVATE ${EXAMPLE}.cpp) target_link_libraries(${EXAMPLE_TARGET} PRIVATE ${TARGET_LIBRARY}) - target_link_libraries(${EXAMPLE_TARGET} PRIVATE beman::execution) endforeach() diff --git a/examples/taps.cpp b/examples/taps.cpp index 7b05123..41ee2c5 100644 --- a/examples/taps.cpp +++ b/examples/taps.cpp @@ -1,17 +1,42 @@ // examples/taps.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include +#include +#include #include +namespace ex = beman::execution; namespace net = beman::net; // ---------------------------------------------------------------------------- int main(int ac, char* av[]) { + net::scope scope; + net::preconnection pre( net::remote_endpoint().with_hostname(1 < ac ? av[1] : "example.com").with_port(2 < ac ? std::stoi(av[2]) : 80), {}); - // pre.connect() + ex::spawn(net::initiate(pre) | ex::then([](auto) noexcept {}) | ex::upon_error([](auto) noexcept {}), + scope.get_token()); + + ex::spawn( + []() -> net::task { + [[maybe_unused]] auto handle = co_await ex::read_env(net::get_io_handle); + + auto socket{co_await net::initiate( + net::preconnection(net::remote_endpoint().with_hostname("example.com").with_port(80)))}; + std::string request = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"; + co_await net::async_send(socket, net::buffer(request)); + + char buffer[1024]; + for (std::size_t n; (n = co_await net::async_receive(socket, net::buffer(buffer)));) { + std::cout.write(buffer, n); + } + }(), + scope.get_token()); + + ex::sync_wait(scope.run()); } \ No newline at end of file diff --git a/include/beman/net/detail/get_io_handle.hpp b/include/beman/net/detail/get_io_handle.hpp new file mode 100644 index 0000000..01de5ce --- /dev/null +++ b/include/beman/net/detail/get_io_handle.hpp @@ -0,0 +1,30 @@ +// include/beman/net/detail/get_io_handle.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_GET_IO_HANDLE +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_GET_IO_HANDLE + +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { + struct get_io_handle_t + : beman::execution::forwarding_query_t + { + template + requires requires(Object obj, get_io_handle_t const& gih) { obj.query(gih); } + auto operator()(Object const& obj) const noexcept -> decltype(obj.query(*this)) { + return obj.query(*this); + } + }; +} + +namespace beman::net { +using get_io_handle_t = beman::net::detail::get_io_handle_t; +inline constexpr get_io_handle_t get_io_handle{}; +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/get_scope_token.hpp b/include/beman/net/detail/get_scope_token.hpp new file mode 100644 index 0000000..78517d0 --- /dev/null +++ b/include/beman/net/detail/get_scope_token.hpp @@ -0,0 +1,24 @@ +// include/beman/net/detail/get_scope_token.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_GET_SCOPE_TOKEN +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_GET_SCOPE_TOKEN + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { + struct get_scope_token_t { + template + auto operator()(Object const& obj) const -> decltype(obj.query(*this)) { + return obj.query(*this); + } + }; +} +namespace beman::net { +using get_scope_token_t = beman::net::detail::get_scope_token_t; +inline constexpr get_scope_token_t get_scope_token{}; +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/initiate.hpp b/include/beman/net/detail/initiate.hpp new file mode 100644 index 0000000..5970759 --- /dev/null +++ b/include/beman/net/detail/initiate.hpp @@ -0,0 +1,41 @@ +// include/beman/net/detail/initiate.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_INITIATE +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_INITIATE + +#include +#include +#include +#include + +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +class initiate_t { + public: + auto operator()(const preconnection& pre) const -> beman::execution::task { + //auto handle = co_await beman::execution::read_env(beman::net::get_io_handle); + beman::net::io_context ctxt; + beman::net::ip::tcp::endpoint ep(net::ip::address_v4::loopback(), pre.local().port()); + beman::net::ip::tcp::socket client(ctxt, ep); + + co_await beman::net::async_connect(client); + co_return std::move(client); + } +}; +} // namespace beman::net::detail + +namespace beman::net { +using initiate_t = beman::net::detail::initiate_t; +inline constexpr initiate_t initiate{}; +} // namespace beman::net + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/io_context.hpp b/include/beman/net/detail/io_context.hpp index 811f0fe..e0102b3 100644 --- a/include/beman/net/detail/io_context.hpp +++ b/include/beman/net/detail/io_context.hpp @@ -36,6 +36,18 @@ class beman::net::io_context { using scheduler_type = ::beman::net::detail::io_context_scheduler; class executor_type {}; + class handle { + public: + handle(beman::net::io_context* ctxt) : context(ctxt) {} + auto get_io_context() const -> beman::net::io_context& { + return *this->context; + } + + private: + beman::net::io_context* context{}; + }; + auto get_handle() -> handle { return handle(this); } + io_context() { std::signal(SIGPIPE, SIG_IGN); } io_context(::beman::net::detail::context_base& context) : d_owned(), d_context(context) {} io_context(io_context&&) = delete; diff --git a/include/beman/net/detail/listen.hpp b/include/beman/net/detail/listen.hpp new file mode 100644 index 0000000..4a2e8e7 --- /dev/null +++ b/include/beman/net/detail/listen.hpp @@ -0,0 +1,20 @@ +// include/beman/net/detail/listen.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_LISTEN +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_LISTEN + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +struct listen_t {}; +} // namespace beman::net::detail + +namespace beman::net { +using listen_t = beman::net::detail::listen_t; +inline constexpr listen_t listen{}; +} // namespace beman::net + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/local_endpoint.hpp b/include/beman/net/detail/local_endpoint.hpp index dc2e117..3d3ec91 100644 --- a/include/beman/net/detail/local_endpoint.hpp +++ b/include/beman/net/detail/local_endpoint.hpp @@ -21,6 +21,11 @@ class beman::net::detail::local_endpoint { this->_hostname = hostname; return *this; } + auto ip_address() const -> std::string { return this->_ip_address; } + auto with_ip_address(const std::string& ip_address) -> local_endpoint& { + this->_ip_address = ip_address; + return *this; + } auto port() const -> std::uint16_t { return this->_port; } auto with_port(std::uint16_t port) -> local_endpoint& { this->_port = port; @@ -31,12 +36,6 @@ class beman::net::detail::local_endpoint { this->_service = service; return *this; } - auto ip_address() const -> std::string { return this->_ip_address; } - auto with_ip_address(const std::string& ip_address) -> local_endpoint& { - this->_ip_address = ip_address; - return *this; - } - auto interface() const -> std::string { return this->_interface; } auto with_interface(const std::string& interface) -> local_endpoint& { this->_interface = interface; @@ -45,9 +44,9 @@ class beman::net::detail::local_endpoint { private: std::string _hostname; + std::string _ip_address{}; std::uint16_t _port{}; std::string _service{}; - std::string _ip_address{}; std::string _interface; }; diff --git a/include/beman/net/detail/preconnection.hpp b/include/beman/net/detail/preconnection.hpp index 0922d73..e4100a9 100644 --- a/include/beman/net/detail/preconnection.hpp +++ b/include/beman/net/detail/preconnection.hpp @@ -30,6 +30,8 @@ class beman::net::detail::preconnection { (void)this->_security_props; } + auto local() const noexcept -> const local_endpoint& { return this->_local; } + private: remote_endpoint _remote; local_endpoint _local; diff --git a/include/beman/net/detail/rendezvous.hpp b/include/beman/net/detail/rendezvous.hpp new file mode 100644 index 0000000..e8f1ef7 --- /dev/null +++ b/include/beman/net/detail/rendezvous.hpp @@ -0,0 +1,20 @@ +// include/beman/net/detail/rendezvous.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_RENDEZVOUS +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_RENDEZVOUS + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +struct rendezvous_t {}; +} // namespace beman::net::detail + +namespace beman::net { +using rendezvous_t = beman::net::detail::rendezvous_t; +inline constexpr rendezvous_t rendezvous{}; +} // namespace beman::net + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/scope.hpp b/include/beman/net/detail/scope.hpp new file mode 100644 index 0000000..3a84f40 --- /dev/null +++ b/include/beman/net/detail/scope.hpp @@ -0,0 +1,73 @@ +// include/beman/net/detail/scope.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_SCOPE +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_SCOPE + +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +class scope; +} +namespace beman::net { +using scope = beman::net::detail::scope; +} + +// ---------------------------------------------------------------------------- + +class beman::net::detail::scope { + public: + class token; + class env { + friend class token; + public: + auto query(beman::net::get_io_handle_t const&) const noexcept { + return this->_scope->_io_context.get_handle(); + } + auto query(beman::execution::get_scheduler_t const&) const noexcept { + return this->_scope->_io_context.get_scheduler(); + } + auto query(beman::net::get_scope_token_t const&) const noexcept { + return this->_scope->get_token(); + } + + private: + env(scope* s): _scope(s) {} + scope* _scope; + }; + class token { + public: + token(scope* s) : _scope(s), _counting_token(s->_counting_scope.get_token()) {} + + auto try_associate() noexcept -> bool { return this->_counting_token.try_associate(); } + auto disassociate() noexcept -> void { this->_counting_token.disassociate(); } + template + auto wrap(Sender&& sndr, const Env&... ev) const noexcept -> beman::execution::sender auto { + return this->_counting_token.wrap( + beman::execution::write_env(std::forward(sndr), env(this->_scope)), + ev...); + } + + private: + scope* _scope; + beman::execution::counting_scope::token _counting_token; + }; + + auto run() -> auto { return beman::execution::just(); } + + auto get_token() -> token { return {this}; } + + private: + beman::net::io_context _io_context; + beman::execution::counting_scope _counting_scope; +}; +static_assert(beman::execution::scope_token); + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/task.hpp b/include/beman/net/detail/task.hpp new file mode 100644 index 0000000..44cd240 --- /dev/null +++ b/include/beman/net/detail/task.hpp @@ -0,0 +1,38 @@ +// include/beman/net/detail/task.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_TASK +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_TASK + +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +struct task_env { + using error_types = beman::execution::completion_signatures<>; + + beman::net::io_context::handle _handle; + auto query(beman::net::get_io_handle_t const&) const noexcept { + return this->_handle; + } + + task_env(auto const& env) + : _handle(beman::net::get_io_handle(env)) { + } + +}; + +template +using task = beman::execution::task; +} // namespace beman::net::detail +namespace beman::net { +template +using task = beman::net::detail::task; +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/transport_preference.hpp b/include/beman/net/detail/transport_preference.hpp index 42a75ce..d72a98b 100644 --- a/include/beman/net/detail/transport_preference.hpp +++ b/include/beman/net/detail/transport_preference.hpp @@ -6,7 +6,9 @@ // ---------------------------------------------------------------------------- -namespace beman::net::detail {} +namespace beman::net::detail { +enum class transport_preference { require, prefer, none, avoid, prohibit }; +} // ---------------------------------------------------------------------------- diff --git a/include/beman/net/net.hpp b/include/beman/net/net.hpp index 70c0100..2e3eb69 100644 --- a/include/beman/net/net.hpp +++ b/include/beman/net/net.hpp @@ -27,10 +27,15 @@ // TAPS -#include -#include +#include +#include +#include +#include #include +#include #include +#include +#include // ---------------------------------------------------------------------------- diff --git a/src/beman/net/CMakeLists.txt b/src/beman/net/CMakeLists.txt index f67869a..0c5f109 100644 --- a/src/beman/net/CMakeLists.txt +++ b/src/beman/net/CMakeLists.txt @@ -56,7 +56,7 @@ install( FILE_SET ${TARGET_LIBRARY}_detail_headers ) target_include_directories(${TARGET_LIBRARY} PUBLIC $) -target_link_libraries(${TARGET_LIBRARY} PUBLIC beman::execution) +target_link_libraries(${TARGET_LIBRARY} PUBLIC beman::task) if(FALSE) install(EXPORT ${TARGETS_EXPORT_NAME} From 32d13ad8f45d216a8ef8c9b6ff7292b5f14760a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Fri, 8 Aug 2025 00:55:06 +0100 Subject: [PATCH 03/10] made some progress towards implementing initiate --- CMakeLists.txt | 6 ++-- examples/taps.cpp | 25 +++++++------- include/beman/net/detail/get_io_handle.hpp | 20 +++++------ include/beman/net/detail/get_scope_token.hpp | 18 +++++----- include/beman/net/detail/initiate.hpp | 13 +++++--- include/beman/net/detail/io_context.hpp | 31 ++++++++++++----- include/beman/net/detail/scope.hpp | 35 ++++++++++---------- include/beman/net/detail/task.hpp | 25 +++++++++----- 8 files changed, 100 insertions(+), 73 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7cfb12..3ab4720 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,16 +14,16 @@ set(TARGETS_EXPORT_NAME ${CMAKE_PROJECT_NAME}) include(FetchContent) FetchContent_Declare( execution - # SOURCE_DIR /execution + # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../execution GIT_REPOSITORY https://github.com/bemanproject/execution GIT_TAG 4a55162 ) FetchContent_MakeAvailable(execution) FetchContent_Declare( task - # SOURCE_DIR /task + # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../task GIT_REPOSITORY https://github.com/bemanproject/task - GIT_TAG be2fb72 + GIT_TAG 08ce0ca ) FetchContent_MakeAvailable(task) diff --git a/examples/taps.cpp b/examples/taps.cpp index 41ee2c5..4247720 100644 --- a/examples/taps.cpp +++ b/examples/taps.cpp @@ -12,31 +12,30 @@ namespace net = beman::net; // ---------------------------------------------------------------------------- -int main(int ac, char* av[]) { +int main(int, char*[]) { + std::cout << std::unitbuf; net::scope scope; - net::preconnection pre( - net::remote_endpoint().with_hostname(1 < ac ? av[1] : "example.com").with_port(2 < ac ? std::stoi(av[2]) : 80), - {}); - - ex::spawn(net::initiate(pre) | ex::then([](auto) noexcept {}) | ex::upon_error([](auto) noexcept {}), - scope.get_token()); - + std::cout << "spawning\n"; ex::spawn( - []() -> net::task { - [[maybe_unused]] auto handle = co_await ex::read_env(net::get_io_handle); - - auto socket{co_await net::initiate( - net::preconnection(net::remote_endpoint().with_hostname("example.com").with_port(80)))}; + []() -> net::task<> { + net::preconnection pre(net::remote_endpoint().with_hostname("example.com").with_port(80)); + std::cout << "initiate\n"; + auto socket{co_await net::initiate(pre)}; std::string request = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"; + std::cout << "async_send\n"; co_await net::async_send(socket, net::buffer(request)); char buffer[1024]; + std::cout << "reading\n"; for (std::size_t n; (n = co_await net::async_receive(socket, net::buffer(buffer)));) { + std::cout << "read n=" << n << "\n"; std::cout.write(buffer, n); } }(), scope.get_token()); + std::cout << "spawned\n"; + ex::sync_wait(scope.run()); } \ No newline at end of file diff --git a/include/beman/net/detail/get_io_handle.hpp b/include/beman/net/detail/get_io_handle.hpp index 01de5ce..b7f738a 100644 --- a/include/beman/net/detail/get_io_handle.hpp +++ b/include/beman/net/detail/get_io_handle.hpp @@ -9,21 +9,19 @@ // ---------------------------------------------------------------------------- namespace beman::net::detail { - struct get_io_handle_t - : beman::execution::forwarding_query_t - { - template - requires requires(Object obj, get_io_handle_t const& gih) { obj.query(gih); } - auto operator()(Object const& obj) const noexcept -> decltype(obj.query(*this)) { - return obj.query(*this); - } - }; -} +struct get_io_handle_t : beman::execution::forwarding_query_t { + template + requires requires(Object obj, const get_io_handle_t& gih) { obj.query(gih); } + auto operator()(const Object& obj) const noexcept -> decltype(obj.query(*this)) { + return obj.query(*this); + } +}; +} // namespace beman::net::detail namespace beman::net { using get_io_handle_t = beman::net::detail::get_io_handle_t; inline constexpr get_io_handle_t get_io_handle{}; -} +} // namespace beman::net // ---------------------------------------------------------------------------- diff --git a/include/beman/net/detail/get_scope_token.hpp b/include/beman/net/detail/get_scope_token.hpp index 78517d0..2f26b7d 100644 --- a/include/beman/net/detail/get_scope_token.hpp +++ b/include/beman/net/detail/get_scope_token.hpp @@ -4,20 +4,22 @@ #ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_GET_SCOPE_TOKEN #define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_GET_SCOPE_TOKEN +#include + // ---------------------------------------------------------------------------- namespace beman::net::detail { - struct get_scope_token_t { - template - auto operator()(Object const& obj) const -> decltype(obj.query(*this)) { - return obj.query(*this); - } - }; -} +struct get_scope_token_t : beman::execution::forwarding_query_t { + template + auto operator()(const Object& obj) const -> decltype(obj.query(*this)) { + return obj.query(*this); + } +}; +} // namespace beman::net::detail namespace beman::net { using get_scope_token_t = beman::net::detail::get_scope_token_t; inline constexpr get_scope_token_t get_scope_token{}; -} +} // namespace beman::net // ---------------------------------------------------------------------------- diff --git a/include/beman/net/detail/initiate.hpp b/include/beman/net/detail/initiate.hpp index 5970759..45448ff 100644 --- a/include/beman/net/detail/initiate.hpp +++ b/include/beman/net/detail/initiate.hpp @@ -13,19 +13,24 @@ #include #include #include +#include //-dk:TODO remove // ---------------------------------------------------------------------------- namespace beman::net::detail { class initiate_t { public: - auto operator()(const preconnection& pre) const -> beman::execution::task { - //auto handle = co_await beman::execution::read_env(beman::net::get_io_handle); - beman::net::io_context ctxt; + auto operator()(const preconnection& pre) const -> beman::net::task { + std::cout << "initiate coro\n"; + //-dk:TODO use the destination endpoint from the preconnection beman::net::ip::tcp::endpoint ep(net::ip::address_v4::loopback(), pre.local().port()); - beman::net::ip::tcp::socket client(ctxt, ep); + std::cout << "created endpoint\n"; + beman::net::ip::tcp::socket client( + (co_await beman::execution::read_env(beman::net::get_io_handle)).get_io_context(), ep); + std::cout << "created socket\n"; co_await beman::net::async_connect(client); + std::cout << "connected\n"; co_return std::move(client); } }; diff --git a/include/beman/net/detail/io_context.hpp b/include/beman/net/detail/io_context.hpp index e0102b3..9434b8a 100644 --- a/include/beman/net/detail/io_context.hpp +++ b/include/beman/net/detail/io_context.hpp @@ -18,6 +18,7 @@ #include #include #include +#include // ---------------------------------------------------------------------------- @@ -37,20 +38,34 @@ class beman::net::io_context { class executor_type {}; class handle { - public: - handle(beman::net::io_context* ctxt) : context(ctxt) {} - auto get_io_context() const -> beman::net::io_context& { - return *this->context; + public: + explicit handle(beman::net::io_context* ctxt) : context(ctxt) { + std::cout << "io_context handle created: " << this << "(" << this->context << ")\n"; } + handle(const handle& other) : context(other.context) { + std::cout << "io_context handle copy created: " << this << "(" << this->context << "): other=" << &other + << "\n"; + } + ~handle() { std::cout << "io_context handle destroyed: " << this << "(" << this->context << ")\n"; } + auto get_io_context() const -> beman::net::io_context& { return *this->context; } - private: + private: beman::net::io_context* context{}; }; - auto get_handle() -> handle { return handle(this); } + auto get_handle() -> handle { + std::cout << "get_handle(" << this << ")\n"; + return handle(this); + } - io_context() { std::signal(SIGPIPE, SIG_IGN); } - io_context(::beman::net::detail::context_base& context) : d_owned(), d_context(context) {} + io_context() { + std::signal(SIGPIPE, SIG_IGN); + std::cout << "io_context default created: " << this << "\n"; + } + io_context(::beman::net::detail::context_base& context) : d_owned(), d_context(context) { + std::cout << "io_context created: " << this << " with context: " << &this->d_context << "\n"; + } io_context(io_context&&) = delete; + ~io_context() { std::cout << "io_context destroyed: " << this << "\n"; } auto make_socket(int d, int t, int p, ::std::error_code& error) -> ::beman::net::detail::socket_id { return this->d_context.make_socket(d, t, p, error); diff --git a/include/beman/net/detail/scope.hpp b/include/beman/net/detail/scope.hpp index 3a84f40..9ae10d4 100644 --- a/include/beman/net/detail/scope.hpp +++ b/include/beman/net/detail/scope.hpp @@ -25,20 +25,19 @@ class beman::net::detail::scope { class token; class env { friend class token; - public: - auto query(beman::net::get_io_handle_t const&) const noexcept { - return this->_scope->_io_context.get_handle(); - } - auto query(beman::execution::get_scheduler_t const&) const noexcept { - return this->_scope->_io_context.get_scheduler(); - } - auto query(beman::net::get_scope_token_t const&) const noexcept { - return this->_scope->get_token(); - } - - private: - env(scope* s): _scope(s) {} - scope* _scope; + + public: + auto query(const beman::net::get_io_handle_t&) const noexcept { + return this->_scope->_io_context.get_handle(); + } + auto query(const beman::execution::get_scheduler_t&) const noexcept { + return this->_scope->_io_context.get_scheduler(); + } + auto query(const beman::net::get_scope_token_t&) const noexcept { return this->_scope->get_token(); } + + private: + env(scope* s) : _scope(s) {} + scope* _scope; }; class token { public: @@ -49,8 +48,7 @@ class beman::net::detail::scope { template auto wrap(Sender&& sndr, const Env&... ev) const noexcept -> beman::execution::sender auto { return this->_counting_token.wrap( - beman::execution::write_env(std::forward(sndr), env(this->_scope)), - ev...); + beman::execution::write_env(std::forward(sndr), env(this->_scope)), ev...); } private: @@ -58,7 +56,10 @@ class beman::net::detail::scope { beman::execution::counting_scope::token _counting_token; }; - auto run() -> auto { return beman::execution::just(); } + auto run() -> auto { + std::cout << "scope::run()\n"; + return this->_counting_scope.join(); + } auto get_token() -> token { return {this}; } diff --git a/include/beman/net/detail/task.hpp b/include/beman/net/detail/task.hpp index 44cd240..cc549db 100644 --- a/include/beman/net/detail/task.hpp +++ b/include/beman/net/detail/task.hpp @@ -6,30 +6,37 @@ #include #include +#include +#include #include +#include // ---------------------------------------------------------------------------- namespace beman::net::detail { -struct task_env { +class task_env { + public: using error_types = beman::execution::completion_signatures<>; - beman::net::io_context::handle _handle; - auto query(beman::net::get_io_handle_t const&) const noexcept { - return this->_handle; - } + auto query(const beman::net::get_io_handle_t&) const noexcept { return this->_handle; } + auto query(const beman::net::get_scope_token_t&) const noexcept { return this->_token; } - task_env(auto const& env) - : _handle(beman::net::get_io_handle(env)) { + task_env(const auto& env) : _handle(beman::net::get_io_handle(env)), _token(beman::net::get_scope_token(env)) { + std::cout << "task_env created: " << this << "\n"; } + task_env(task_env&&) = delete; + ~task_env() { std::cout << "task_env destroyed: " << this << "\n"; } + private: + beman::net::io_context::handle _handle; + beman::net::scope::token _token; }; -template +template using task = beman::execution::task; } // namespace beman::net::detail namespace beman::net { -template +template using task = beman::net::detail::task; } From 9e4dc476e5819e45f634b076fdd284e354db0e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 10 Aug 2025 00:28:54 +0100 Subject: [PATCH 04/10] added into_expected and fixed a bunch of issues --- CMakeLists.txt | 2 +- examples/taps.cpp | 39 +++++--- include/beman/net/detail/initiate.hpp | 21 +++-- include/beman/net/detail/into_expected.hpp | 89 +++++++++++++++++++ include/beman/net/detail/io_context.hpp | 63 ++++++++----- .../beman/net/detail/io_context_scheduler.hpp | 5 +- include/beman/net/detail/scope.hpp | 3 +- include/beman/net/detail/task.hpp | 8 +- include/beman/net/net.hpp | 1 + 9 files changed, 180 insertions(+), 51 deletions(-) create mode 100644 include/beman/net/detail/into_expected.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ab4720..6030180 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ FetchContent_Declare( execution # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../execution GIT_REPOSITORY https://github.com/bemanproject/execution - GIT_TAG 4a55162 + GIT_TAG e43fc56 ) FetchContent_MakeAvailable(execution) FetchContent_Declare( diff --git a/examples/taps.cpp b/examples/taps.cpp index 4247720..0e73bd1 100644 --- a/examples/taps.cpp +++ b/examples/taps.cpp @@ -19,20 +19,33 @@ int main(int, char*[]) { std::cout << "spawning\n"; ex::spawn( []() -> net::task<> { - net::preconnection pre(net::remote_endpoint().with_hostname("example.com").with_port(80)); - std::cout << "initiate\n"; - auto socket{co_await net::initiate(pre)}; - std::string request = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"; - std::cout << "async_send\n"; - co_await net::async_send(socket, net::buffer(request)); - - char buffer[1024]; - std::cout << "reading\n"; - for (std::size_t n; (n = co_await net::async_receive(socket, net::buffer(buffer)));) { - std::cout << "read n=" << n << "\n"; - std::cout.write(buffer, n); + try { + net::preconnection pre(net::remote_endpoint().with_hostname("example.com").with_port(80)); + std::cout << "starting initiate\n"; + auto exp{co_await (net::initiate(pre) | net::detail::into_expected)}; + std::cout << "initiate done\n"; + if (!exp) { + std::cout << "initiate failed: " << exp.error().message() << "\n"; + co_yield ex::with_error(exp.error()); + } + auto socket{std::move(std::get<0>(exp.value()))}; + + std::string request = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"; + std::cout << "async_send\n"; + co_await net::async_send(socket, net::buffer(request)); + + char buffer[1024]; + std::cout << "reading\n"; + for (std::size_t n; (n = co_await net::async_receive(socket, net::buffer(buffer)));) { + std::cout << "read n=" << n << "\n"; + std::cout.write(buffer, n); + } + } catch (...) { + std::cout << "exception!\n"; } - }(), + }() | ex::upon_error([](const std::error_code& e) noexcept { + std::cout << "Error: " << e.message() << "\n"; + }) | ex::then([]() noexcept { std::cout << "running connection DONE!\n"; }), scope.get_token()); std::cout << "spawned\n"; diff --git a/include/beman/net/detail/initiate.hpp b/include/beman/net/detail/initiate.hpp index 45448ff..8210a08 100644 --- a/include/beman/net/detail/initiate.hpp +++ b/include/beman/net/detail/initiate.hpp @@ -7,13 +7,14 @@ #include #include #include +#include #include +#include #include #include #include #include -#include //-dk:TODO remove // ---------------------------------------------------------------------------- @@ -21,16 +22,22 @@ namespace beman::net::detail { class initiate_t { public: auto operator()(const preconnection& pre) const -> beman::net::task { - std::cout << "initiate coro\n"; //-dk:TODO use the destination endpoint from the preconnection beman::net::ip::tcp::endpoint ep(net::ip::address_v4::loopback(), pre.local().port()); - std::cout << "created endpoint\n"; - beman::net::ip::tcp::socket client( + beman::net::ip::tcp::socket client( (co_await beman::execution::read_env(beman::net::get_io_handle)).get_io_context(), ep); - std::cout << "created socket\n"; - co_await beman::net::async_connect(client); - std::cout << "connected\n"; + auto exp{co_await (beman::net::async_connect(client) | beman::net::detail::into_expected | + beman::execution::then([](auto&& e) { + std::cout << "connect completed\n"; + return std::move(e); + }))}; + std::cout << "connect completed\n"; + if (!exp) { + std::cout << "initiate failed: " << exp.error().message() << "\n"; + co_yield beman::execution::with_error(exp.error()); + } + std::cout << "initiate succeeded\n"; co_return std::move(client); } }; diff --git a/include/beman/net/detail/into_expected.hpp b/include/beman/net/detail/into_expected.hpp new file mode 100644 index 0000000..60eb9a4 --- /dev/null +++ b/include/beman/net/detail/into_expected.hpp @@ -0,0 +1,89 @@ +// include/beman/net/detail/into_expected.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_INTO_EXPECTED +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_INTO_EXPECTED + +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +struct into_expected_t : beman::execution::sender_adaptor_closure { + template + using expected_t = std::expected, + beman::execution::error_types_of_t>; + + template + struct state { + struct receiver { + using receiver_concept = beman::execution::receiver_t; + using env_t = beman::execution::env_of_t; + Receiver* _receiver; + auto get_env() const noexcept { return beman::execution::get_env(*this->_receiver); } + template + auto set_value(Args&&... args) && noexcept { + std::cout << "into_expected: success\n"; + beman::execution::set_value(std::move(*this->_receiver), + expected_t(std::forward(args)...)); + } + template + auto set_error(Error&& error) && noexcept { + std::cout << "into_expected: failure\n"; + beman::execution::set_value(std::move(*this->_receiver), + expected_t(std::unexpected(std::forward(error)))); + } + auto set_stopped() && noexcept { + std::cout << "into_expected: cancel\n"; + beman::execution::set_stopped(std::move(*this->_receiver)); + } + }; + using operation_state_concept = beman::execution::operation_state_t; + using inner_state_t = beman::execution::connect_result_t; + + Receiver _receiver; + inner_state_t _state; + + state(auto&& sndr, Receiver&& r) + : _receiver(std::forward(r)), + _state(beman::execution::connect(std::forward(sndr), receiver{&this->_receiver})) {} + + auto start() & noexcept -> void { beman::execution::start(this->_state); } + }; + template + struct sender { + using sender_concept = beman::execution::sender_t; + + Sender _sender; + + template + auto get_completion_signatures(const Env&) const { + return beman::execution::completion_signatures), + beman::execution::set_stopped_t()>(); + } + template + auto connect(Receiver&& receiver) { + return state>(std::move(_sender), std::forward(receiver)); + } + }; + + template + auto operator()(Sender&& sndr) const { + return sender>{std::forward(sndr)}; + } +}; + +inline constexpr into_expected_t into_expected{}; +} // namespace beman::net::detail + +namespace beman::net { +using into_expected_t = beman::net::detail::into_expected_t; +inline constexpr into_expected_t into_expected{}; +} // namespace beman::net + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/detail/io_context.hpp b/include/beman/net/detail/io_context.hpp index 9434b8a..bc44590 100644 --- a/include/beman/net/detail/io_context.hpp +++ b/include/beman/net/detail/io_context.hpp @@ -15,10 +15,10 @@ #include #include #include -#include #include #include -#include +#include +#include // ---------------------------------------------------------------------------- @@ -39,33 +39,17 @@ class beman::net::io_context { class handle { public: - explicit handle(beman::net::io_context* ctxt) : context(ctxt) { - std::cout << "io_context handle created: " << this << "(" << this->context << ")\n"; - } - handle(const handle& other) : context(other.context) { - std::cout << "io_context handle copy created: " << this << "(" << this->context << "): other=" << &other - << "\n"; - } - ~handle() { std::cout << "io_context handle destroyed: " << this << "(" << this->context << ")\n"; } + explicit handle(beman::net::io_context* ctxt) : context(ctxt) {} auto get_io_context() const -> beman::net::io_context& { return *this->context; } private: beman::net::io_context* context{}; }; - auto get_handle() -> handle { - std::cout << "get_handle(" << this << ")\n"; - return handle(this); - } + auto get_handle() -> handle { return handle(this); } - io_context() { - std::signal(SIGPIPE, SIG_IGN); - std::cout << "io_context default created: " << this << "\n"; - } - io_context(::beman::net::detail::context_base& context) : d_owned(), d_context(context) { - std::cout << "io_context created: " << this << " with context: " << &this->d_context << "\n"; - } + io_context() { std::signal(SIGPIPE, SIG_IGN); } + io_context(::beman::net::detail::context_base& context) : d_owned(), d_context(context) {} io_context(io_context&&) = delete; - ~io_context() { std::cout << "io_context destroyed: " << this << "\n"; } auto make_socket(int d, int t, int p, ::std::error_code& error) -> ::beman::net::detail::socket_id { return this->d_context.make_socket(d, t, p, error); @@ -94,6 +78,41 @@ class beman::net::io_context { } auto get_scheduler() -> scheduler_type { return scheduler_type(&this->d_context); } + template + struct run_one_state { + using operation_state_concept = ::beman::execution::operation_state_t; + + beman::net::io_context* _context; + ::std::remove_cvref_t _receiver; + + auto start() & noexcept -> void { + try { + std::cout << "run_one_state start\n"; + std::size_t count{this->_context->run_one()}; + std::cout << "run_one_state started: " << this << " with count: " << count << "\n"; + ::beman::execution::set_value(::std::move(this->_receiver), count); + std::cout << "run_one_state set_value called\n"; + } catch (...) { + std::cout << "run_one_state exception caught\n"; + } + } + }; + + struct run_one_sender { + using sender_concept = ::beman::execution::sender_t; + using completion_signatures = + ::beman::execution::completion_signatures<::beman::execution::set_value_t(std::size_t), + ::beman::execution::set_stopped_t()>; + + beman::net::io_context* _context; + template + auto connect(Receiver&& receiver) { + return run_one_state{this->_context, ::std::forward(receiver)}; + } + }; + + auto async_run_one() { return run_one_sender{this}; } + auto async_run() { return this->async_run_one(); } ::std::size_t run_one() { return this->d_context.run_one(); } ::std::size_t run() { ::std::size_t count{}; diff --git a/include/beman/net/detail/io_context_scheduler.hpp b/include/beman/net/detail/io_context_scheduler.hpp index fa92cc1..429d0cb 100644 --- a/include/beman/net/detail/io_context_scheduler.hpp +++ b/include/beman/net/detail/io_context_scheduler.hpp @@ -45,7 +45,10 @@ class beman::net::detail::io_context_scheduler { state(Receiver&& receiver, ::beman::net::detail::context_base* context) : d_receiver(::std::forward(receiver)), d_context(context) {} - auto start() & noexcept -> void { this->d_context->schedule(this); } + auto start() & noexcept -> void { + std::cout << "io_context_scheduler::sender::state start\n"; + this->d_context->schedule(this); + } auto complete() -> void override { ::beman::net::detail::ex::set_value(::std::move(this->d_receiver)); } }; diff --git a/include/beman/net/detail/scope.hpp b/include/beman/net/detail/scope.hpp index 9ae10d4..1ce46c9 100644 --- a/include/beman/net/detail/scope.hpp +++ b/include/beman/net/detail/scope.hpp @@ -57,8 +57,7 @@ class beman::net::detail::scope { }; auto run() -> auto { - std::cout << "scope::run()\n"; - return this->_counting_scope.join(); + return beman::execution::when_all(this->_counting_scope.join(), this->_io_context.async_run()); } auto get_token() -> token { return {this}; } diff --git a/include/beman/net/detail/task.hpp b/include/beman/net/detail/task.hpp index cc549db..4c4d923 100644 --- a/include/beman/net/detail/task.hpp +++ b/include/beman/net/detail/task.hpp @@ -10,22 +10,20 @@ #include #include #include +#include // ---------------------------------------------------------------------------- namespace beman::net::detail { class task_env { public: - using error_types = beman::execution::completion_signatures<>; + using error_types = beman::execution::completion_signatures; auto query(const beman::net::get_io_handle_t&) const noexcept { return this->_handle; } auto query(const beman::net::get_scope_token_t&) const noexcept { return this->_token; } - task_env(const auto& env) : _handle(beman::net::get_io_handle(env)), _token(beman::net::get_scope_token(env)) { - std::cout << "task_env created: " << this << "\n"; - } + task_env(const auto& env) : _handle(beman::net::get_io_handle(env)), _token(beman::net::get_scope_token(env)) {} task_env(task_env&&) = delete; - ~task_env() { std::cout << "task_env destroyed: " << this << "\n"; } private: beman::net::io_context::handle _handle; diff --git a/include/beman/net/net.hpp b/include/beman/net/net.hpp index 2e3eb69..b46dd5b 100644 --- a/include/beman/net/net.hpp +++ b/include/beman/net/net.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include From 78c921247f85b995b2d482e8ba3d70832edf1516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 10 Aug 2025 16:29:45 +0100 Subject: [PATCH 05/10] added repeat_effect_until (and applied a few fixes) --- examples/taps.cpp | 4 +- include/beman/net/detail/initiate.hpp | 8 +- include/beman/net/detail/into_expected.hpp | 7 +- include/beman/net/detail/io_context.hpp | 29 ++-- .../beman/net/detail/io_context_scheduler.hpp | 5 +- .../beman/net/detail/repeat_effect_until.hpp | 140 ++++++++++++++++++ include/beman/net/net.hpp | 1 + 7 files changed, 165 insertions(+), 29 deletions(-) create mode 100644 include/beman/net/detail/repeat_effect_until.hpp diff --git a/examples/taps.cpp b/examples/taps.cpp index 0e73bd1..f8917f3 100644 --- a/examples/taps.cpp +++ b/examples/taps.cpp @@ -21,9 +21,7 @@ int main(int, char*[]) { []() -> net::task<> { try { net::preconnection pre(net::remote_endpoint().with_hostname("example.com").with_port(80)); - std::cout << "starting initiate\n"; - auto exp{co_await (net::initiate(pre) | net::detail::into_expected)}; - std::cout << "initiate done\n"; + auto exp{co_await (net::initiate(pre) | net::detail::into_expected)}; if (!exp) { std::cout << "initiate failed: " << exp.error().message() << "\n"; co_yield ex::with_error(exp.error()); diff --git a/include/beman/net/detail/initiate.hpp b/include/beman/net/detail/initiate.hpp index 8210a08..572329b 100644 --- a/include/beman/net/detail/initiate.hpp +++ b/include/beman/net/detail/initiate.hpp @@ -28,16 +28,10 @@ class initiate_t { (co_await beman::execution::read_env(beman::net::get_io_handle)).get_io_context(), ep); auto exp{co_await (beman::net::async_connect(client) | beman::net::detail::into_expected | - beman::execution::then([](auto&& e) { - std::cout << "connect completed\n"; - return std::move(e); - }))}; - std::cout << "connect completed\n"; + beman::execution::then([](auto&& e) { return std::move(e); }))}; if (!exp) { - std::cout << "initiate failed: " << exp.error().message() << "\n"; co_yield beman::execution::with_error(exp.error()); } - std::cout << "initiate succeeded\n"; co_return std::move(client); } }; diff --git a/include/beman/net/detail/into_expected.hpp b/include/beman/net/detail/into_expected.hpp index 60eb9a4..9c0b003 100644 --- a/include/beman/net/detail/into_expected.hpp +++ b/include/beman/net/detail/into_expected.hpp @@ -26,20 +26,15 @@ struct into_expected_t : beman::execution::sender_adaptor_closure_receiver); } template auto set_value(Args&&... args) && noexcept { - std::cout << "into_expected: success\n"; beman::execution::set_value(std::move(*this->_receiver), expected_t(std::forward(args)...)); } template auto set_error(Error&& error) && noexcept { - std::cout << "into_expected: failure\n"; beman::execution::set_value(std::move(*this->_receiver), expected_t(std::unexpected(std::forward(error)))); } - auto set_stopped() && noexcept { - std::cout << "into_expected: cancel\n"; - beman::execution::set_stopped(std::move(*this->_receiver)); - } + auto set_stopped() && noexcept { beman::execution::set_stopped(std::move(*this->_receiver)); } }; using operation_state_concept = beman::execution::operation_state_t; using inner_state_t = beman::execution::connect_result_t; diff --git a/include/beman/net/detail/io_context.hpp b/include/beman/net/detail/io_context.hpp index bc44590..78cbdd5 100644 --- a/include/beman/net/detail/io_context.hpp +++ b/include/beman/net/detail/io_context.hpp @@ -7,10 +7,13 @@ // ---------------------------------------------------------------------------- #include +#include #include #include #include -#include +#include +#include + #include #include #include @@ -85,14 +88,14 @@ class beman::net::io_context { beman::net::io_context* _context; ::std::remove_cvref_t _receiver; + run_one_state(beman::net::io_context* context, Receiver&& receiver) noexcept + : _context(context), _receiver(::std::forward(receiver)) {} + run_one_state(run_one_state&&) = delete; auto start() & noexcept -> void { try { - std::cout << "run_one_state start\n"; - std::size_t count{this->_context->run_one()}; - std::cout << "run_one_state started: " << this << " with count: " << count << "\n"; - ::beman::execution::set_value(::std::move(this->_receiver), count); - std::cout << "run_one_state set_value called\n"; + ::beman::execution::set_value(::std::move(this->_receiver), this->_context->run_one()); } catch (...) { + //-dk:TODO deal with exceptions in async_run_one std::cout << "run_one_state exception caught\n"; } } @@ -107,12 +110,20 @@ class beman::net::io_context { beman::net::io_context* _context; template auto connect(Receiver&& receiver) { - return run_one_state{this->_context, ::std::forward(receiver)}; + return run_one_state(this->_context, ::std::forward(receiver)); } }; - auto async_run_one() { return run_one_sender{this}; } - auto async_run() { return this->async_run_one(); } + auto async_run_one() { return run_one_sender{this}; } + auto async_run() { + return beman::execution::let_value(beman::execution::just(), [this, last_count = std::size_t(1)]() mutable { + return beman::net::repeat_effect_until( + beman::execution::just(), + [this] { return this->async_run_one(); }() | + beman::execution::then([&last_count](std::size_t count) { last_count = count; }), + [&last_count] { return last_count == 0; }); + }); + } ::std::size_t run_one() { return this->d_context.run_one(); } ::std::size_t run() { ::std::size_t count{}; diff --git a/include/beman/net/detail/io_context_scheduler.hpp b/include/beman/net/detail/io_context_scheduler.hpp index 429d0cb..fa92cc1 100644 --- a/include/beman/net/detail/io_context_scheduler.hpp +++ b/include/beman/net/detail/io_context_scheduler.hpp @@ -45,10 +45,7 @@ class beman::net::detail::io_context_scheduler { state(Receiver&& receiver, ::beman::net::detail::context_base* context) : d_receiver(::std::forward(receiver)), d_context(context) {} - auto start() & noexcept -> void { - std::cout << "io_context_scheduler::sender::state start\n"; - this->d_context->schedule(this); - } + auto start() & noexcept -> void { this->d_context->schedule(this); } auto complete() -> void override { ::beman::net::detail::ex::set_value(::std::move(this->d_receiver)); } }; diff --git a/include/beman/net/detail/repeat_effect_until.hpp b/include/beman/net/detail/repeat_effect_until.hpp new file mode 100644 index 0000000..f20455b --- /dev/null +++ b/include/beman/net/detail/repeat_effect_until.hpp @@ -0,0 +1,140 @@ +// include/beman/net/detail/repeat_effect_until.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_NET_DETAIL_REPEAT_EFFECT_UNTIL +#define INCLUDED_INCLUDE_BEMAN_NET_DETAIL_REPEAT_EFFECT_UNTIL + +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::net::detail { +struct repeat_effect_until_t : beman::execution::sender_adaptor_closure { + template + auto operator()(Upstream&& upstream, Body&& body, Predicate&& predicate) const { + return sender, std::remove_cvref_t, std::remove_cvref_t>{ + std::forward(upstream), std::forward(body), std::forward(predicate)}; + } + + template + struct state { + struct receiver { + using receiver_concept = beman::execution::receiver_t; + state* _state; + auto get_env() const noexcept -> beman::execution::env_of_t; + auto set_value() && noexcept -> void; + template + auto set_error(Error&& e) && noexcept -> void; + auto set_stopped() && noexcept -> void; + }; + using operation_state_concept = beman::execution::operation_state_t; + using upstream_state = beman::execution::connect_result_t; + using body_state = beman::execution::connect_result_t; + struct connector { + template + connector(Sndr&& sndr, Rcvr&& rcvr) + : _state(beman::execution::connect(std::forward(sndr), std::forward(rcvr))) {} + connector(connector&&) = delete; + body_state _state; + }; + + Body _body; + Predicate _predicate; + Receiver _receiver; + upstream_state _up_state; + std::optional _body_state{}; + + template + state(Up&& up, By&& by, Pred&& pred, Rcvr&& rcvr) noexcept + : _body(std::forward(by)), + _predicate(std::forward(pred)), + _receiver(std::forward(rcvr)), + _up_state(beman::execution::connect(std::forward(up), receiver{this})) {} + auto start() & noexcept -> void { beman::execution::start(_up_state); } + auto run_next() & noexcept -> void { + this->_body_state.reset(); + if (this->_predicate()) { + beman::execution::set_value(std::move(this->_receiver)); + } else { + this->_body_state.emplace(std::forward(this->_body), receiver{this}); + beman::execution::start(this->_body_state->_state); + } + } + }; + template + struct sender { + using sender_concept = beman::execution::sender_t; + using completion_signatures = + beman::execution::completion_signatures; + + Upstream upstream; + Body body; + Predicate predicate; + + template + auto connect(Receiver&& receiver) { + return state>{std::move(this->upstream), + std::move(this->body), + std::move(this->predicate), + std::forward(receiver)}; + } + }; +}; +} // namespace beman::net::detail + +namespace beman::net { +using repeat_effect_until_t = beman::net::detail::repeat_effect_until_t; +inline constexpr repeat_effect_until_t repeat_effect_until{}; +} // namespace beman::net + +// ---------------------------------------------------------------------------- + +template +auto beman::net::detail::repeat_effect_until_t::state::receiver::get_env() + const noexcept -> beman::execution::env_of_t { + return beman::execution::get_env(this->_state->_receiver); +} +template +auto beman::net::detail::repeat_effect_until_t::state::receiver:: + set_value() && noexcept -> void { + this->_state->run_next(); +} +template +template +auto beman::net::detail::repeat_effect_until_t::state::receiver::set_error( + Error&& e) && noexcept -> void { + beman::execution::set_error(std::move(this->_state->_receiver), std::forward(e)); +} +template +auto beman::net::detail::repeat_effect_until_t::state::receiver:: + set_stopped() && noexcept -> void { + beman::execution::set_stopped(std::move(this->_state->_receiver)); +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/net/net.hpp b/include/beman/net/net.hpp index b46dd5b..5eb6f90 100644 --- a/include/beman/net/net.hpp +++ b/include/beman/net/net.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include From 923b4ae023836199eb11abffcf7b8729821e9d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 10 Aug 2025 20:10:57 +0100 Subject: [PATCH 06/10] added a fallback expected class to use if necessary --- include/beman/net/detail/into_expected.hpp | 56 ++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/include/beman/net/detail/into_expected.hpp b/include/beman/net/detail/into_expected.hpp index 9c0b003..27ed79a 100644 --- a/include/beman/net/detail/into_expected.hpp +++ b/include/beman/net/detail/into_expected.hpp @@ -7,14 +7,62 @@ #include #include #include +#include #include // ---------------------------------------------------------------------------- namespace beman::net::detail { + +#if 202202 <= __cpp_lib_expected +template +using expected = std::expected; +template +using unexpected = std::unexpected; +#else +template +class unexpected { + public: + template + explicit unexpected(F&& f) noexcept : _error(std::forward(f)) {} + auto error() const& noexcept -> const T& { return this->_error; } + auto error() && noexcept -> T&& { return std::move(this->_error); } + + private: + std::remove_cvref_t _error; +}; +template +unexpected(T&&) -> unexpected>; + +template +class expected { + public: + template + explicit expected(::beman::net::detail::unexpected&& e) noexcept + : _value(std::in_place_index<1>, std::move(e).error()) {} + template + explicit expected(const ::beman::net::detail::unexpected& e) noexcept + : _value(std::in_place_index<1>, e.error()) {} + template + explicit expected(S&&... s) noexcept : _value(std::in_place_index<0>, std::forward(s)...) {} + + explicit operator bool() const noexcept { return this->_value.index() == 0; } + const T& value() const& { return std::get<0>(this->_value); } + const E& error() const& { return std::get<1>(this->_value); } + T& value() & { return std::get<0>(this->_value); } + E& error() & { return std::get<1>(this->_value); } + T&& value() && { return std::get<0>(std::move(this->_value)); } + E&& error() && { return std::get<1>(std::move(this->_value)); } + + private: + std::variant, std::remove_cvref_t> _value; +}; +#endif + struct into_expected_t : beman::execution::sender_adaptor_closure { template - using expected_t = std::expected, + using expected_t = + beman::net::detail::expected, beman::execution::error_types_of_t>; template @@ -31,8 +79,10 @@ struct into_expected_t : beman::execution::sender_adaptor_closure auto set_error(Error&& error) && noexcept { - beman::execution::set_value(std::move(*this->_receiver), - expected_t(std::unexpected(std::forward(error)))); + beman::execution::set_value( + std::move(*this->_receiver), + expected_t( + beman::net::detail::unexpected>(std::forward(error)))); } auto set_stopped() && noexcept { beman::execution::set_stopped(std::move(*this->_receiver)); } }; From b19896ef3d648af00cee22d43a777603b1cfef42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 10 Aug 2025 20:22:49 +0100 Subject: [PATCH 07/10] fixed some issues caught by CI --- include/beman/net/detail/into_expected.hpp | 2 + include/beman/net/detail/io_context.hpp | 1 + src/beman/net/CMakeLists.txt | 61 ++++++++++++++-------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/include/beman/net/detail/into_expected.hpp b/include/beman/net/detail/into_expected.hpp index 27ed79a..ea181a0 100644 --- a/include/beman/net/detail/into_expected.hpp +++ b/include/beman/net/detail/into_expected.hpp @@ -6,7 +6,9 @@ #include #include +#if 202202 <= __cpp_lib_expected #include +#endif #include #include diff --git a/include/beman/net/detail/io_context.hpp b/include/beman/net/detail/io_context.hpp index 78cbdd5..e8609f3 100644 --- a/include/beman/net/detail/io_context.hpp +++ b/include/beman/net/detail/io_context.hpp @@ -117,6 +117,7 @@ class beman::net::io_context { auto async_run_one() { return run_one_sender{this}; } auto async_run() { return beman::execution::let_value(beman::execution::just(), [this, last_count = std::size_t(1)]() mutable { + (void)last_count; //-dk:TODO remove this once no compiler complains about last_count being unused return beman::net::repeat_effect_until( beman::execution::just(), [this] { return this->async_run_one(); }() | diff --git a/src/beman/net/CMakeLists.txt b/src/beman/net/CMakeLists.txt index 0c5f109..7e96272 100644 --- a/src/beman/net/CMakeLists.txt +++ b/src/beman/net/CMakeLists.txt @@ -13,32 +13,49 @@ target_sources(${TARGET_LIBRARY} FILE_SET ${TARGET_LIBRARY}_public_headers TYPE HEADERS BASE_DIRS ${PROJECT_SOURCE_DIR}/include FILES - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/net.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/net.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net29/net.hpp PUBLIC FILE_SET ${TARGET_LIBRARY}_detail_headers TYPE HEADERS BASE_DIRS ${PROJECT_SOURCE_DIR}/include FILES - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/basic_socket.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/basic_socket_acceptor.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/basic_stream_socket.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/buffer.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/container.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/context_base.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/endpoint.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/execution.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/internet.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/io_base.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/io_context.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/io_context_scheduler.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/netfwd.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/operations.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/poll_context.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/sender.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/socket_base.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/socket_category.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/sorted_list.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/stop_token.hpp - ${PROJECT_SOURCE_DIR}/include/beman/${TARGET_NAME}/detail/timer.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/basic_socket.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/basic_socket_acceptor.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/basic_stream_socket.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/buffer.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/container.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/context_base.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/endpoint.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/event_type.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/execution.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/get_io_handle.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/get_scope_token.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/initiate.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/internet.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/into_expected.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/io_base.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/io_context.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/io_context_scheduler.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/listen.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/local_endpoint.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/netfwd.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/operations.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/poll_context.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/preconnection.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/remote_endpoint.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/rendezvous.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/repeat_effect_until.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/scope.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/security_props.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/sender.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/socket_base.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/socket_category.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/sorted_list.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/stop_token.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/task.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/timer.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/transport_preference.hpp + ${PROJECT_SOURCE_DIR}/include/beman/net/detail/transport_props.hpp ) get_property(DETAIL_HEADER_FILES TARGET ${TARGET_LIBRARY} PROPERTY HEADER_SET_${TARGET_LIBRARY}_detail_headers) source_group("Header Files\\detail" FILES ${DETAIL_HEADER_FILES}) From 4181f81363c8a6b45f3dade267cf50f7b3caf1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 10 Aug 2025 20:37:33 +0100 Subject: [PATCH 08/10] merged infrastructure changes --- examples/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4467b98..7dd59d7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,7 +14,7 @@ set(EXAMPLES server task ) -set(EXAMPLES taps) +set(xEXAMPLES taps) foreach(EXAMPLE ${EXAMPLES}) set(EXAMPLE_TARGET ${TARGET_PREFIX}.examples.${EXAMPLE}) From 368173297b1a86276e8ac9d40b2349243c715bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 10 Aug 2025 20:40:09 +0100 Subject: [PATCH 09/10] fixed a silly CI complaint --- examples/taps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/taps.cpp b/examples/taps.cpp index f8917f3..d25bc73 100644 --- a/examples/taps.cpp +++ b/examples/taps.cpp @@ -49,4 +49,4 @@ int main(int, char*[]) { std::cout << "spawned\n"; ex::sync_wait(scope.run()); -} \ No newline at end of file +} From 10b40a37f90309fec07aebd5bbb3d3c289a73d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 10 Aug 2025 23:01:09 +0100 Subject: [PATCH 10/10] some more fixes and set up a somewhat working demo --- CMakeLists.txt | 2 +- examples/taps.cpp | 2 +- include/beman/net/detail/initiate.hpp | 5 +++-- include/beman/net/detail/preconnection.hpp | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d072f72..48fe0a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ FetchContent_Declare( task # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../task GIT_REPOSITORY https://github.com/bemanproject/task - GIT_TAG 08ce0ca + GIT_TAG 0495d7f ) FetchContent_MakeAvailable(task) diff --git a/examples/taps.cpp b/examples/taps.cpp index d25bc73..d39af6f 100644 --- a/examples/taps.cpp +++ b/examples/taps.cpp @@ -20,7 +20,7 @@ int main(int, char*[]) { ex::spawn( []() -> net::task<> { try { - net::preconnection pre(net::remote_endpoint().with_hostname("example.com").with_port(80)); + net::preconnection pre(net::remote_endpoint().with_hostname("localhost").with_port(12345)); auto exp{co_await (net::initiate(pre) | net::detail::into_expected)}; if (!exp) { std::cout << "initiate failed: " << exp.error().message() << "\n"; diff --git a/include/beman/net/detail/initiate.hpp b/include/beman/net/detail/initiate.hpp index 572329b..1fa03ac 100644 --- a/include/beman/net/detail/initiate.hpp +++ b/include/beman/net/detail/initiate.hpp @@ -23,8 +23,9 @@ class initiate_t { public: auto operator()(const preconnection& pre) const -> beman::net::task { //-dk:TODO use the destination endpoint from the preconnection - beman::net::ip::tcp::endpoint ep(net::ip::address_v4::loopback(), pre.local().port()); - beman::net::ip::tcp::socket client( + beman::net::ip::tcp::endpoint ep(net::ip::address_v4::loopback(), pre.remote().port()); + // beman::net::ip::tcp::endpoint ep(net::ip::address_v4(0x9d'e6'43'b3), 80); + beman::net::ip::tcp::socket client( (co_await beman::execution::read_env(beman::net::get_io_handle)).get_io_context(), ep); auto exp{co_await (beman::net::async_connect(client) | beman::net::detail::into_expected | diff --git a/include/beman/net/detail/preconnection.hpp b/include/beman/net/detail/preconnection.hpp index e4100a9..deb1cb8 100644 --- a/include/beman/net/detail/preconnection.hpp +++ b/include/beman/net/detail/preconnection.hpp @@ -31,6 +31,7 @@ class beman::net::detail::preconnection { } auto local() const noexcept -> const local_endpoint& { return this->_local; } + auto remote() const noexcept -> const remote_endpoint& { return this->_remote; } private: remote_endpoint _remote;