src/corosio/src/tcp_acceptor.cpp

100.0% Lines (71/71) 100.0% List of functions (12/12) 56.1% Branches (37/66)
tcp_acceptor.cpp
f(x) Functions (12)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
3 // Copyright (c) 2026 Steve Gerbino
4 //
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)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #include <boost/corosio/tcp_acceptor.hpp>
12 #include <boost/corosio/socket_option.hpp>
13 #include <boost/corosio/detail/platform.hpp>
14
15 #if BOOST_COROSIO_HAS_IOCP
16 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
17 #else
18 #include <boost/corosio/detail/tcp_acceptor_service.hpp>
19 #endif
20
21 #include <boost/corosio/detail/except.hpp>
22
23 namespace boost::corosio {
24
25 #if BOOST_COROSIO_HAS_IOCP
26 namespace {
27
28 // On Windows SO_REUSEADDR grants bind-over ("hijack") rights instead
29 // of TIME_WAIT reuse, so a second listener would share the port
30 // silently. SO_EXCLUSIVEADDRUSE restores the POSIX contract: the
31 // collision surfaces as WSAEADDRINUSE (errc::address_in_use).
32 struct exclusive_address_use
33 {
34 int value_ = 1;
35
36 static int level() noexcept
37 {
38 return SOL_SOCKET;
39 }
40 static int name() noexcept
41 {
42 return SO_EXCLUSIVEADDRUSE;
43 }
44 void const* data() const noexcept
45 {
46 return &value_;
47 }
48 std::size_t size() const noexcept
49 {
50 return sizeof(value_);
51 }
52 };
53
54 } // namespace
55 #endif
56
57 3249x tcp_acceptor::~tcp_acceptor()
58 3249x {
59 1645x close();
60 3249x }
61
62 3208x tcp_acceptor::tcp_acceptor(capy::execution_context& ctx)
63 #if BOOST_COROSIO_HAS_IOCP
64 : io_object(create_handle<detail::win_tcp_acceptor_service>(ctx))
65 #else
66 1604x : io_object(create_handle<detail::tcp_acceptor_service>(ctx))
67 #endif
68 3208x {
69 3208x }
70
71 77x tcp_acceptor::tcp_acceptor(
72 capy::execution_context& ctx, endpoint ep, int backlog)
73 77x : tcp_acceptor(ctx)
74 {
75
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 75 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 75 times.
77x if (auto ec = open(ep.is_v6() ? tcp::v6() : tcp::v4()))
76
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2x detail::throw_system_error(ec, "tcp_acceptor");
77 #if BOOST_COROSIO_HAS_IOCP
78 set_option(exclusive_address_use{});
79 #else
80
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
75x set_option(socket_option::reuse_address(true));
81 #endif
82
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 71 times.
75x if (auto ec = bind(ep))
83
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4x detail::throw_system_error(ec, "tcp_acceptor");
84
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 69 times.
71x if (auto ec = listen(backlog))
85
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2x detail::throw_system_error(ec, "tcp_acceptor");
86 77x }
87
88 std::error_code
89 1614x tcp_acceptor::open(tcp proto) noexcept
90 {
91
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1612 times.
1614x if (is_open())
92 2x return {};
93
94 #if BOOST_COROSIO_HAS_IOCP
95 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
96 #else
97 1612x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
98 #endif
99
2/4
✓ Branch 0 taken 1612 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1612 times.
✗ Branch 3 not taken.
3224x std::error_code ec = svc.open_acceptor_socket(
100 1612x *static_cast<tcp_acceptor::implementation*>(h_.get()), proto.family(),
101 1612x proto.type(), proto.protocol());
102 1612x return ec;
103 1614x }
104
105 std::error_code
106 21x tcp_acceptor::assign(native_handle_type fd) noexcept
107 {
108 #if BOOST_COROSIO_HAS_IOCP
109 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
110 #else
111 21x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
112 #endif
113
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
42x std::error_code ec = svc.assign_socket(
114 21x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
115 21x return ec;
116 }
117
118 native_handle_type
119 14x tcp_acceptor::release()
120 {
121
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
14x if (!is_open())
122 2x detail::throw_system_error(
123 2x make_error_code(std::errc::bad_file_descriptor),
124 "tcp_acceptor::release");
125 12x return get().release_socket();
126 }
127
128 native_handle_type
129 26x tcp_acceptor::native_handle() const noexcept
130 {
131
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 22 times.
26x if (!is_open())
132 {
133 #if BOOST_COROSIO_HAS_IOCP
134 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
135 #else
136 4x return -1;
137 #endif
138 }
139 22x return get().native_handle();
140 26x }
141
142 std::error_code
143 1591x tcp_acceptor::bind(endpoint ep) noexcept
144 {
145
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1589 times.
1591x if (!is_open())
146 2x return make_error_code(std::errc::bad_file_descriptor);
147 #if BOOST_COROSIO_HAS_IOCP
148 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
149 #else
150 1589x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
151 #endif
152
2/4
✓ Branch 0 taken 1589 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1589 times.
✗ Branch 3 not taken.
3178x return svc.bind_acceptor(
153 1589x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
154 1591x }
155
156 std::error_code
157 1562x tcp_acceptor::listen(int backlog) noexcept
158 {
159
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1560 times.
1562x if (!is_open())
160 2x return make_error_code(std::errc::bad_file_descriptor);
161 #if BOOST_COROSIO_HAS_IOCP
162 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
163 #else
164 1560x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
165 #endif
166
2/4
✓ Branch 0 taken 1560 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1560 times.
✗ Branch 3 not taken.
3120x return svc.listen_acceptor(
167 1560x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
168 1562x }
169
170 void
171 3051x tcp_acceptor::close() noexcept
172 {
173
2/2
✓ Branch 0 taken 1593 times.
✓ Branch 1 taken 1458 times.
3051x if (!is_open())
174 1458x return;
175
1/2
✓ Branch 0 taken 1593 times.
✗ Branch 1 not taken.
1593x h_.service().close(h_);
176 3051x }
177
178 void
179 15x tcp_acceptor::cancel() noexcept
180 {
181
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 13 times.
15x if (!is_open())
182 2x return;
183 13x get().cancel();
184 15x }
185
186 endpoint
187 1537x tcp_acceptor::local_endpoint() const noexcept
188 {
189
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1535 times.
1537x if (!is_open())
190 2x return endpoint{};
191 1535x return get().local_endpoint();
192 1537x }
193
194 } // namespace boost::corosio
195