src/corosio/src/tcp_acceptor.cpp

97.2% Lines (69/71) 100.0% List of functions (12/12) 50.0% Branches (33/66)
tcp_acceptor.cpp
f(x) Functions (12)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
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 3953x tcp_acceptor::~tcp_acceptor()
46 3953x {
47 1994x close();
48 3953x }
49
50 3908x 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 1954x : io_object(create_handle<detail::tcp_acceptor_service>(ctx))
55 #endif
56 3908x {
57 3908x }
58
59 40x tcp_acceptor::tcp_acceptor(
60 capy::execution_context& ctx, endpoint ep, int backlog)
61 40x : tcp_acceptor(ctx)
62 {
63
3/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 38 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 40 times.
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
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
40x set_option(socket_option::reuse_address(true));
69 #endif
70
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 36 times.
40x if (auto ec = bind(ep))
71
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4x detail::throw_system_error(ec, "tcp_acceptor");
72
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
36x if (auto ec = listen(backlog))
73 detail::throw_system_error(ec, "tcp_acceptor");
74 40x }
75
76 std::error_code
77 1958x tcp_acceptor::open(tcp proto) noexcept
78 {
79
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1956 times.
1958x 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 1956x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
86 #endif
87
2/4
✓ Branch 0 taken 1956 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
✗ Branch 3 not taken.
3912x std::error_code ec = svc.open_acceptor_socket(
88 1956x *static_cast<tcp_acceptor::implementation*>(h_.get()), proto.family(),
89 1956x proto.type(), proto.protocol());
90 1956x return ec;
91 1958x }
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
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
36x 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
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
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
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 22 times.
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 26x }
129
130 std::error_code
131 1946x tcp_acceptor::bind(endpoint ep) noexcept
132 {
133
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1944 times.
1946x 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 1944x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
139 #endif
140
2/4
✓ Branch 0 taken 1944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1944 times.
✗ Branch 3 not taken.
3888x return svc.bind_acceptor(
141 1944x *static_cast<tcp_acceptor::implementation*>(h_.get()), ep);
142 1946x }
143
144 std::error_code
145 1916x tcp_acceptor::listen(int backlog) noexcept
146 {
147
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1914 times.
1916x 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 1914x auto& svc = static_cast<detail::tcp_acceptor_service&>(h_.service());
153 #endif
154
2/4
✓ Branch 0 taken 1914 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1914 times.
✗ Branch 3 not taken.
3828x return svc.listen_acceptor(
155 1914x *static_cast<tcp_acceptor::implementation*>(h_.get()), backlog);
156 1916x }
157
158 void
159 3826x tcp_acceptor::close() noexcept
160 {
161
2/2
✓ Branch 0 taken 1956 times.
✓ Branch 1 taken 1870 times.
3826x if (!is_open())
162 1870x return;
163
1/2
✓ Branch 0 taken 1956 times.
✗ Branch 1 not taken.
1956x h_.service().close(h_);
164 3826x }
165
166 void
167 13x tcp_acceptor::cancel() noexcept
168 {
169
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
13x if (!is_open())
170 2x return;
171 11x get().cancel();
172 13x }
173
174 endpoint
175 1904x tcp_acceptor::local_endpoint() const noexcept
176 {
177
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1902 times.
1904x if (!is_open())
178 2x return endpoint{};
179 1902x return get().local_endpoint();
180 1904x }
181
182 } // namespace boost::corosio
183