Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/corosio
8 : //
9 :
10 : #include <boost/corosio/test/socket_pair.hpp>
11 : #include <boost/corosio/tcp_acceptor.hpp>
12 : #include <system_error>
13 : #include <boost/corosio/basic_io_context.hpp>
14 : #include <boost/corosio/detail/platform.hpp>
15 : #include <boost/capy/ex/run_async.hpp>
16 : #include <boost/capy/task.hpp>
17 :
18 : #include <cstdio>
19 : #include <stdexcept>
20 :
21 : namespace boost::corosio::test {
22 :
23 : std::pair<tcp_socket, tcp_socket>
24 2 : make_socket_pair(basic_io_context& ctx)
25 : {
26 2 : auto ex = ctx.get_executor();
27 :
28 2 : std::error_code accept_ec;
29 2 : std::error_code connect_ec;
30 2 : bool accept_done = false;
31 2 : bool connect_done = false;
32 :
33 : // Use ephemeral port (0) - OS assigns an available port
34 2 : tcp_acceptor acc(ctx);
35 2 : if (auto ec = acc.listen(endpoint(ipv4_address::loopback(), 0)))
36 0 : throw std::runtime_error("socket_pair listen failed: " + ec.message());
37 2 : auto port = acc.local_endpoint().port();
38 :
39 2 : tcp_socket s1(ctx);
40 2 : tcp_socket s2(ctx);
41 2 : s2.open();
42 :
43 4 : capy::run_async(ex)(
44 2 : [](tcp_acceptor& a, tcp_socket& s,
45 : std::error_code& ec_out, bool& done_out) -> capy::task<>
46 : {
47 : auto [ec] = co_await a.accept(s);
48 : ec_out = ec;
49 : done_out = true;
50 8 : }(acc, s1, accept_ec, accept_done));
51 :
52 4 : capy::run_async(ex)(
53 2 : [](tcp_socket& s, endpoint ep,
54 : std::error_code& ec_out, bool& done_out) -> capy::task<>
55 : {
56 : auto [ec] = co_await s.connect(ep);
57 : ec_out = ec;
58 : done_out = true;
59 8 : }(s2, endpoint(ipv4_address::loopback(), port),
60 : connect_ec, connect_done));
61 :
62 2 : ctx.run();
63 2 : ctx.restart();
64 :
65 2 : if (!accept_done || accept_ec)
66 : {
67 0 : std::fprintf(stderr, "socket_pair: accept failed (done=%d, ec=%s)\n",
68 0 : accept_done, accept_ec.message().c_str());
69 0 : acc.close();
70 0 : throw std::runtime_error("socket_pair accept failed");
71 : }
72 :
73 2 : if (!connect_done || connect_ec)
74 : {
75 0 : std::fprintf(stderr, "socket_pair: connect failed (done=%d, ec=%s)\n",
76 0 : connect_done, connect_ec.message().c_str());
77 0 : acc.close();
78 0 : s1.close();
79 0 : throw std::runtime_error("socket_pair connect failed");
80 : }
81 :
82 2 : acc.close();
83 :
84 4 : return {std::move(s1), std::move(s2)};
85 2 : }
86 :
87 : } // namespace boost::corosio::test
|