include/boost/corosio/connect.hpp

89.6% Lines (43/48) 100.0% List of functions (9/9) 44.3% Branches (131/296)
connect.hpp
f(x) Functions (9)
Function Calls Lines Branches Blocks
bool boost::corosio::detail::default_connect_condition::operator()<boost::corosio::endpoint>(std::__1::error_code const&, boost::corosio::endpoint const&) const :54 20x 100.0% 100.0% boost::capy::task<std::__1::tuple<std::__1::error_code, boost::corosio::tcp_socket::endpoint_type>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>>(boost::corosio::tcp_socket&, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>) :139 12x 66.7% 50.0% 50.0% boost::capy::task<std::__1::tuple<std::__1::error_code, boost::corosio::tcp_socket::endpoint_type>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::kqueue_t{}>::testCondSelectiveSkip()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)>(boost::corosio::tcp_socket&, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::kqueue_t{}>::testCondSelectiveSkip()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)) :178 1x 100.0% 44.0% boost::capy::task<std::__1::tuple<std::__1::error_code, boost::corosio::tcp_socket::endpoint_type>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::kqueue_t{}>::testCondSkipsAll()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)>(boost::corosio::tcp_socket&, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::kqueue_t{}>::testCondSkipsAll()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)) :178 1x 100.0% 55.0% boost::capy::task<std::__1::tuple<std::__1::error_code, boost::corosio::tcp_socket::endpoint_type>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::select_t{}>::testCondSelectiveSkip()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)>(boost::corosio::tcp_socket&, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::select_t{}>::testCondSelectiveSkip()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)) :178 1x 100.0% 42.8% 44.0% boost::capy::task<std::__1::tuple<std::__1::error_code, boost::corosio::tcp_socket::endpoint_type>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::select_t{}>::testCondSkipsAll()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)>(boost::corosio::tcp_socket&, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::connect_test<boost::corosio::select_t{}>::testCondSkipsAll()::'lambda'()::operator()() const::'lambda'(std::__1::error_code const&, boost::corosio::endpoint const&)) :178 1x 100.0% 55.0% boost::capy::task<std::__1::tuple<std::__1::error_code, boost::corosio::tcp_socket::endpoint_type>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::detail::default_connect_condition>(boost::corosio::tcp_socket&, std::__1::vector<boost::corosio::endpoint, std::__1::allocator<boost::corosio::endpoint>>, boost::corosio::detail::default_connect_condition) :178 12x 100.0% 60.0% boost::capy::task<std::__1::tuple<std::__1::error_code, std::__1::__wrap_iter<boost::corosio::endpoint*>>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::__wrap_iter<boost::corosio::endpoint*>>(boost::corosio::tcp_socket&, std::__1::__wrap_iter<boost::corosio::endpoint*>, std::__1::__wrap_iter<boost::corosio::endpoint*>) :241 4x 100.0% 100.0% boost::capy::task<std::__1::tuple<std::__1::error_code, std::__1::__wrap_iter<boost::corosio::endpoint*>>> boost::corosio::connect<boost::corosio::tcp_socket, std::__1::__wrap_iter<boost::corosio::endpoint*>, boost::corosio::detail::default_connect_condition>(boost::corosio::tcp_socket&, std::__1::__wrap_iter<boost::corosio::endpoint*>, std::__1::__wrap_iter<boost::corosio::endpoint*>, boost::corosio::detail::default_connect_condition) :272 4x 80.0% 50.0% 54.0%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Michael Vandeberg
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 #ifndef BOOST_COROSIO_CONNECT_HPP
11 #define BOOST_COROSIO_CONNECT_HPP
12
13 #include <boost/corosio/detail/config.hpp>
14
15 #include <boost/capy/cond.hpp>
16 #include <boost/capy/io_result.hpp>
17 #include <boost/capy/task.hpp>
18
19 #include <concepts>
20 #include <iterator>
21 #include <ranges>
22 #include <system_error>
23 #include <utility>
24
25 /*
26 Range-based composed connect operation.
27
28 These free functions try each endpoint in a range (or iterator pair)
29 in order, returning on the first successful connect. Between attempts
30 the socket is closed so that the next attempt can auto-open with the
31 correct address family (e.g. going from IPv4 to IPv6 candidates).
32
33 The iteration semantics follow Boost.Asio's range/iterator async_connect:
34 on success, the successful endpoint (or its iterator) is returned; on
35 all-fail, the last attempt's error code is returned; on an empty range
36 (or when a connect_condition rejects every candidate),
37 std::errc::no_such_device_or_address is returned, matching the error
38 the resolver uses for "no results" in posix_resolver_service.
39
40 The operation is a plain coroutine; cancellation is propagated to the
41 inner per-endpoint connect via the affine awaitable protocol on io_env.
42 */
43
44 namespace boost::corosio {
45
46 namespace detail {
47
48 /* Always-true connect condition used by the overloads that take no
49 user-supplied predicate. Kept at namespace-detail scope so it has a
50 stable linkage name across translation units. */
51 struct default_connect_condition
52 {
53 template<class Endpoint>
54 20x bool operator()(std::error_code const&, Endpoint const&) const noexcept
55 {
56 20x return true;
57 }
58 };
59
60 } // namespace detail
61
62 /* Forward declarations so the non-condition overloads can delegate
63 to the condition overloads via qualified lookup (qualified calls
64 bind to the overload set visible at definition, not instantiation). */
65
66 template<class Socket, std::ranges::input_range Range, class ConnectCondition>
67 requires std::convertible_to<
68 std::ranges::range_reference_t<Range>,
69 typename Socket::endpoint_type> &&
70 std::predicate<
71 ConnectCondition&,
72 std::error_code const&,
73 typename Socket::endpoint_type const&>
74 capy::task<capy::io_result<typename Socket::endpoint_type>>
75 connect(Socket& s, Range endpoints, ConnectCondition cond);
76
77 template<class Socket, std::input_iterator Iter, class ConnectCondition>
78 requires std::convertible_to<
79 std::iter_reference_t<Iter>,
80 typename Socket::endpoint_type> &&
81 std::predicate<
82 ConnectCondition&,
83 std::error_code const&,
84 typename Socket::endpoint_type const&>
85 capy::task<capy::io_result<Iter>>
86 connect(Socket& s, Iter begin, Iter end, ConnectCondition cond);
87
88 /** Asynchronously connect a socket by trying each endpoint in a range.
89
90 Each candidate is tried in order. Before each attempt the socket is
91 closed (so the next `connect` auto-opens with the candidate's
92 address family). On first successful connect, the operation
93 completes with the connected endpoint.
94
95 @par Cancellation
96 Supports cancellation via the affine awaitable protocol. If a
97 per-endpoint connect completes with `capy::cond::canceled` the
98 operation completes immediately with that error and does not try
99 further endpoints.
100
101 @param s The socket to connect. Must have a `connect(endpoint)`
102 member returning an awaitable, plus `close()` and `is_open()`.
103 If the socket is already open, it will be closed before the
104 first attempt.
105 @param endpoints A range of candidate endpoints. Taken by value
106 so temporaries (e.g. `resolver_results` returned from
107 `resolver::resolve`) remain alive for the coroutine's lifetime.
108 Because the range is owned by the coroutine, passing an lvalue
109 copies it; since `resolver_results` is a
110 `std::vector<resolver_entry>`, that is a deep copy of every entry.
111 Pass an rvalue (`std::move(results)`) or use the iterator overload
112 (`connect(s, results.begin(), results.end())`) to avoid the copy.
113
114 @return An awaitable completing with
115 `capy::io_result<typename Socket::endpoint_type>`:
116 - on success: default error_code and the connected endpoint;
117 - on failure of all attempts: the error from the last attempt
118 and a default-constructed endpoint;
119 - on empty range: `std::errc::no_such_device_or_address` and a
120 default-constructed endpoint.
121
122 @note The socket is closed and re-opened before each attempt, so
123 any socket options set by the caller (e.g. `no_delay`,
124 `reuse_address`) are lost. Apply options after this operation
125 completes.
126
127 If auto-opening the socket fails during an attempt, that attempt
128 completes with the open error (inherits the contract of
129 `Socket::connect`).
130
131 @par Example
132 @par !example connect
133 */
134 template<class Socket, std::ranges::input_range Range>
135 requires std::convertible_to<
136 std::ranges::range_reference_t<Range>,
137 typename Socket::endpoint_type>
138 capy::task<capy::io_result<typename Socket::endpoint_type>>
139 12x connect(Socket& s, Range endpoints)
140 {
141 detail::default_connect_condition cond;
142
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12x return corosio::connect(s, std::move(endpoints), cond);
143 }
144
145 /** Asynchronously connect a socket by trying each endpoint in a range,
146 filtered by a user-supplied condition.
147
148 For each candidate the condition is invoked as
149 `cond(last_ec, ep)` where `last_ec` is the error from the most
150 recent attempt (default-constructed before the first attempt). If
151 the condition returns `false` the candidate is skipped; otherwise a
152 connect is attempted.
153
154 @param s The socket to connect. See the non-condition overload for
155 requirements.
156 @param endpoints A range of candidate endpoints, taken by value. See
157 the non-condition overload for the deep-copy caveat when passing
158 an lvalue `resolver_results`.
159 @param cond A predicate invocable with
160 `(std::error_code const&, typename Socket::endpoint_type const&)`
161 returning a value contextually convertible to `bool`.
162
163 @return Same as the non-condition overload. If every candidate is
164 rejected, completes with `std::errc::no_such_device_or_address`.
165
166 If auto-opening the socket fails, the attempt completes with the
167 open error.
168 */
169 template<class Socket, std::ranges::input_range Range, class ConnectCondition>
170 requires std::convertible_to<
171 std::ranges::range_reference_t<Range>,
172 typename Socket::endpoint_type> &&
173 std::predicate<
174 ConnectCondition&,
175 std::error_code const&,
176 typename Socket::endpoint_type const&>
177 capy::task<capy::io_result<typename Socket::endpoint_type>>
178
46/120
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 12 times.
✓ Branch 15 taken 12 times.
✓ Branch 16 taken 12 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 16 times.
✓ Branch 19 taken 12 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 1 time.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 time.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 time.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 1 time.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 time.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✓ Branch 38 taken 1 time.
✓ Branch 39 taken 1 time.
✓ Branch 40 taken 1 time.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✓ Branch 43 taken 1 time.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✓ Branch 48 taken 1 time.
✗ Branch 49 not taken.
✓ Branch 50 taken 1 time.
✗ Branch 51 not taken.
✓ Branch 52 taken 1 time.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✓ Branch 55 taken 1 time.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✓ Branch 58 taken 1 time.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✓ Branch 62 taken 1 time.
✓ Branch 63 taken 1 time.
✓ Branch 64 taken 1 time.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✓ Branch 67 taken 1 time.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✓ Branch 72 taken 1 time.
✗ Branch 73 not taken.
✓ Branch 74 taken 1 time.
✗ Branch 75 not taken.
✓ Branch 76 taken 1 time.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✓ Branch 79 taken 1 time.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✓ Branch 82 taken 1 time.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✓ Branch 86 taken 1 time.
✓ Branch 87 taken 1 time.
✓ Branch 88 taken 1 time.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✓ Branch 91 taken 1 time.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✓ Branch 96 taken 1 time.
✗ Branch 97 not taken.
✓ Branch 98 taken 1 time.
✗ Branch 99 not taken.
✓ Branch 100 taken 1 time.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✓ Branch 103 taken 1 time.
✗ Branch 104 not taken.
✗ Branch 105 not taken.
✓ Branch 106 taken 1 time.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✓ Branch 110 taken 1 time.
✓ Branch 111 taken 1 time.
✓ Branch 112 taken 1 time.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✓ Branch 115 taken 1 time.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
80x connect(Socket& s, Range endpoints, ConnectCondition cond)
179 16x {
180 using endpoint_type = typename Socket::endpoint_type;
181
182 16x std::error_code last_ec;
183
184
12/16
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 1 time.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 time.
✓ Branch 11 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 1 time.
✗ Branch 15 not taken.
86x for (auto&& e : endpoints)
185 {
186 54x endpoint_type ep = e;
187
188
7/10
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 1 time.
52x if (!cond(
189 static_cast<std::error_code const&>(last_ec),
190 static_cast<endpoint_type const&>(ep)))
191 2x continue;
192
193
4/6
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
50x if (s.is_open())
194 6x s.close();
195
196
14/34
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 16 times.
✓ Branch 11 taken 16 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 16 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 time.
✓ Branch 16 taken 1 time.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 time.
✗ Branch 24 not taken.
✓ Branch 25 taken 1 time.
✓ Branch 26 taken 1 time.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✓ Branch 33 taken 1 time.
50x auto [ec] = co_await s.connect(ep);
197
198
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
18x if (!ec)
199
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
8x co_return {std::error_code{}, std::move(ep)};
200
201
2/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10x if (ec == capy::cond::canceled)
202
2/12
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4x co_return {ec, endpoint_type{}};
203
204 8x last_ec = ec;
205 22x }
206
207
4/10
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
6x if (!last_ec)
208 4x last_ec = std::make_error_code(std::errc::no_such_device_or_address);
209
210
3/10
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
6x co_return {last_ec, endpoint_type{}};
211 64x }
212
213 /** Asynchronously connect a socket by trying each endpoint in an
214 iterator range.
215
216 Behaves like the range overload, except the return value carries
217 the iterator to the successfully connected endpoint on success, or
218 `end` on failure. This mirrors Boost.Asio's iterator-based
219 `async_connect`.
220
221 @param s The socket to connect.
222 @param begin The first candidate.
223 @param end One past the last candidate.
224
225 @return An awaitable completing with `capy::io_result<Iter>`:
226 - on success: default error_code and the iterator of the
227 successful endpoint;
228 - on failure of all attempts: the error from the last attempt
229 and `end`;
230 - on empty range: `std::errc::no_such_device_or_address` and
231 `end`.
232
233 If auto-opening the socket fails, the attempt completes with the
234 open error.
235 */
236 template<class Socket, std::input_iterator Iter>
237 requires std::convertible_to<
238 std::iter_reference_t<Iter>,
239 typename Socket::endpoint_type>
240 capy::task<capy::io_result<Iter>>
241 4x connect(Socket& s, Iter begin, Iter end)
242 {
243 4x return corosio::connect(
244 4x s, std::move(begin), std::move(end),
245 detail::default_connect_condition{});
246 }
247
248 /** Asynchronously connect a socket by trying each endpoint in an
249 iterator range, filtered by a user-supplied condition.
250
251 @param s The socket to connect.
252 @param begin The first candidate.
253 @param end One past the last candidate.
254 @param cond A predicate invocable with
255 `(std::error_code const&, typename Socket::endpoint_type const&)`.
256
257 @return Same as the plain iterator overload. If every candidate is
258 rejected, completes with `std::errc::no_such_device_or_address`.
259
260 If auto-opening the socket fails, the attempt completes with the
261 open error.
262 */
263 template<class Socket, std::input_iterator Iter, class ConnectCondition>
264 requires std::convertible_to<
265 std::iter_reference_t<Iter>,
266 typename Socket::endpoint_type> &&
267 std::predicate<
268 ConnectCondition&,
269 std::error_code const&,
270 typename Socket::endpoint_type const&>
271 capy::task<capy::io_result<Iter>>
272
10/24
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 4 times.
✓ Branch 15 taken 4 times.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
20x connect(Socket& s, Iter begin, Iter end, ConnectCondition cond)
273 4x {
274 using endpoint_type = typename Socket::endpoint_type;
275
276 4x std::error_code last_ec;
277
278
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2 times.
20x for (Iter it = begin; it != end; ++it)
279 {
280 12x endpoint_type ep = *it;
281
282
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12x if (!cond(
283 static_cast<std::error_code const&>(last_ec),
284 static_cast<endpoint_type const&>(ep)))
285 continue;
286
287
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12x if (s.is_open())
288 s.close();
289
290
7/12
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
12x auto [ec] = co_await s.connect(ep);
291
292
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4x if (!ec)
293
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2x co_return {std::error_code{}, std::move(it)};
294
295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2x if (ec == capy::cond::canceled)
296 co_return {ec, std::move(end)};
297
298 2x last_ec = ec;
299 4x }
300
301
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2x if (!last_ec)
302 last_ec = std::make_error_code(std::errc::no_such_device_or_address);
303
304
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2x co_return {last_ec, std::move(end)};
305 16x }
306
307 } // namespace boost::corosio
308
309 #endif
310