include/boost/corosio/native/detail/posix/posix_resolver_service.hpp

85.0% Lines (244/287) 93.3% List of functions (28/30) 58.7% Branches (74/126)
f(x) Functions (30)
Function Calls Lines Branches Blocks
boost::corosio::detail::posix_resolver_service::posix_resolver_service(boost::capy::execution_context&, boost::corosio::detail::scheduler&) :36 1212x 100.0% 50.0% 100.0% boost::corosio::detail::posix_resolver_service::~posix_resolver_service() :42 1818x 100.0% 100.0% boost::corosio::detail::posix_resolver_service::destroy(boost::corosio::io_object::implementation*) :49 35x 100.0% 100.0% boost::corosio::detail::posix_resolver_service::pool() :64 28x 100.0% 100.0% boost::corosio::detail::posix_resolver_detail::flags_to_hints(boost::corosio::resolve_flags) :97 18x 73.3% 66.7% 69.0% boost::corosio::detail::posix_resolver_detail::flags_to_ni_flags(boost::corosio::reverse_flags) :118 10x 90.9% 87.5% 88.0% boost::corosio::detail::posix_resolver_detail::convert_results(addrinfo*, std::__1::basic_string_view<char, std::__1::char_traits<char>>, std::__1::basic_string_view<char, std::__1::char_traits<char>>) :135 15x 100.0% 64.3% 77.0% boost::corosio::detail::posix_resolver_detail::make_gai_error(int) :161 4x 22.7% 10.0% 25.0% boost::corosio::detail::posix_resolver::posix_resolver(boost::corosio::detail::posix_resolver_service&) :226 70x 100.0% 100.0% boost::corosio::detail::posix_resolver::resolve_op::reset() :234 18x 100.0% 100.0% boost::corosio::detail::posix_resolver::resolve_op::operator()() :248 18x 93.3% 66.7% 92.0% boost::corosio::detail::posix_resolver::resolve_op::destroy() :272 0 0.0% 0.0% boost::corosio::detail::posix_resolver::resolve_op::request_cancel() :278 39x 100.0% 100.0% boost::corosio::detail::posix_resolver::resolve_op::start(std::__1::stop_token const&) :284 18x 83.3% 50.0% 66.0% boost::corosio::detail::posix_resolver::reverse_resolve_op::reset() :296 10x 100.0% 100.0% boost::corosio::detail::posix_resolver::reverse_resolve_op::operator()() :310 10x 94.1% 64.3% 81.0% boost::corosio::detail::posix_resolver::reverse_resolve_op::destroy() :337 0 0.0% 0.0% boost::corosio::detail::posix_resolver::reverse_resolve_op::request_cancel() :343 39x 100.0% 100.0% boost::corosio::detail::posix_resolver::reverse_resolve_op::start(std::__1::stop_token const&) :349 10x 83.3% 50.0% 66.0% boost::corosio::detail::posix_resolver::resolve(std::__1::coroutine_handle<void>, boost::capy::executor_ref, std::__1::basic_string_view<char, std::__1::char_traits<char>>, std::__1::basic_string_view<char, std::__1::char_traits<char>>, boost::corosio::resolve_flags, std::__1::stop_token, std::__1::error_code*, boost::corosio::resolver_results*) :361 18x 81.8% 50.0% 66.0% boost::corosio::detail::posix_resolver::reverse_resolve(std::__1::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::endpoint const&, boost::corosio::reverse_flags, std::__1::stop_token, std::__1::error_code*, boost::corosio::reverse_resolver_result*) :401 10x 81.0% 50.0% 66.0% boost::corosio::detail::posix_resolver::cancel() :439 39x 100.0% 100.0% boost::corosio::detail::posix_resolver::do_resolve_work(boost::corosio::detail::pool_work_item*) :446 18x 100.0% 59.1% 85.0% boost::corosio::detail::posix_resolver::do_reverse_resolve_work(boost::corosio::detail::pool_work_item*) :486 10x 100.0% 62.5% 93.0% boost::corosio::detail::posix_resolver_service::shutdown() :538 606x 62.5% 50.0% 60.0% boost::corosio::detail::posix_resolver_service::construct() :556 35x 100.0% 50.0% 42.0% boost::corosio::detail::posix_resolver_service::destroy_impl(boost::corosio::detail::posix_resolver&) :571 35x 100.0% 50.0% 50.0% boost::corosio::detail::posix_resolver_service::post(boost::corosio::detail::scheduler_op*) :579 28x 100.0% 100.0% boost::corosio::detail::posix_resolver_service::work_finished() :591 28x 100.0% 100.0% boost::corosio::detail::get_resolver_service(boost::capy::execution_context&, boost::corosio::detail::scheduler&) :599 606x 100.0% 100.0%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
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_NATIVE_DETAIL_POSIX_POSIX_RESOLVER_SERVICE_HPP
11 #define BOOST_COROSIO_NATIVE_DETAIL_POSIX_POSIX_RESOLVER_SERVICE_HPP
12
13 #include <boost/corosio/detail/platform.hpp>
14
15 #if BOOST_COROSIO_POSIX
16
17 #include <boost/corosio/native/detail/posix/posix_resolver.hpp>
18 #include <boost/corosio/detail/thread_pool.hpp>
19
20 #include <unordered_map>
21
22 namespace boost::corosio::detail {
23
24 /** Resolver service for POSIX backends.
25
26 Owns all posix_resolver instances. Thread lifecycle is managed
27 by the thread_pool service.
28 */
29 class BOOST_COROSIO_DECL posix_resolver_service final
30 : public capy::execution_context::service
31 , public io_object::io_service
32 {
33 public:
34 using key_type = posix_resolver_service;
35
36 1818x posix_resolver_service(capy::execution_context& ctx, scheduler& sched)
37 606x : sched_(&sched)
38
1/2
✓ Branch 0 taken 606 times.
✗ Branch 1 not taken.
606x , pool_(ctx.make_service<thread_pool>())
39 1818x {
40 1212x }
41
42 1818x ~posix_resolver_service() override = default;
43
44 posix_resolver_service(posix_resolver_service const&) = delete;
45 posix_resolver_service& operator=(posix_resolver_service const&) = delete;
46
47 io_object::implementation* construct() override;
48
49 35x void destroy(io_object::implementation* p) override
50 {
51 35x auto& impl = static_cast<posix_resolver&>(*p);
52 35x impl.cancel();
53 35x destroy_impl(impl);
54 35x }
55
56 void shutdown() override;
57 void destroy_impl(posix_resolver& impl);
58
59 void post(scheduler_op* op);
60 void work_started() noexcept;
61 void work_finished() noexcept;
62
63 /** Return the resolver thread pool. */
64 28x thread_pool& pool() noexcept
65 {
66 28x return pool_;
67 }
68
69 private:
70 scheduler* sched_;
71 thread_pool& pool_;
72 std::mutex mutex_;
73 intrusive_list<posix_resolver> resolver_list_;
74 std::unordered_map<posix_resolver*, std::shared_ptr<posix_resolver>>
75 resolver_ptrs_;
76 };
77
78 /** Get or create the resolver service for the given context.
79
80 This function is called by the concrete scheduler during initialization
81 to create the resolver service with a reference to itself.
82
83 @param ctx Reference to the owning execution_context.
84 @param sched Reference to the scheduler for posting completions.
85 @return Reference to the resolver service.
86 */
87 posix_resolver_service&
88 get_resolver_service(capy::execution_context& ctx, scheduler& sched);
89
90 // ---------------------------------------------------------------------------
91 // Inline implementation
92 // ---------------------------------------------------------------------------
93
94 // posix_resolver_detail helpers
95
96 inline int
97 18x posix_resolver_detail::flags_to_hints(resolve_flags flags)
98 {
99 18x int hints = 0;
100
101
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x if ((flags & resolve_flags::passive) != resolve_flags::none)
102 hints |= AI_PASSIVE;
103
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 11 times.
18x if ((flags & resolve_flags::numeric_host) != resolve_flags::none)
104 11x hints |= AI_NUMERICHOST;
105
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
18x if ((flags & resolve_flags::numeric_service) != resolve_flags::none)
106 8x hints |= AI_NUMERICSERV;
107
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x if ((flags & resolve_flags::address_configured) != resolve_flags::none)
108 hints |= AI_ADDRCONFIG;
109
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x if ((flags & resolve_flags::v4_mapped) != resolve_flags::none)
110 hints |= AI_V4MAPPED;
111
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x if ((flags & resolve_flags::all_matching) != resolve_flags::none)
112 hints |= AI_ALL;
113
114 18x return hints;
115 }
116
117 inline int
118 10x posix_resolver_detail::flags_to_ni_flags(reverse_flags flags)
119 {
120 10x int ni_flags = 0;
121
122
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10x if ((flags & reverse_flags::numeric_host) != reverse_flags::none)
123 5x ni_flags |= NI_NUMERICHOST;
124
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10x if ((flags & reverse_flags::numeric_service) != reverse_flags::none)
125 5x ni_flags |= NI_NUMERICSERV;
126
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
10x if ((flags & reverse_flags::name_required) != reverse_flags::none)
127 1x ni_flags |= NI_NAMEREQD;
128
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x if ((flags & reverse_flags::datagram_service) != reverse_flags::none)
129 ni_flags |= NI_DGRAM;
130
131 10x return ni_flags;
132 }
133
134 inline resolver_results
135 15x posix_resolver_detail::convert_results(
136 struct addrinfo* ai, std::string_view host, std::string_view service)
137 {
138 15x std::vector<resolver_entry> entries;
139
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15x entries.reserve(4); // Most lookups return 1-4 addresses
140
141
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 15 times.
36x for (auto* p = ai; p != nullptr; p = p->ai_next)
142 {
143
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
21x if (p->ai_family == AF_INET)
144 {
145 13x auto* addr = reinterpret_cast<sockaddr_in*>(p->ai_addr);
146 13x auto ep = from_sockaddr_in(*addr);
147
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13x entries.emplace_back(ep, host, service);
148 13x }
149
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8x else if (p->ai_family == AF_INET6)
150 {
151 8x auto* addr = reinterpret_cast<sockaddr_in6*>(p->ai_addr);
152 8x auto ep = from_sockaddr_in6(*addr);
153
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8x entries.emplace_back(ep, host, service);
154 8x }
155 21x }
156
157
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15x return resolver_results(std::move(entries));
158 15x }
159
160 inline std::error_code
161 4x posix_resolver_detail::make_gai_error(int gai_err)
162 {
163 // Map GAI errors to appropriate generic error codes
164
1/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
4x switch (gai_err)
165 {
166 case EAI_AGAIN:
167 // Temporary failure - try again later
168 return std::error_code(
169 static_cast<int>(std::errc::resource_unavailable_try_again),
170 std::generic_category());
171
172 case EAI_BADFLAGS:
173 // Invalid flags
174 return std::error_code(
175 static_cast<int>(std::errc::invalid_argument),
176 std::generic_category());
177
178 case EAI_FAIL:
179 // Non-recoverable failure
180 return std::error_code(
181 static_cast<int>(std::errc::io_error), std::generic_category());
182
183 case EAI_FAMILY:
184 // Address family not supported
185 return std::error_code(
186 static_cast<int>(std::errc::address_family_not_supported),
187 std::generic_category());
188
189 case EAI_MEMORY:
190 // Memory allocation failure
191 return std::error_code(
192 static_cast<int>(std::errc::not_enough_memory),
193 std::generic_category());
194
195 case EAI_NONAME:
196 // Host or service not found
197 4x return std::error_code(
198 static_cast<int>(std::errc::no_such_device_or_address),
199 4x std::generic_category());
200
201 case EAI_SERVICE:
202 // Service not supported for socket type
203 return std::error_code(
204 static_cast<int>(std::errc::invalid_argument),
205 std::generic_category());
206
207 case EAI_SOCKTYPE:
208 // Socket type not supported
209 return std::error_code(
210 static_cast<int>(std::errc::not_supported),
211 std::generic_category());
212
213 case EAI_SYSTEM:
214 // System error - use errno
215 return std::error_code(errno, std::generic_category());
216
217 default:
218 // Unknown error
219 return std::error_code(
220 static_cast<int>(std::errc::io_error), std::generic_category());
221 }
222 4x }
223
224 // posix_resolver
225
226 140x inline posix_resolver::posix_resolver(posix_resolver_service& svc) noexcept
227 35x : svc_(svc)
228 105x {
229 70x }
230
231 // posix_resolver::resolve_op implementation
232
233 inline void
234 18x posix_resolver::resolve_op::reset() noexcept
235 {
236 18x host.clear();
237 18x service.clear();
238 18x flags = resolve_flags::none;
239 18x stored_results = resolver_results{};
240 18x gai_error = 0;
241 18x cancelled.store(false, std::memory_order_relaxed);
242 18x stop_cb.reset();
243 18x ec_out = nullptr;
244 18x out = nullptr;
245 18x }
246
247 inline void
248 18x posix_resolver::resolve_op::operator()()
249 {
250 18x stop_cb.reset(); // Disconnect stop callback
251
252 18x bool const was_cancelled = cancelled.load(std::memory_order_acquire);
253
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18x if (ec_out)
255 {
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18x if (was_cancelled)
257 *ec_out = capy::error::canceled;
258
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
18x else if (gai_error != 0)
259 3x *ec_out = posix_resolver_detail::make_gai_error(gai_error);
260 else
261 15x *ec_out = {}; // Clear on success
262 18x }
263
264
4/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 15 times.
18x if (out && !was_cancelled && gai_error == 0)
265 15x *out = std::move(stored_results);
266
267 18x impl->svc_.work_finished();
268 18x dispatch_coro(ex, h).resume();
269 18x }
270
271 inline void
272 posix_resolver::resolve_op::destroy()
273 {
274 stop_cb.reset();
275 }
276
277 inline void
278 39x posix_resolver::resolve_op::request_cancel() noexcept
279 {
280 39x cancelled.store(true, std::memory_order_release);
281 39x }
282
283 inline void
284 18x posix_resolver::resolve_op::start(std::stop_token const& token)
285 {
286 18x cancelled.store(false, std::memory_order_release);
287 18x stop_cb.reset();
288
289
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x if (token.stop_possible())
290 stop_cb.emplace(token, canceller{this});
291 18x }
292
293 // posix_resolver::reverse_resolve_op implementation
294
295 inline void
296 10x posix_resolver::reverse_resolve_op::reset() noexcept
297 {
298 10x ep = endpoint{};
299 10x flags = reverse_flags::none;
300 10x stored_host.clear();
301 10x stored_service.clear();
302 10x gai_error = 0;
303 10x cancelled.store(false, std::memory_order_relaxed);
304 10x stop_cb.reset();
305 10x ec_out = nullptr;
306 10x result_out = nullptr;
307 10x }
308
309 inline void
310 10x posix_resolver::reverse_resolve_op::operator()()
311 {
312 10x stop_cb.reset(); // Disconnect stop callback
313
314 10x bool const was_cancelled = cancelled.load(std::memory_order_acquire);
315
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10x if (ec_out)
317 {
318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10x if (was_cancelled)
319 *ec_out = capy::error::canceled;
320
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 9 times.
10x else if (gai_error != 0)
321 1x *ec_out = posix_resolver_detail::make_gai_error(gai_error);
322 else
323 9x *ec_out = {}; // Clear on success
324 10x }
325
326
4/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 9 times.
10x if (result_out && !was_cancelled && gai_error == 0)
327 {
328
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9x *result_out = reverse_resolver_result(
329 9x ep, std::move(stored_host), std::move(stored_service));
330 9x }
331
332 10x impl->svc_.work_finished();
333 10x dispatch_coro(ex, h).resume();
334 10x }
335
336 inline void
337 posix_resolver::reverse_resolve_op::destroy()
338 {
339 stop_cb.reset();
340 }
341
342 inline void
343 39x posix_resolver::reverse_resolve_op::request_cancel() noexcept
344 {
345 39x cancelled.store(true, std::memory_order_release);
346 39x }
347
348 inline void
349 10x posix_resolver::reverse_resolve_op::start(std::stop_token const& token)
350 {
351 10x cancelled.store(false, std::memory_order_release);
352 10x stop_cb.reset();
353
354
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x if (token.stop_possible())
355 stop_cb.emplace(token, canceller{this});
356 10x }
357
358 // posix_resolver implementation
359
360 inline std::coroutine_handle<>
361 18x posix_resolver::resolve(
362 std::coroutine_handle<> h,
363 capy::executor_ref ex,
364 std::string_view host,
365 std::string_view service,
366 resolve_flags flags,
367 std::stop_token token,
368 std::error_code* ec,
369 resolver_results* out)
370 {
371 18x auto& op = op_;
372 18x op.reset();
373 18x op.h = h;
374 18x op.ex = ex;
375 18x op.impl = this;
376 18x op.ec_out = ec;
377 18x op.out = out;
378 18x op.host = host;
379 18x op.service = service;
380 18x op.flags = flags;
381 18x op.start(token);
382
383 // Keep io_context alive while resolution is pending
384 18x op.ex.on_work_started();
385
386 // Prevent impl destruction while work is in flight
387 18x resolve_pool_op_.resolver_ = this;
388 18x resolve_pool_op_.ref_ = this->shared_from_this();
389 18x resolve_pool_op_.func_ = &posix_resolver::do_resolve_work;
390
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x if (!svc_.pool().post(&resolve_pool_op_))
391 {
392 // Pool shut down — complete with cancellation
393 resolve_pool_op_.ref_.reset();
394 op.cancelled.store(true, std::memory_order_release);
395 svc_.post(&op_);
396 }
397 18x return std::noop_coroutine();
398 }
399
400 inline std::coroutine_handle<>
401 10x posix_resolver::reverse_resolve(
402 std::coroutine_handle<> h,
403 capy::executor_ref ex,
404 endpoint const& ep,
405 reverse_flags flags,
406 std::stop_token token,
407 std::error_code* ec,
408 reverse_resolver_result* result_out)
409 {
410 10x auto& op = reverse_op_;
411 10x op.reset();
412 10x op.h = h;
413 10x op.ex = ex;
414 10x op.impl = this;
415 10x op.ec_out = ec;
416 10x op.result_out = result_out;
417 10x op.ep = ep;
418 10x op.flags = flags;
419 10x op.start(token);
420
421 // Keep io_context alive while resolution is pending
422 10x op.ex.on_work_started();
423
424 // Prevent impl destruction while work is in flight
425 10x reverse_pool_op_.resolver_ = this;
426 10x reverse_pool_op_.ref_ = this->shared_from_this();
427 10x reverse_pool_op_.func_ = &posix_resolver::do_reverse_resolve_work;
428
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x if (!svc_.pool().post(&reverse_pool_op_))
429 {
430 // Pool shut down — complete with cancellation
431 reverse_pool_op_.ref_.reset();
432 op.cancelled.store(true, std::memory_order_release);
433 svc_.post(&reverse_op_);
434 }
435 10x return std::noop_coroutine();
436 }
437
438 inline void
439 39x posix_resolver::cancel() noexcept
440 {
441 39x op_.request_cancel();
442 39x reverse_op_.request_cancel();
443 39x }
444
445 inline void
446 18x posix_resolver::do_resolve_work(pool_work_item* w) noexcept
447 {
448 18x auto* pw = static_cast<pool_op*>(w);
449 18x auto* self = pw->resolver_;
450
451 18x struct addrinfo hints{};
452 18x hints.ai_family = AF_UNSPEC;
453 18x hints.ai_socktype = SOCK_STREAM;
454
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x hints.ai_flags = posix_resolver_detail::flags_to_hints(self->op_.flags);
455
456 18x struct addrinfo* ai = nullptr;
457
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x int result = ::getaddrinfo(
458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18x self->op_.host.empty() ? nullptr : self->op_.host.c_str(),
459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18x self->op_.service.empty() ? nullptr : self->op_.service.c_str(), &hints,
460 &ai);
461
462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18x if (!self->op_.cancelled.load(std::memory_order_acquire))
463 {
464
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
18x if (result == 0 && ai)
465 {
466
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15x self->op_.stored_results = posix_resolver_detail::convert_results(
467 15x ai, self->op_.host, self->op_.service);
468 15x self->op_.gai_error = 0;
469 15x }
470 else
471 {
472 3x self->op_.gai_error = result;
473 }
474 18x }
475
476
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18x if (ai)
477
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15x ::freeaddrinfo(ai);
478
479 // Move ref to stack before post — post may trigger destroy_impl
480 // which erases the last shared_ptr, destroying *self (and *pw)
481 18x auto ref = std::move(pw->ref_);
482
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18x self->svc_.post(&self->op_);
483 18x }
484
485 inline void
486 10x posix_resolver::do_reverse_resolve_work(pool_work_item* w) noexcept
487 {
488 10x auto* pw = static_cast<pool_op*>(w);
489 10x auto* self = pw->resolver_;
490
491 10x sockaddr_storage ss{};
492 socklen_t ss_len;
493
494
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10x if (self->reverse_op_.ep.is_v4())
495 {
496 8x auto sa = to_sockaddr_in(self->reverse_op_.ep);
497 8x std::memcpy(&ss, &sa, sizeof(sa));
498 8x ss_len = sizeof(sockaddr_in);
499 8x }
500 else
501 {
502 2x auto sa = to_sockaddr_in6(self->reverse_op_.ep);
503 2x std::memcpy(&ss, &sa, sizeof(sa));
504 2x ss_len = sizeof(sockaddr_in6);
505 }
506
507 char host[NI_MAXHOST];
508 char service[NI_MAXSERV];
509
510
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x int result = ::getnameinfo(
511 10x reinterpret_cast<sockaddr*>(&ss), ss_len, host, sizeof(host), service,
512 sizeof(service),
513
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x posix_resolver_detail::flags_to_ni_flags(self->reverse_op_.flags));
514
515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10x if (!self->reverse_op_.cancelled.load(std::memory_order_acquire))
516 {
517
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
10x if (result == 0)
518 {
519
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9x self->reverse_op_.stored_host = host;
520
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9x self->reverse_op_.stored_service = service;
521 9x self->reverse_op_.gai_error = 0;
522 9x }
523 else
524 {
525 1x self->reverse_op_.gai_error = result;
526 }
527 10x }
528
529 // Move ref to stack before post — post may trigger destroy_impl
530 // which erases the last shared_ptr, destroying *self (and *pw)
531 10x auto ref = std::move(pw->ref_);
532
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10x self->svc_.post(&self->reverse_op_);
533 10x }
534
535 // posix_resolver_service implementation
536
537 inline void
538 606x posix_resolver_service::shutdown()
539 {
540 606x std::lock_guard<std::mutex> lock(mutex_);
541
542 // Cancel all resolvers (sets cancelled flag checked by pool threads)
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 606 times.
606x for (auto* impl = resolver_list_.pop_front(); impl != nullptr;
544 impl = resolver_list_.pop_front())
545 {
546 impl->cancel();
547 }
548
549 // Clear the map which releases shared_ptrs.
550 // The thread pool service shuts down separately via
551 // execution_context service ordering.
552 606x resolver_ptrs_.clear();
553 606x }
554
555 inline io_object::implementation*
556 35x posix_resolver_service::construct()
557 {
558 35x auto ptr = std::make_shared<posix_resolver>(*this);
559 35x auto* impl = ptr.get();
560
561 {
562
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35x std::lock_guard<std::mutex> lock(mutex_);
563 35x resolver_list_.push_back(impl);
564
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35x resolver_ptrs_[impl] = std::move(ptr);
565 35x }
566
567 35x return impl;
568 35x }
569
570 inline void
571 35x posix_resolver_service::destroy_impl(posix_resolver& impl)
572 {
573 35x std::lock_guard<std::mutex> lock(mutex_);
574 35x resolver_list_.remove(&impl);
575
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35x resolver_ptrs_.erase(&impl);
576 35x }
577
578 inline void
579 28x posix_resolver_service::post(scheduler_op* op)
580 {
581 28x sched_->post(op);
582 28x }
583
584 inline void
585 posix_resolver_service::work_started() noexcept
586 {
587 sched_->work_started();
588 }
589
590 inline void
591 28x posix_resolver_service::work_finished() noexcept
592 {
593 28x sched_->work_finished();
594 28x }
595
596 // Free function to get/create the resolver service
597
598 inline posix_resolver_service&
599 606x get_resolver_service(capy::execution_context& ctx, scheduler& sched)
600 {
601 606x return ctx.make_service<posix_resolver_service>(sched);
602 }
603
604 } // namespace boost::corosio::detail
605
606 #endif // BOOST_COROSIO_POSIX
607
608 #endif // BOOST_COROSIO_NATIVE_DETAIL_POSIX_POSIX_RESOLVER_SERVICE_HPP
609