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

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