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