src/corosio/src/tcp_acceptor.cpp

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