src/corosio/src/tcp_acceptor.cpp

100.0% Lines (72 / 72) 100.0% Functions (15 / 15)
tcp_acceptor.cpp
f(x) Functions (15)
Line 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/detail/platform.hpp>
16
17 #if BOOST_COROSIO_HAS_IOCP
18 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
19 #else
20 #include <boost/corosio/detail/tcp_acceptor_service.hpp>
21 #include <boost/corosio/detail/tcp_service.hpp>
22 #endif
23
24 #include <boost/corosio/detail/except.hpp>
25
26 #include "src/detail/open_listener.hpp"
27 #include "src/detail/use_backend_service.hpp"
28
29 namespace boost::corosio {
30
31 namespace {
32
33 #if BOOST_COROSIO_HAS_IOCP
34 using tcp_peer_service = detail::win_tcp_service;
35 #else
36 using tcp_peer_service = detail::tcp_service;
37 #endif
38
39 void
40 57x open_listener_or_throw(tcp_acceptor& acc, endpoint ep, int backlog)
41 {
42 57x if (auto ec = detail::open_listener(acc, ep, backlog))
43 17x detail::throw_system_error(ec, "tcp_acceptor");
44 40x }
45
46 } // namespace
47
48 5081x tcp_acceptor::~tcp_acceptor()
49 {
50 5081x close();
51 5081x }
52
53 4764x tcp_acceptor::tcp_acceptor(capy::execution_context& ctx)
54 4764x : io_object(handle(
55 ctx,
56 detail::use_backend_service<
57 detail::tcp_acceptor_service_of,
58 #if BOOST_COROSIO_HAS_IOCP
59 detail::win_tcp_acceptor_service
60 #else
61 detail::tcp_acceptor_service
62 #endif
63 4764x >(ctx)))
64 {
65 4764x }
66
67 45x tcp_acceptor::tcp_acceptor(
68 45x capy::execution_context& ctx, endpoint ep, int backlog)
69 45x : tcp_acceptor(ctx)
70 {
71 45x open_listener_or_throw(*this, ep, backlog);
72 45x }
73
74 12x tcp_acceptor::tcp_acceptor(handle h, endpoint ep, int backlog)
75 12x : tcp_acceptor(std::move(h))
76 {
77 12x open_listener_or_throw(*this, ep, backlog);
78 12x }
79
80 std::error_code
81 4738x tcp_acceptor::open(family f) noexcept
82 {
83 4738x if (is_open())
84 3x return {};
85
86 #if BOOST_COROSIO_HAS_IOCP
87 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
88 #else
89 4735x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
90 #endif
91 9470x std::error_code ec = svc.open_acceptor_socket(
92 4735x *static_cast<tcp_acceptor::implementation*>(h_.get()),
93 detail::native_family(f), SOCK_STREAM, IPPROTO_TCP);
94 4735x return ec;
95 }
96
97 std::error_code
98 35x tcp_acceptor::assign(native_handle_type fd) noexcept
99 {
100 35x if (is_open())
101 9x return make_error_code(error::already_open);
102 #if BOOST_COROSIO_HAS_IOCP
103 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
104 #else
105 26x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
106 #endif
107 26x std::error_code ec = svc.assign_socket(
108 26x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
109 26x return ec;
110 }
111
112 capy::results<native_handle_type>
113 20x tcp_acceptor::release() noexcept
114 {
115 20x if (!is_open())
116 return {
117 6x make_error_code(std::errc::bad_file_descriptor),
118 3x detail::invalid_native_handle};
119 17x return {std::error_code{}, get().release_socket()};
120 }
121
122 native_handle_type
123 52x tcp_acceptor::native_handle() const noexcept
124 {
125 52x if (!is_open())
126 {
127 #if BOOST_COROSIO_HAS_IOCP
128 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
129 #else
130 6x return -1;
131 #endif
132 }
133 46x return get().native_handle();
134 }
135
136 std::error_code
137 4666x tcp_acceptor::bind(endpoint ep) noexcept
138 {
139 4666x if (!is_open())
140 3x return make_error_code(std::errc::bad_file_descriptor);
141 #if BOOST_COROSIO_HAS_IOCP
142 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
143 #else
144 4663x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
145 #endif
146 4663x return svc.bind_acceptor(
147 9326x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
148 }
149
150 std::error_code
151 4621x tcp_acceptor::listen(int backlog) noexcept
152 {
153 4621x if (!is_open())
154 3x 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 4618x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
159 #endif
160 4618x return svc.listen_acceptor(
161 9236x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
162 }
163
164 void
165 8170x tcp_acceptor::close() noexcept
166 {
167 8170x if (!is_open())
168 4275x return;
169 3895x h_.service().close(h_);
170 }
171
172 void
173 39x tcp_acceptor::cancel() noexcept
174 {
175 39x if (!is_open())
176 3x return;
177 36x get().cancel();
178 }
179
180 endpoint
181 3306x tcp_acceptor::local_endpoint() const noexcept
182 {
183 3306x if (!is_open())
184 3x return endpoint{};
185 3303x return get().local_endpoint();
186 }
187
188 void
189 12x tcp_acceptor::discard_peer(
190 tcp_acceptor& acc, io_object::implementation* impl) noexcept
191 {
192 // Its own handle closes and releases the peer, as the socket the
193 // awaiter would have received does.
194 12x auto& ctx = acc.context();
195 handle h(
196 ctx,
197 12x detail::use_backend_service<detail::tcp_service_of, tcp_peer_service>(
198 ctx),
199 12x impl);
200 12x }
201
202 } // namespace boost::corosio
203