src/corosio/src/tcp_acceptor.cpp

100.0% Lines (63 / 63) 100.0% Functions (12 / 12)
tcp_acceptor.cpp
f(x) Functions (12)
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
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/native/detail/endpoint_convert.hpp>
13 #include <boost/corosio/socket_option.hpp>
14 #include <boost/corosio/detail/platform.hpp>
15
16 #if BOOST_COROSIO_HAS_IOCP
17 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
18 #else
19 #include <boost/corosio/detail/tcp_acceptor_service.hpp>
20 #endif
21
22 #include <boost/corosio/detail/except.hpp>
23
24 #include "src/detail/use_backend_service.hpp"
25
26 namespace boost::corosio {
27
28 #if BOOST_COROSIO_HAS_IOCP
29 namespace {
30
31 // On Windows SO_REUSEADDR grants bind-over ("hijack") rights instead
32 // of TIME_WAIT reuse, so a second listener would share the port
33 // silently. SO_EXCLUSIVEADDRUSE restores the POSIX contract: the
34 // collision surfaces as WSAEADDRINUSE (errc::address_in_use).
35 struct exclusive_address_use
36 {
37 int value_ = 1;
38
39 static int level(family) noexcept
40 {
41 return SOL_SOCKET;
42 }
43 static int name(family) noexcept
44 {
45 return SO_EXCLUSIVEADDRUSE;
46 }
47 void const* data(family) const noexcept
48 {
49 return &value_;
50 }
51 std::size_t size(family) const noexcept
52 {
53 return sizeof(value_);
54 }
55 };
56
57 } // namespace
58 #endif
59
60 664x tcp_acceptor::~tcp_acceptor()
61 {
62 664x close();
63 664x }
64
65 625x tcp_acceptor::tcp_acceptor(capy::execution_context& ctx)
66 625x : io_object(handle(
67 ctx,
68 detail::use_backend_service<
69 detail::tcp_acceptor_service_of,
70 #if BOOST_COROSIO_HAS_IOCP
71 detail::win_tcp_acceptor_service
72 #else
73 detail::tcp_acceptor_service
74 #endif
75 625x >(ctx)))
76 {
77 625x }
78
79 96x tcp_acceptor::tcp_acceptor(
80 96x capy::execution_context& ctx, endpoint ep, int backlog)
81 96x : tcp_acceptor(ctx)
82 {
83 96x if (auto ec = open(ep.address().family()))
84 2x detail::throw_system_error(ec, "tcp_acceptor");
85 #if BOOST_COROSIO_HAS_IOCP
86 set_option(exclusive_address_use{});
87 #else
88 94x set_option(socket_option::reuse_address(true));
89 #endif
90 94x if (auto ec = bind(ep))
91 4x detail::throw_system_error(ec, "tcp_acceptor");
92 90x if (auto ec = listen(backlog))
93 5x detail::throw_system_error(ec, "tcp_acceptor");
94 96x }
95
96 std::error_code
97 631x tcp_acceptor::open(family f) noexcept
98 {
99 631x if (is_open())
100 2x return {};
101
102 #if BOOST_COROSIO_HAS_IOCP
103 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
104 #else
105 629x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
106 #endif
107 1258x std::error_code ec = svc.open_acceptor_socket(
108 629x *static_cast<tcp_acceptor::implementation*>(h_.get()),
109 detail::native_family(f), SOCK_STREAM, IPPROTO_TCP);
110 629x return ec;
111 }
112
113 std::error_code
114 21x tcp_acceptor::assign(native_handle_type fd) noexcept
115 {
116 #if BOOST_COROSIO_HAS_IOCP
117 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
118 #else
119 21x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
120 #endif
121 21x std::error_code ec = svc.assign_socket(
122 21x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
123 21x return ec;
124 }
125
126 native_handle_type
127 14x tcp_acceptor::release()
128 {
129 14x if (!is_open())
130 2x detail::throw_system_error(
131 2x make_error_code(std::errc::bad_file_descriptor),
132 "tcp_acceptor::release");
133 12x return get().release_socket();
134 }
135
136 native_handle_type
137 26x tcp_acceptor::native_handle() const noexcept
138 {
139 26x if (!is_open())
140 {
141 #if BOOST_COROSIO_HAS_IOCP
142 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
143 #else
144 4x return -1;
145 #endif
146 }
147 22x return get().native_handle();
148 }
149
150 std::error_code
151 607x tcp_acceptor::bind(endpoint ep) noexcept
152 {
153 607x if (!is_open())
154 2x return make_error_code(std::errc::bad_file_descriptor);
155 #if BOOST_COROSIO_HAS_IOCP
156 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
157 #else
158 605x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
159 #endif
160 605x return svc.bind_acceptor(
161 1210x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
162 }
163
164 std::error_code
165 578x tcp_acceptor::listen(int backlog) noexcept
166 {
167 578x if (!is_open())
168 2x return make_error_code(std::errc::bad_file_descriptor);
169 #if BOOST_COROSIO_HAS_IOCP
170 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
171 #else
172 576x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
173 #endif
174 576x return svc.listen_acceptor(
175 1152x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
176 }
177
178 void
179 1063x tcp_acceptor::close() noexcept
180 {
181 1063x if (!is_open())
182 450x return;
183 613x h_.service().close(h_);
184 }
185
186 void
187 15x tcp_acceptor::cancel() noexcept
188 {
189 15x if (!is_open())
190 2x return;
191 13x get().cancel();
192 }
193
194 endpoint
195 547x tcp_acceptor::local_endpoint() const noexcept
196 {
197 547x if (!is_open())
198 2x return endpoint{};
199 545x return get().local_endpoint();
200 }
201
202 } // namespace boost::corosio
203