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 Linger Whether to enable `SO_LINGER` with a zero timeout  
35 - on both sockets (default `true`).  
36   @tparam Acceptor The acceptor type (default `tcp_acceptor`). 34   @tparam Acceptor The acceptor type (default `tcp_acceptor`).
37   35  
38   @param ctx The I/O context for the sockets. 36   @param ctx The I/O context for the sockets.
39   37  
40 -  
41 - @throws std::runtime_error if opening, binding, listening,  
42 - accepting, or connecting fails.  
43   @return A pair of connected sockets. 38   @return A pair of connected sockets.
44   */ 39   */
45   template< 40   template<
46   class Socket = tcp_socket, 41   class Socket = tcp_socket,
47   class Acceptor = tcp_acceptor, 42   class Acceptor = tcp_acceptor,
48   bool Linger = true> 43   bool Linger = true>
49   std::pair<Socket, Socket> 44   std::pair<Socket, Socket>
HITCBC 50   264 make_socket_pair(io_context& ctx) 45   264 make_socket_pair(io_context& ctx)
51   { 46   {
HITCBC 52   264 auto ex = ctx.get_executor(); 47   264 auto ex = ctx.get_executor();
53   48  
HITCBC 54   264 std::error_code accept_ec; 49   264 std::error_code accept_ec;
HITCBC 55   264 std::error_code connect_ec; 50   264 std::error_code connect_ec;
HITCBC 56   264 bool accept_done = false; 51   264 bool accept_done = false;
HITCBC 57   264 bool connect_done = false; 52   264 bool connect_done = false;
58   53  
HITCBC 59   264 Acceptor acc(ctx); 54   264 Acceptor acc(ctx);
HITCBC 60   264 if (auto open_ec = acc.open()) 55   264 if (auto open_ec = acc.open())
MISUBC 61   ✗ throw std::runtime_error( 56   ✗ throw std::runtime_error(
62   "socket_pair open failed: " + open_ec.message()); 57   "socket_pair open failed: " + open_ec.message());
HITCBC 63   264 acc.set_option(socket_option::reuse_address(true)); 58   264 acc.set_option(socket_option::reuse_address(true));
HITCBC 64   264 if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0))) 59   264 if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0)))
MISUBC 65   ✗ throw std::runtime_error("socket_pair bind failed: " + ec.message()); 60   ✗ throw std::runtime_error("socket_pair bind failed: " + ec.message());
HITCBC 66   264 if (auto ec = acc.listen()) 61   264 if (auto ec = acc.listen())
MISUBC 67   ✗ throw std::runtime_error("socket_pair listen failed: " + ec.message()); 62   ✗ throw std::runtime_error("socket_pair listen failed: " + ec.message());
HITCBC 68   264 auto port = acc.local_endpoint().port(); 63   264 auto port = acc.local_endpoint().port();
69   64  
HITCBC 70   264 Socket s1(ctx); 65   264 Socket s1(ctx);
HITCBC 71   264 Socket s2(ctx); 66   264 Socket s2(ctx);
HITCBC 72   264 if (auto open_ec = s2.open()) 67   264 if (auto open_ec = s2.open())
MISUBC 73   ✗ throw std::runtime_error( 68   ✗ throw std::runtime_error(
74   "socket_pair open failed: " + open_ec.message()); 69   "socket_pair open failed: " + open_ec.message());
75   70  
HITCBC 76   264 capy::run_async(ex)( 71   264 capy::run_async(ex)(
HITCBC 77   528 [](Acceptor& a, Socket& s, std::error_code& ec_out, 72   528 [](Acceptor& a, Socket& s, std::error_code& ec_out,
78   bool& done_out) -> capy::task<> { 73   bool& done_out) -> capy::task<> {
79   auto [ec] = co_await a.accept(s); 74   auto [ec] = co_await a.accept(s);
80   ec_out = ec; 75   ec_out = ec;
81   done_out = true; 76   done_out = true;
82   }(acc, s1, accept_ec, accept_done)); 77   }(acc, s1, accept_ec, accept_done));
83   78  
HITCBC 84   528 capy::run_async(ex)( 79   528 capy::run_async(ex)(
HITCBC 85   264 [](Socket& s, endpoint ep, std::error_code& ec_out, 80   264 [](Socket& s, endpoint ep, std::error_code& ec_out,
86   bool& done_out) -> capy::task<> { 81   bool& done_out) -> capy::task<> {
87   auto [ec] = co_await s.connect(ep); 82   auto [ec] = co_await s.connect(ep);
88   ec_out = ec; 83   ec_out = ec;
89   done_out = true; 84   done_out = true;
HITCBC 90   528 }(s2, endpoint(ipv4_address::loopback(), port), connect_ec, 85   528 }(s2, endpoint(ipv4_address::loopback(), port), connect_ec,
91   connect_done)); 86   connect_done));
92   87  
HITCBC 93   264 ctx.run(); 88   264 ctx.run();
HITCBC 94   264 ctx.restart(); 89   264 ctx.restart();
95   90  
HITCBC 96   264 if (!accept_done || accept_ec) 91   264 if (!accept_done || accept_ec)
97   { 92   {
MISUBC 98   ✗ std::fprintf( 93   ✗ std::fprintf(
99   stderr, "socket_pair: accept failed (done=%d, ec=%s)\n", 94   stderr, "socket_pair: accept failed (done=%d, ec=%s)\n",
100   accept_done, accept_ec.message().c_str()); 95   accept_done, accept_ec.message().c_str());
MISUBC 101   ✗ acc.close(); 96   ✗ acc.close();
MISUBC 102   ✗ throw std::runtime_error("socket_pair accept failed"); 97   ✗ throw std::runtime_error("socket_pair accept failed");
103   } 98   }
104   99  
HITCBC 105   264 if (!connect_done || connect_ec) 100   264 if (!connect_done || connect_ec)
106   { 101   {
MISUBC 107   ✗ std::fprintf( 102   ✗ std::fprintf(
108   stderr, "socket_pair: connect failed (done=%d, ec=%s)\n", 103   stderr, "socket_pair: connect failed (done=%d, ec=%s)\n",
109   connect_done, connect_ec.message().c_str()); 104   connect_done, connect_ec.message().c_str());
MISUBC 110   ✗ acc.close(); 105   ✗ acc.close();
MISUBC 111   ✗ s1.close(); 106   ✗ s1.close();
MISUBC 112   ✗ throw std::runtime_error("socket_pair connect failed"); 107   ✗ throw std::runtime_error("socket_pair connect failed");
113   } 108   }
114   109  
HITCBC 115   264 acc.close(); 110   264 acc.close();
116   111  
117   if constexpr (Linger) 112   if constexpr (Linger)
118   { 113   {
HITCBC 119   93 s1.set_option(socket_option::linger(true, 0)); 114   93 s1.set_option(socket_option::linger(true, 0));
HITCBC 120   93 s2.set_option(socket_option::linger(true, 0)); 115   93 s2.set_option(socket_option::linger(true, 0));
121   } 116   }
122   117  
HITCBC 123   528 return {std::move(s1), std::move(s2)}; 118   528 return {std::move(s1), std::move(s2)};
HITCBC 124   264 } 119   264 }
125   120  
126   } // namespace boost::corosio::test 121   } // namespace boost::corosio::test
127   122  
128   #endif 123   #endif