src/corosio/src/tcp_acceptor.cpp

100.0% Lines (62/0/62) 100.0% List of functions (12/0/12)
tcp_acceptor.cpp
f(x) Functions (12)
Line 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 2031x tcp_acceptor::~tcp_acceptor()
58 {
59 2031x close();
60 2031x }
61
62 1976x 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 1976x : io_object(create_handle<detail::tcp_acceptor_service>(ctx))
67 #endif
68 {
69 1976x }
70
71 124x tcp_acceptor::tcp_acceptor(
72 124x capy::execution_context& ctx, endpoint ep, int backlog)
73 124x : tcp_acceptor(ctx)
74 {
75 124x if (auto ec = open(ep.is_v6() ? tcp::v6() : tcp::v4()))
76 2x detail::throw_system_error(ec, "tcp_acceptor");
77 #if BOOST_COROSIO_HAS_IOCP
78 set_option(exclusive_address_use{});
79 #else
80 122x set_option(socket_option::reuse_address(true));
81 #endif
82 122x if (auto ec = bind(ep))
83 6x detail::throw_system_error(ec, "tcp_acceptor");
84 116x if (auto ec = listen(backlog))
85 9x detail::throw_system_error(ec, "tcp_acceptor");
86 124x }
87
88 std::error_code
89 1986x tcp_acceptor::open(tcp proto) noexcept
90 {
91 1986x if (is_open())
92 3x return {};
93
94 #if BOOST_COROSIO_HAS_IOCP
95 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
96 #else
97 1983x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
98 #endif
99 3966x std::error_code ec = svc.open_acceptor_socket(
100 1983x *static_cast<tcp_acceptor::implementation*>(h_.get()), proto.family(),
101 proto.type(), proto.protocol());
102 1983x return ec;
103 }
104
105 std::error_code
106 31x 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 31x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
112 #endif
113 31x std::error_code ec = svc.assign_socket(
114 31x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
115 31x return ec;
116 }
117
118 native_handle_type
119 19x tcp_acceptor::release()
120 {
121 19x if (!is_open())
122 3x detail::throw_system_error(
123 3x make_error_code(std::errc::bad_file_descriptor),
124 "tcp_acceptor::release");
125 16x return get().release_socket();
126 }
127
128 native_handle_type
129 40x tcp_acceptor::native_handle() const noexcept
130 {
131 40x if (!is_open())
132 {
133 #if BOOST_COROSIO_HAS_IOCP
134 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
135 #else
136 6x return -1;
137 #endif
138 }
139 34x return get().native_handle();
140 }
141
142 std::error_code
143 1953x tcp_acceptor::bind(endpoint ep) noexcept
144 {
145 1953x if (!is_open())
146 3x 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 1950x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
151 #endif
152 1950x return svc.bind_acceptor(
153 3900x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
154 }
155
156 std::error_code
157 1913x tcp_acceptor::listen(int backlog) noexcept
158 {
159 1913x if (!is_open())
160 3x 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 1910x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
165 #endif
166 1910x return svc.listen_acceptor(
167 3820x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
168 }
169
170 void
171 3703x tcp_acceptor::close() noexcept
172 {
173 3703x if (!is_open())
174 1738x return;
175 1965x h_.service().close(h_);
176 }
177
178 void
179 20x tcp_acceptor::cancel() noexcept
180 {
181 20x if (!is_open())
182 3x return;
183 17x get().cancel();
184 }
185
186 endpoint
187 1859x tcp_acceptor::local_endpoint() const noexcept
188 {
189 1859x if (!is_open())
190 3x return endpoint{};
191 1856x return get().local_endpoint();
192 }
193
194 } // namespace boost::corosio
195