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 (vinnie.falco@gmail.com)
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 33x open_listener_or_throw(tcp_acceptor& acc, endpoint ep, int backlog)
41 {
42 33x if (auto ec = detail::open_listener(acc, ep, backlog))
43 11x detail::throw_system_error(ec, "tcp_acceptor");
44 22x }
45
46 } // namespace
47
48 2559x tcp_acceptor::~tcp_acceptor()
49 {
50 2559x close();
51 2559x }
52
53 2330x tcp_acceptor::tcp_acceptor(capy::execution_context& ctx)
54 2330x : 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 2330x >(ctx)))
64 {
65 2330x }
66
67 25x tcp_acceptor::tcp_acceptor(
68 25x capy::execution_context& ctx, endpoint ep, int backlog)
69 25x : tcp_acceptor(ctx)
70 {
71 25x open_listener_or_throw(*this, ep, backlog);
72 25x }
73
74 8x tcp_acceptor::tcp_acceptor(handle h, endpoint ep, int backlog)
75 8x : tcp_acceptor(std::move(h))
76 {
77 8x open_listener_or_throw(*this, ep, backlog);
78 8x }
79
80 std::error_code
81 2312x tcp_acceptor::open(family f) noexcept
82 {
83 2312x if (is_open())
84 2x return {};
85
86 #if BOOST_COROSIO_HAS_IOCP
87 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
88 #else
89 2310x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
90 #endif
91 4620x std::error_code ec = svc.open_acceptor_socket(
92 2310x *static_cast<tcp_acceptor::implementation*>(h_.get()),
93 detail::native_family(f), SOCK_STREAM, IPPROTO_TCP);
94 2310x return ec;
95 }
96
97 std::error_code
98 23x tcp_acceptor::assign(native_handle_type fd) noexcept
99 {
100 23x if (is_open())
101 6x 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 17x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
106 #endif
107 17x std::error_code ec = svc.assign_socket(
108 17x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
109 17x return ec;
110 }
111
112 capy::results<native_handle_type>
113 14x tcp_acceptor::release() noexcept
114 {
115 14x if (!is_open())
116 return {
117 4x make_error_code(std::errc::bad_file_descriptor),
118 2x detail::invalid_native_handle};
119 12x return {std::error_code{}, get().release_socket()};
120 }
121
122 native_handle_type
123 34x tcp_acceptor::native_handle() const noexcept
124 {
125 34x if (!is_open())
126 {
127 #if BOOST_COROSIO_HAS_IOCP
128 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
129 #else
130 4x return -1;
131 #endif
132 }
133 30x return get().native_handle();
134 }
135
136 std::error_code
137 2266x tcp_acceptor::bind(endpoint ep) noexcept
138 {
139 2266x if (!is_open())
140 2x 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 2264x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
145 #endif
146 2264x return svc.bind_acceptor(
147 4528x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
148 }
149
150 std::error_code
151 2233x tcp_acceptor::listen(int backlog) noexcept
152 {
153 2233x 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 2231x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
159 #endif
160 2231x return svc.listen_acceptor(
161 4462x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
162 }
163
164 void
165 3838x tcp_acceptor::close() noexcept
166 {
167 3838x if (!is_open())
168 2360x return;
169 1478x h_.service().close(h_);
170 }
171
172 void
173 29x tcp_acceptor::cancel() noexcept
174 {
175 29x if (!is_open())
176 2x return;
177 27x get().cancel();
178 }
179
180 endpoint
181 1360x tcp_acceptor::local_endpoint() const noexcept
182 {
183 1360x if (!is_open())
184 2x return endpoint{};
185 1358x return get().local_endpoint();
186 }
187
188 void
189 8x 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 8x auto& ctx = acc.context();
195 handle h(
196 ctx,
197 8x detail::use_backend_service<detail::tcp_service_of, tcp_peer_service>(
198 ctx),
199 8x impl);
200 8x }
201
202 } // namespace boost::corosio
203