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 (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/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 654x tcp_acceptor::~tcp_acceptor()
58 {
59 654x close();
60 654x }
61
62 617x 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 617x : io_object(create_handle<detail::tcp_acceptor_service>(ctx))
67 #endif
68 {
69 617x }
70
71 96x tcp_acceptor::tcp_acceptor(
72 96x capy::execution_context& ctx, endpoint ep, int backlog)
73 96x : tcp_acceptor(ctx)
74 {
75 96x 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 94x set_option(socket_option::reuse_address(true));
81 #endif
82 94x if (auto ec = bind(ep))
83 4x detail::throw_system_error(ec, "tcp_acceptor");
84 90x if (auto ec = listen(backlog))
85 5x detail::throw_system_error(ec, "tcp_acceptor");
86 96x }
87
88 std::error_code
89 623x tcp_acceptor::open(tcp proto) noexcept
90 {
91 623x 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 621x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
98 #endif
99 1242x std::error_code ec = svc.open_acceptor_socket(
100 621x *static_cast<tcp_acceptor::implementation*>(h_.get()), proto.family(),
101 proto.type(), proto.protocol());
102 621x return ec;
103 }
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 21x 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 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 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 }
141
142 std::error_code
143 599x tcp_acceptor::bind(endpoint ep) noexcept
144 {
145 599x 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 597x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
151 #endif
152 597x return svc.bind_acceptor(
153 1194x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
154 }
155
156 std::error_code
157 570x tcp_acceptor::listen(int backlog) noexcept
158 {
159 570x 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 568x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
165 #endif
166 568x return svc.listen_acceptor(
167 1136x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
168 }
169
170 void
171 1045x tcp_acceptor::close() noexcept
172 {
173 1045x if (!is_open())
174 440x return;
175 605x h_.service().close(h_);
176 }
177
178 void
179 15x tcp_acceptor::cancel() noexcept
180 {
181 15x if (!is_open())
182 2x return;
183 13x get().cancel();
184 }
185
186 endpoint
187 539x tcp_acceptor::local_endpoint() const noexcept
188 {
189 539x if (!is_open())
190 2x return endpoint{};
191 537x return get().local_endpoint();
192 }
193
194 } // namespace boost::corosio
195