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   260 make_socket_pair(io_context& ctx) 50   260 make_socket_pair(io_context& ctx)
51   { 51   {
HITCBC 52   260 auto ex = ctx.get_executor(); 52   260 auto ex = ctx.get_executor();
53   53  
HITCBC 54   260 std::error_code accept_ec; 54   260 std::error_code accept_ec;
HITCBC 55   260 std::error_code connect_ec; 55   260 std::error_code connect_ec;
HITCBC 56   260 bool accept_done = false; 56   260 bool accept_done = false;
HITCBC 57   260 bool connect_done = false; 57   260 bool connect_done = false;
58   58  
HITCBC 59   260 Acceptor acc(ctx); 59   260 Acceptor acc(ctx);
HITCBC 60   260 if (auto open_ec = acc.open()) 60   260 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   260 acc.set_option(socket_option::reuse_address(true)); 63   260 acc.set_option(socket_option::reuse_address(true));
HITCBC 64   260 if (auto ec = acc.bind(endpoint(ipv4_address::loopback(), 0))) 64   260 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   260 if (auto ec = acc.listen()) 66   260 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   260 auto port = acc.local_endpoint().port(); 68   260 auto port = acc.local_endpoint().port();
69   69  
HITCBC 70   260 Socket s1(ctx); 70   260 Socket s1(ctx);
HITCBC 71   260 Socket s2(ctx); 71   260 Socket s2(ctx);
HITCBC 72   260 if (auto open_ec = s2.open()) 72   260 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   260 capy::run_async(ex)( 76   260 capy::run_async(ex)(
HITCBC 77   520 [](Acceptor& a, Socket& s, std::error_code& ec_out, 77   520 [](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   520 capy::run_async(ex)( 84   520 capy::run_async(ex)(
HITCBC 85   260 [](Socket& s, endpoint ep, std::error_code& ec_out, 85   260 [](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   520 }(s2, endpoint(ipv4_address::loopback(), port), connect_ec, 90   520 }(s2, endpoint(ipv4_address::loopback(), port), connect_ec,
91   connect_done)); 91   connect_done));
92   92  
HITCBC 93   260 ctx.run(); 93   260 ctx.run();
HITCBC 94   260 ctx.restart(); 94   260 ctx.restart();
95   95  
HITCBC 96   260 if (!accept_done || accept_ec) 96   260 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   260 if (!connect_done || connect_ec) 105   260 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   260 acc.close(); 115   260 acc.close();
116   116  
117   if constexpr (Linger) 117   if constexpr (Linger)
118   { 118   {
HITCBC 119   93 s1.set_option(socket_option::linger(true, 0)); 119   93 s1.set_option(socket_option::linger(true, 0));
HITCBC 120   93 s2.set_option(socket_option::linger(true, 0)); 120   93 s2.set_option(socket_option::linger(true, 0));
121   } 121   }
122   122  
HITCBC 123   520 return {std::move(s1), std::move(s2)}; 123   520 return {std::move(s1), std::move(s2)};
HITCBC 124   260 } 124   260 }
125   125  
126   } // namespace boost::corosio::test 126   } // namespace boost::corosio::test
127   127  
128   #endif 128   #endif