72.50% Lines (29/40) 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   264 make_socket_pair(io_context& ctx) 45   264 make_socket_pair(io_context& ctx)
46   { 46   {
HITCBC 47   264 auto ex = ctx.get_executor(); 47   264 auto ex = ctx.get_executor();
48   48  
HITCBC 49   264 std::error_code accept_ec; 49   264 std::error_code accept_ec;
HITCBC 50   264 std::error_code connect_ec; 50   264 std::error_code connect_ec;
HITCBC 51   264 bool accept_done = false; 51   264 bool accept_done = false;
HITCBC 52   264 bool connect_done = false; 52   264 bool connect_done = false;
53   53  
HITCBC 54   264 Acceptor acc(ctx); 54   264 Acceptor acc(ctx);
HITCBC 55   264 if (auto open_ec = acc.open()) 55   264 if (auto open_ec = acc.open())
MISUBC 56   ✗ throw std::runtime_error( 56   ✗ throw std::runtime_error(
57   "socket_pair open failed: " + open_ec.message()); 57   "socket_pair open failed: " + open_ec.message());
HITCBC 58   264 acc.set_option(socket_option::reuse_address(true)); 58   264 acc.set_option(socket_option::reuse_address(true));
HITCBC 59   264 if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0))) 59   264 if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0)))
MISUBC 60   ✗ throw std::runtime_error("socket_pair bind failed: " + ec.message()); 60   ✗ throw std::runtime_error("socket_pair bind failed: " + ec.message());
HITCBC 61   264 if (auto ec = acc.listen()) 61   264 if (auto ec = acc.listen())
MISUBC 62   ✗ throw std::runtime_error("socket_pair listen failed: " + ec.message()); 62   ✗ throw std::runtime_error("socket_pair listen failed: " + ec.message());
HITCBC 63   264 auto port = acc.local_endpoint().port(); 63   264 auto port = acc.local_endpoint().port();
64   64  
HITCBC 65   264 Socket s1(ctx); 65   264 Socket s1(ctx);
HITCBC 66   264 Socket s2(ctx); 66   264 Socket s2(ctx);
HITCBC 67   264 if (auto open_ec = s2.open()) 67   264 if (auto open_ec = s2.open())
MISUBC 68   ✗ throw std::runtime_error( 68   ✗ throw std::runtime_error(
69   "socket_pair open failed: " + open_ec.message()); 69   "socket_pair open failed: " + open_ec.message());
70   70  
HITCBC 71   264 capy::run_async(ex)( 71   264 capy::run_async(ex)(
HITCBC 72   528 [](Acceptor& a, Socket& s, std::error_code& ec_out, 72   528 [](Acceptor& a, Socket& s, std::error_code& ec_out,
73   bool& done_out) -> capy::task<> { 73   bool& done_out) -> capy::task<> {
74   auto [ec] = co_await a.accept(s); 74   auto [ec] = co_await a.accept(s);
75   ec_out = ec; 75   ec_out = ec;
76   done_out = true; 76   done_out = true;
77   }(acc, s1, accept_ec, accept_done)); 77   }(acc, s1, accept_ec, accept_done));
78   78  
HITCBC 79   528 capy::run_async(ex)( 79   528 capy::run_async(ex)(
HITCBC 80   264 [](Socket& s, endpoint ep, std::error_code& ec_out, 80   264 [](Socket& s, endpoint ep, std::error_code& ec_out,
81   bool& done_out) -> capy::task<> { 81   bool& done_out) -> capy::task<> {
82   auto [ec] = co_await s.connect(ep); 82   auto [ec] = co_await s.connect(ep);
83   ec_out = ec; 83   ec_out = ec;
84   done_out = true; 84   done_out = true;
HITCBC 85   528 }(s2, endpoint(ipv4_address::loopback(), port), connect_ec, 85   528 }(s2, endpoint(ipv4_address::loopback(), port), connect_ec,
86   connect_done)); 86   connect_done));
87   87  
HITCBC 88   264 ctx.run(); 88   264 ctx.run();
HITCBC 89   264 ctx.restart(); 89   264 ctx.restart();
90   90  
HITCBC 91   264 if (!accept_done || accept_ec) 91   264 if (!accept_done || accept_ec)
92   { 92   {
MISUBC 93   ✗ std::fprintf( 93   ✗ std::fprintf(
94   stderr, "socket_pair: accept failed (done=%d, ec=%s)\n", 94   stderr, "socket_pair: accept failed (done=%d, ec=%s)\n",
95   accept_done, accept_ec.message().c_str()); 95   accept_done, accept_ec.message().c_str());
MISUBC 96   ✗ acc.close(); 96   ✗ acc.close();
MISUBC 97   ✗ throw std::runtime_error("socket_pair accept failed"); 97   ✗ throw std::runtime_error("socket_pair accept failed");
98   } 98   }
99   99  
HITCBC 100   264 if (!connect_done || connect_ec) 100   264 if (!connect_done || connect_ec)
101   { 101   {
MISUBC 102   ✗ std::fprintf( 102   ✗ std::fprintf(
103   stderr, "socket_pair: connect failed (done=%d, ec=%s)\n", 103   stderr, "socket_pair: connect failed (done=%d, ec=%s)\n",
104   connect_done, connect_ec.message().c_str()); 104   connect_done, connect_ec.message().c_str());
MISUBC 105   ✗ acc.close(); 105   ✗ acc.close();
MISUBC 106   ✗ s1.close(); 106   ✗ s1.close();
MISUBC 107   ✗ throw std::runtime_error("socket_pair connect failed"); 107   ✗ throw std::runtime_error("socket_pair connect failed");
108   } 108   }
109   109  
HITCBC 110   264 acc.close(); 110   264 acc.close();
111   111  
112   if constexpr (Linger) 112   if constexpr (Linger)
113   { 113   {
HITCBC 114   93 s1.set_option(socket_option::linger(true, 0)); 114   93 s1.set_option(socket_option::linger(true, 0));
HITCBC 115   93 s2.set_option(socket_option::linger(true, 0)); 115   93 s2.set_option(socket_option::linger(true, 0));
116   } 116   }
117   117  
HITCBC 118   528 return {std::move(s1), std::move(s2)}; 118   528 return {std::move(s1), std::move(s2)};
HITCBC 119   264 } 119   264 }
120   120  
121   } // namespace boost::corosio::test 121   } // namespace boost::corosio::test
122   122  
123   #endif 123   #endif