75.68% Lines (28/37)
100.00% Functions (3/3)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // | 1 | // | |||||
| 2 | // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) | 2 | // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) | |||||
| 3 | // Copyright (c) 2026 Steve Gerbino | 3 | // Copyright (c) 2026 Steve Gerbino | |||||
| 4 | // | 4 | // | |||||
| 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||||
| 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| 7 | // | 7 | // | |||||
| 8 | // Official repository: https://github.com/cppalliance/corosio | 8 | // Official repository: https://github.com/cppalliance/corosio | |||||
| 9 | // | 9 | // | |||||
| 10 | 10 | |||||||
| 11 | #ifndef BOOST_COROSIO_TEST_SOCKET_PAIR_HPP | 11 | #ifndef BOOST_COROSIO_TEST_SOCKET_PAIR_HPP | |||||
| 12 | #define BOOST_COROSIO_TEST_SOCKET_PAIR_HPP | 12 | #define BOOST_COROSIO_TEST_SOCKET_PAIR_HPP | |||||
| 13 | 13 | |||||||
| 14 | #include <boost/corosio/io_context.hpp> | 14 | #include <boost/corosio/io_context.hpp> | |||||
| 15 | #include <boost/corosio/tcp_acceptor.hpp> | 15 | #include <boost/corosio/tcp_acceptor.hpp> | |||||
| 16 | #include <boost/corosio/tcp_socket.hpp> | 16 | #include <boost/corosio/tcp_socket.hpp> | |||||
| 17 | #include <boost/corosio/socket_option.hpp> | 17 | #include <boost/corosio/socket_option.hpp> | |||||
| 18 | #include <boost/capy/ex/run_async.hpp> | 18 | #include <boost/capy/ex/run_async.hpp> | |||||
| 19 | #include <boost/capy/task.hpp> | 19 | #include <boost/capy/task.hpp> | |||||
| 20 | 20 | |||||||
| 21 | #include <cstdio> | 21 | #include <cstdio> | |||||
| 22 | #include <stdexcept> | 22 | #include <stdexcept> | |||||
| 23 | #include <system_error> | 23 | #include <system_error> | |||||
| 24 | #include <utility> | 24 | #include <utility> | |||||
| 25 | 25 | |||||||
| 26 | namespace boost::corosio::test { | 26 | namespace boost::corosio::test { | |||||
| 27 | 27 | |||||||
| 28 | /** Create a connected pair of sockets. | 28 | /** Create a connected pair of sockets. | |||||
| 29 | 29 | |||||||
| 30 | Creates two sockets connected via loopback TCP sockets. | 30 | Creates two sockets connected via loopback TCP sockets. | |||||
| 31 | Data written to one socket can be read from the other. | 31 | Data written to one socket can be read from the other. | |||||
| 32 | 32 | |||||||
| 33 | @tparam Socket The socket type (default `tcp_socket`). | 33 | @tparam Socket The socket type (default `tcp_socket`). | |||||
| 34 | @tparam Acceptor The acceptor type (default `tcp_acceptor`). | 34 | @tparam Acceptor The acceptor type (default `tcp_acceptor`). | |||||
| 35 | 35 | |||||||
| 36 | @param ctx The I/O context for the sockets. | 36 | @param ctx The I/O context for the sockets. | |||||
| 37 | 37 | |||||||
| 38 | @return A pair of connected sockets. | 38 | @return A pair of connected sockets. | |||||
| 39 | */ | 39 | */ | |||||
| 40 | template< | 40 | template< | |||||
| 41 | class Socket = tcp_socket, | 41 | class Socket = tcp_socket, | |||||
| 42 | class Acceptor = tcp_acceptor, | 42 | class Acceptor = tcp_acceptor, | |||||
| 43 | bool Linger = true> | 43 | bool Linger = true> | |||||
| 44 | std::pair<Socket, Socket> | 44 | std::pair<Socket, Socket> | |||||
| HITCBC | 45 | 58 | make_socket_pair(io_context& ctx) | 45 | 58 | make_socket_pair(io_context& ctx) | ||
| 46 | { | 46 | { | |||||
| HITCBC | 47 | 58 | auto ex = ctx.get_executor(); | 47 | 58 | auto ex = ctx.get_executor(); | ||
| 48 | 48 | |||||||
| HITCBC | 49 | 58 | std::error_code accept_ec; | 49 | 58 | std::error_code accept_ec; | ||
| HITCBC | 50 | 58 | std::error_code connect_ec; | 50 | 58 | std::error_code connect_ec; | ||
| HITCBC | 51 | 58 | bool accept_done = false; | 51 | 58 | bool accept_done = false; | ||
| HITCBC | 52 | 58 | bool connect_done = false; | 52 | 58 | bool connect_done = false; | ||
| 53 | 53 | |||||||
| HITCBC | 54 | 58 | Acceptor acc(ctx); | 54 | 58 | Acceptor acc(ctx); | ||
| HITCBC | 55 | 58 | acc.open(); | 55 | 58 | acc.open(); | ||
| HITCBC | 56 | 58 | acc.set_option(socket_option::reuse_address(true)); | 56 | 58 | acc.set_option(socket_option::reuse_address(true)); | ||
| HITCBC | 57 | 58 | if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0))) | 57 | 58 | if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0))) | ||
| MISUBC | 58 | ✗ | throw std::runtime_error("socket_pair bind failed: " + ec.message()); | 58 | ✗ | throw std::runtime_error("socket_pair bind failed: " + ec.message()); | ||
| HITCBC | 59 | 58 | if (auto ec = acc.listen()) | 59 | 58 | if (auto ec = acc.listen()) | ||
| MISUBC | 60 | ✗ | throw std::runtime_error("socket_pair listen failed: " + ec.message()); | 60 | ✗ | throw std::runtime_error("socket_pair listen failed: " + ec.message()); | ||
| HITCBC | 61 | 58 | auto port = acc.local_endpoint().port(); | 61 | 58 | auto port = acc.local_endpoint().port(); | ||
| 62 | 62 | |||||||
| HITCBC | 63 | 58 | Socket s1(ctx); | 63 | 58 | Socket s1(ctx); | ||
| HITCBC | 64 | 58 | Socket s2(ctx); | 64 | 58 | Socket s2(ctx); | ||
| HITCBC | 65 | 58 | s2.open(); | 65 | 58 | s2.open(); | ||
| 66 | 66 | |||||||
| HITCBC | 67 | 58 | capy::run_async(ex)( | 67 | 58 | capy::run_async(ex)( | ||
| HITCBC | 68 | 116 | [](Acceptor& a, Socket& s, std::error_code& ec_out, | 68 | 116 | [](Acceptor& a, Socket& s, std::error_code& ec_out, | ||
| 69 | bool& done_out) -> capy::task<> { | 69 | bool& done_out) -> capy::task<> { | |||||
| 70 | auto [ec] = co_await a.accept(s); | 70 | auto [ec] = co_await a.accept(s); | |||||
| 71 | ec_out = ec; | 71 | ec_out = ec; | |||||
| 72 | done_out = true; | 72 | done_out = true; | |||||
| 73 | }(acc, s1, accept_ec, accept_done)); | 73 | }(acc, s1, accept_ec, accept_done)); | |||||
| 74 | 74 | |||||||
| HITCBC | 75 | 58 | capy::run_async(ex)( | 75 | 58 | capy::run_async(ex)( | ||
| HITCBC | 76 | 116 | [](Socket& s, endpoint ep, std::error_code& ec_out, | 76 | 116 | [](Socket& s, endpoint ep, std::error_code& ec_out, | ||
| 77 | bool& done_out) -> capy::task<> { | 77 | bool& done_out) -> capy::task<> { | |||||
| 78 | auto [ec] = co_await s.connect(ep); | 78 | auto [ec] = co_await s.connect(ep); | |||||
| 79 | ec_out = ec; | 79 | ec_out = ec; | |||||
| 80 | done_out = true; | 80 | done_out = true; | |||||
| 81 | }(s2, endpoint(ipv4_address::loopback(), port), connect_ec, | 81 | }(s2, endpoint(ipv4_address::loopback(), port), connect_ec, | |||||
| 82 | connect_done)); | 82 | connect_done)); | |||||
| 83 | 83 | |||||||
| HITCBC | 84 | 58 | ctx.run(); | 84 | 58 | ctx.run(); | ||
| HITCBC | 85 | 58 | ctx.restart(); | 85 | 58 | ctx.restart(); | ||
| 86 | 86 | |||||||
| HITCBC | 87 | 58 | if (!accept_done || accept_ec) | 87 | 58 | if (!accept_done || accept_ec) | ||
| 88 | { | 88 | { | |||||
| MISUBC | 89 | ✗ | std::fprintf( | 89 | ✗ | std::fprintf( | ||
| 90 | stderr, "socket_pair: accept failed (done=%d, ec=%s)\n", | 90 | stderr, "socket_pair: accept failed (done=%d, ec=%s)\n", | |||||
| 91 | accept_done, accept_ec.message().c_str()); | 91 | accept_done, accept_ec.message().c_str()); | |||||
| MISUBC | 92 | ✗ | acc.close(); | 92 | ✗ | acc.close(); | ||
| MISUBC | 93 | ✗ | throw std::runtime_error("socket_pair accept failed"); | 93 | ✗ | throw std::runtime_error("socket_pair accept failed"); | ||
| 94 | } | 94 | } | |||||
| 95 | 95 | |||||||
| HITCBC | 96 | 58 | if (!connect_done || connect_ec) | 96 | 58 | if (!connect_done || connect_ec) | ||
| 97 | { | 97 | { | |||||
| MISUBC | 98 | ✗ | std::fprintf( | 98 | ✗ | std::fprintf( | ||
| 99 | stderr, "socket_pair: connect failed (done=%d, ec=%s)\n", | 99 | stderr, "socket_pair: connect failed (done=%d, ec=%s)\n", | |||||
| 100 | connect_done, connect_ec.message().c_str()); | 100 | connect_done, connect_ec.message().c_str()); | |||||
| MISUBC | 101 | ✗ | acc.close(); | 101 | ✗ | acc.close(); | ||
| MISUBC | 102 | ✗ | s1.close(); | 102 | ✗ | s1.close(); | ||
| MISUBC | 103 | ✗ | throw std::runtime_error("socket_pair connect failed"); | 103 | ✗ | throw std::runtime_error("socket_pair connect failed"); | ||
| 104 | } | 104 | } | |||||
| 105 | 105 | |||||||
| HITCBC | 106 | 58 | acc.close(); | 106 | 58 | acc.close(); | ||
| 107 | 107 | |||||||
| 108 | if constexpr (Linger) | 108 | if constexpr (Linger) | |||||
| 109 | { | 109 | { | |||||
| HITCBC | 110 | 4 | s1.set_option(socket_option::linger(true, 0)); | 110 | 4 | s1.set_option(socket_option::linger(true, 0)); | ||
| HITCBC | 111 | 4 | s2.set_option(socket_option::linger(true, 0)); | 111 | 4 | s2.set_option(socket_option::linger(true, 0)); | ||
| 112 | } | 112 | } | |||||
| 113 | 113 | |||||||
| HITCBC | 114 | 116 | return {std::move(s1), std::move(s2)}; | 114 | 116 | return {std::move(s1), std::move(s2)}; | ||
| HITCBC | 115 | 58 | } | 115 | 58 | } | ||
| 116 | 116 | |||||||
| 117 | } // namespace boost::corosio::test | 117 | } // namespace boost::corosio::test | |||||
| 118 | 118 | |||||||
| 119 | #endif | 119 | #endif | |||||