src/corosio/src/tcp_acceptor.cpp

100.0% Lines (70/70) 100.0% List of functions (16/16) 100.0% Branches (26/26)
tcp_acceptor.cpp
f(x) Functions (16)
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 26x static int level() noexcept
37 {
38 26x return SOL_SOCKET;
39 }
40 26x static int name() noexcept
41 {
42 26x return SO_EXCLUSIVEADDRUSE;
43 }
44 26x void const* data() const noexcept
45 {
46 26x return &value_;
47 }
48 26x std::size_t size() const noexcept
49 {
50 26x return sizeof(value_);
51 }
52 };
53
54 } // namespace
55 #endif
56
57 1960x tcp_acceptor::~tcp_acceptor()
58 {
59 1960x close();
60 1960x }
61
62 1943x tcp_acceptor::tcp_acceptor(capy::execution_context& ctx)
63 #if BOOST_COROSIO_HAS_IOCP
64
1/1
✓ Branch 2 → 3 taken 1943 times.
1943x : io_object(create_handle<detail::win_tcp_acceptor_service>(ctx))
65 #else
66 : io_object(create_handle<detail::tcp_acceptor_service>(ctx))
67 #endif
68 {
69 1943x }
70
71 27x tcp_acceptor::tcp_acceptor(
72 27x capy::execution_context& ctx, endpoint ep, int backlog)
73 27x : tcp_acceptor(ctx)
74 {
75
4/4
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 26 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 26 times.
27x if (auto ec = open(ep.is_v6() ? tcp::v6() : tcp::v4()))
76 1x detail::throw_system_error(ec, "tcp_acceptor");
77 #if BOOST_COROSIO_HAS_IOCP
78
1/1
✓ Branch 11 → 12 taken 26 times.
26x set_option(exclusive_address_use{});
79 #else
80 set_option(socket_option::reuse_address(true));
81 #endif
82
2/2
✓ Branch 14 → 15 taken 2 times.
✓ Branch 14 → 16 taken 24 times.
26x if (auto ec = bind(ep))
83 2x detail::throw_system_error(ec, "tcp_acceptor");
84
2/2
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 23 times.
24x if (auto ec = listen(backlog))
85 1x detail::throw_system_error(ec, "tcp_acceptor");
86 27x }
87
88 std::error_code
89 1928x tcp_acceptor::open(tcp proto) noexcept
90 {
91
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1927 times.
1928x if (is_open())
92 1x return {};
93
94 #if BOOST_COROSIO_HAS_IOCP
95 1927x auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
96 #else
97 auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
98 #endif
99 3854x std::error_code ec = svc.open_acceptor_socket(
100 1927x *static_cast<tcp_acceptor::implementation*>(h_.get()), proto.family(),
101 proto.type(), proto.protocol());
102 1927x return ec;
103 }
104
105 std::error_code
106 26x tcp_acceptor::assign(native_handle_type fd) noexcept
107 {
108 #if BOOST_COROSIO_HAS_IOCP
109 26x auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
110 #else
111 auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
112 #endif
113 26x std::error_code ec = svc.assign_socket(
114 26x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
115 26x return ec;
116 }
117
118 native_handle_type
119 5x tcp_acceptor::release()
120 {
121
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 4 times.
5x if (!is_open())
122 1x detail::throw_system_error(
123 1x make_error_code(std::errc::bad_file_descriptor),
124 "tcp_acceptor::release");
125 4x return get().release_socket();
126 }
127
128 native_handle_type
129 13x tcp_acceptor::native_handle() const noexcept
130 {
131
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 11 times.
13x if (!is_open())
132 {
133 #if BOOST_COROSIO_HAS_IOCP
134 2x return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
135 #else
136 return -1;
137 #endif
138 }
139 11x return get().native_handle();
140 }
141
142 std::error_code
143 1912x tcp_acceptor::bind(endpoint ep) noexcept
144 {
145
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1911 times.
1912x if (!is_open())
146 1x return make_error_code(std::errc::bad_file_descriptor);
147 #if BOOST_COROSIO_HAS_IOCP
148 1911x auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
149 #else
150 auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
151 #endif
152 1911x return svc.bind_acceptor(
153 3822x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
154 }
155
156 std::error_code
157 1893x tcp_acceptor::listen(int backlog) noexcept
158 {
159
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1892 times.
1893x if (!is_open())
160 1x return make_error_code(std::errc::bad_file_descriptor);
161 #if BOOST_COROSIO_HAS_IOCP
162 1892x auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
163 #else
164 auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
165 #endif
166 1892x return svc.listen_acceptor(
167 3784x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
168 }
169
170 void
171 3799x tcp_acceptor::close() noexcept
172 {
173
2/2
✓ Branch 3 → 4 taken 1886 times.
✓ Branch 3 → 5 taken 1913 times.
3799x if (!is_open())
174 1886x return;
175 1913x h_.service().close(h_);
176 }
177
178 void
179 6x tcp_acceptor::cancel() noexcept
180 {
181
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 5 times.
6x if (!is_open())
182 1x return;
183 5x get().cancel();
184 }
185
186 endpoint
187 1883x tcp_acceptor::local_endpoint() const noexcept
188 {
189
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1882 times.
1883x if (!is_open())
190 1x return endpoint{};
191 1882x return get().local_endpoint();
192 }
193
194 } // namespace boost::corosio
195