src/corosio/src/tcp_acceptor.cpp

100.0% Lines (77/77) 100.0% List of functions (12/12) 57.8% Branches (37/64)
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 // Copyright (c) 2026 Michael Vandeberg
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // Official repository: https://github.com/cppalliance/corosio
10 //
11
12 #include <boost/corosio/tcp_acceptor.hpp>
13 #include <boost/corosio/error.hpp>
14 #include <boost/corosio/native/detail/endpoint_convert.hpp>
15 #include <boost/corosio/socket_option.hpp>
16 #include <boost/corosio/detail/platform.hpp>
17
18 #if BOOST_COROSIO_HAS_IOCP
19 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
20 #else
21 #include <boost/corosio/detail/tcp_acceptor_service.hpp>
22 #endif
23
24 #include <boost/corosio/detail/except.hpp>
25
26 #include "src/detail/use_backend_service.hpp"
27
28 namespace boost::corosio {
29
30 #if BOOST_COROSIO_HAS_IOCP
31 namespace {
32
33 // On Windows SO_REUSEADDR grants bind-over ("hijack") rights instead
34 // of TIME_WAIT reuse, so a second listener would share the port
35 // silently. SO_EXCLUSIVEADDRUSE restores the POSIX contract: the
36 // collision surfaces as WSAEADDRINUSE (errc::address_in_use).
37 struct exclusive_address_use
38 {
39 int value_ = 1;
40
41 static int level(family) noexcept
42 {
43 return SOL_SOCKET;
44 }
45 static int name(family) noexcept
46 {
47 return SO_EXCLUSIVEADDRUSE;
48 }
49 void const* data(family) const noexcept
50 {
51 return &value_;
52 }
53 std::size_t size(family) const noexcept
54 {
55 return sizeof(value_);
56 }
57 };
58
59 } // namespace
60 #endif
61
62 4757x tcp_acceptor::~tcp_acceptor()
63 4757x {
64 2400x close();
65 4757x }
66
67 4714x tcp_acceptor::tcp_acceptor(capy::execution_context& ctx)
68 2357x : io_object(handle(
69 2357x ctx,
70 2357x detail::use_backend_service<
71 detail::tcp_acceptor_service_of,
72 #if BOOST_COROSIO_HAS_IOCP
73 detail::win_tcp_acceptor_service
74 #else
75 detail::tcp_acceptor_service
76 #endif
77 2357x >(ctx)))
78 4714x {
79 4714x }
80
81 77x tcp_acceptor::tcp_acceptor(
82 capy::execution_context& ctx, endpoint ep, int backlog)
83 77x : tcp_acceptor(ctx)
84 {
85
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 75 times.
77x if (auto ec = open(ep.address().family()))
86
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");
87 #if BOOST_COROSIO_HAS_IOCP
88 set_option(exclusive_address_use{});
89 #else
90
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));
91 #endif
92
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))
93
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");
94
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))
95
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");
96 77x }
97
98 std::error_code
99 2367x tcp_acceptor::open(family f) noexcept
100 {
101
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2365 times.
2367x if (is_open())
102 2x return {};
103
104 #if BOOST_COROSIO_HAS_IOCP
105 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
106 #else
107 2365x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
108 #endif
109
2/4
✓ Branch 0 taken 2365 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2365 times.
✗ Branch 3 not taken.
4730x std::error_code ec = svc.open_acceptor_socket(
110 2365x *static_cast<tcp_acceptor::implementation*>(h_.get()),
111 2365x detail::native_family(f), SOCK_STREAM, IPPROTO_TCP);
112 2365x return ec;
113 2367x }
114
115 std::error_code
116 23x tcp_acceptor::assign(native_handle_type fd) noexcept
117 {
118
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 17 times.
23x if (is_open())
119 6x return make_error_code(error::already_open);
120 #if BOOST_COROSIO_HAS_IOCP
121 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
122 #else
123 17x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
124 #endif
125
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
34x std::error_code ec = svc.assign_socket(
126 17x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
127 17x return ec;
128 23x }
129
130 native_handle_type
131 14x tcp_acceptor::release()
132 {
133
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
14x if (!is_open())
134 2x detail::throw_system_error(
135 2x make_error_code(std::errc::bad_file_descriptor),
136 "tcp_acceptor::release");
137 12x return get().release_socket();
138 }
139
140 native_handle_type
141 32x tcp_acceptor::native_handle() const noexcept
142 {
143
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 28 times.
32x if (!is_open())
144 {
145 #if BOOST_COROSIO_HAS_IOCP
146 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
147 #else
148 4x return -1;
149 #endif
150 }
151 28x return get().native_handle();
152 32x }
153
154 std::error_code
155 2342x tcp_acceptor::bind(endpoint ep) noexcept
156 {
157
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2340 times.
2342x if (!is_open())
158 2x return make_error_code(std::errc::bad_file_descriptor);
159 #if BOOST_COROSIO_HAS_IOCP
160 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
161 #else
162 2340x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
163 #endif
164
2/4
✓ Branch 0 taken 2340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2340 times.
✗ Branch 3 not taken.
4680x return svc.bind_acceptor(
165 2340x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
166 2342x }
167
168 std::error_code
169 2313x tcp_acceptor::listen(int backlog) noexcept
170 {
171
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2311 times.
2313x if (!is_open())
172 2x return make_error_code(std::errc::bad_file_descriptor);
173 #if BOOST_COROSIO_HAS_IOCP
174 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
175 #else
176 2311x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
177 #endif
178
2/4
✓ Branch 0 taken 2311 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2311 times.
✗ Branch 3 not taken.
4622x return svc.listen_acceptor(
179 2311x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
180 2313x }
181
182 void
183 4557x tcp_acceptor::close() noexcept
184 {
185
2/2
✓ Branch 0 taken 2346 times.
✓ Branch 1 taken 2211 times.
4557x if (!is_open())
186 2211x return;
187
1/2
✓ Branch 0 taken 2346 times.
✗ Branch 1 not taken.
2346x h_.service().close(h_);
188 4557x }
189
190 void
191 17x tcp_acceptor::cancel() noexcept
192 {
193
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
17x if (!is_open())
194 2x return;
195 15x get().cancel();
196 17x }
197
198 endpoint
199 2288x tcp_acceptor::local_endpoint() const noexcept
200 {
201
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2286 times.
2288x if (!is_open())
202 2x return endpoint{};
203 2286x return get().local_endpoint();
204 2288x }
205
206 } // namespace boost::corosio
207