src/corosio/src/tcp_acceptor.cpp

96.8% Lines (60/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 { return SOL_SOCKET; }
37 static int name() noexcept { return SO_EXCLUSIVEADDRUSE; }
38 void const* data() const noexcept { return &value_; }
39 std::size_t size() const noexcept { return sizeof(value_); }
40 };
41
42 } // namespace
43 #endif
44
45 455x tcp_acceptor::~tcp_acceptor()
46 {
47 455x close();
48 455x }
49
50 419x tcp_acceptor::tcp_acceptor(capy::execution_context& ctx)
51 #if BOOST_COROSIO_HAS_IOCP
52 : io_object(create_handle<detail::win_tcp_acceptor_service>(ctx))
53 #else
54 419x : io_object(create_handle<detail::tcp_acceptor_service>(ctx))
55 #endif
56 {
57 419x }
58
59 40x tcp_acceptor::tcp_acceptor(
60 40x capy::execution_context& ctx, endpoint ep, int backlog)
61 40x : tcp_acceptor(ctx)
62 {
63 40x if (auto ec = open(ep.is_v6() ? tcp::v6() : tcp::v4()))
64 detail::throw_system_error(ec, "tcp_acceptor");
65 #if BOOST_COROSIO_HAS_IOCP
66 set_option(exclusive_address_use{});
67 #else
68 40x set_option(socket_option::reuse_address(true));
69 #endif
70 40x if (auto ec = bind(ep))
71 4x detail::throw_system_error(ec, "tcp_acceptor");
72 36x if (auto ec = listen(backlog))
73 detail::throw_system_error(ec, "tcp_acceptor");
74 40x }
75
76 std::error_code
77 419x tcp_acceptor::open(tcp proto) noexcept
78 {
79 419x if (is_open())
80 2x return {};
81
82 #if BOOST_COROSIO_HAS_IOCP
83 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
84 #else
85 417x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
86 #endif
87 834x std::error_code ec = svc.open_acceptor_socket(
88 417x *static_cast<tcp_acceptor::implementation*>(h_.get()), proto.family(),
89 proto.type(), proto.protocol());
90 417x return ec;
91 }
92
93 std::error_code
94 18x tcp_acceptor::assign(native_handle_type fd) noexcept
95 {
96 #if BOOST_COROSIO_HAS_IOCP
97 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
98 #else
99 18x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
100 #endif
101 18x std::error_code ec = svc.assign_socket(
102 18x *static_cast<tcp_acceptor::implementation*>(h_.get()), fd);
103 18x return ec;
104 }
105
106 native_handle_type
107 10x tcp_acceptor::release()
108 {
109 10x if (!is_open())
110 2x detail::throw_system_error(
111 2x make_error_code(std::errc::bad_file_descriptor),
112 "tcp_acceptor::release");
113 8x return get().release_socket();
114 }
115
116 native_handle_type
117 26x tcp_acceptor::native_handle() const noexcept
118 {
119 26x if (!is_open())
120 {
121 #if BOOST_COROSIO_HAS_IOCP
122 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
123 #else
124 4x return -1;
125 #endif
126 }
127 22x return get().native_handle();
128 }
129
130 std::error_code
131 407x tcp_acceptor::bind(endpoint ep) noexcept
132 {
133 407x if (!is_open())
134 2x return make_error_code(std::errc::bad_file_descriptor);
135 #if BOOST_COROSIO_HAS_IOCP
136 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
137 #else
138 405x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
139 #endif
140 405x return svc.bind_acceptor(
141 810x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
142 }
143
144 std::error_code
145 377x tcp_acceptor::listen(int backlog) noexcept
146 {
147 377x if (!is_open())
148 2x return make_error_code(std::errc::bad_file_descriptor);
149 #if BOOST_COROSIO_HAS_IOCP
150 auto& svc = static_cast<detail::win_tcp_acceptor_service&>(h_.service());
151 #else
152 375x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
153 #endif
154 375x return svc.listen_acceptor(
155 750x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
156 }
157
158 void
159 748x tcp_acceptor::close() noexcept
160 {
161 748x if (!is_open())
162 331x return;
163 417x h_.service().close(h_);
164 }
165
166 void
167 13x tcp_acceptor::cancel() noexcept
168 {
169 13x if (!is_open())
170 2x return;
171 11x get().cancel();
172 }
173
174 endpoint
175 365x tcp_acceptor::local_endpoint() const noexcept
176 {
177 365x if (!is_open())
178 2x return endpoint{};
179 363x return get().local_endpoint();
180 }
181
182 } // namespace boost::corosio
183