include/boost/corosio/local_stream_acceptor.hpp

100.0% Lines (93 / 93) 100.0% Functions (23 / 23)
local_stream_acceptor.hpp
f(x) Functions (23)
Function Calls Lines Blocks
boost::corosio::local_stream_acceptor::wait_awaitable::wait_awaitable(boost::corosio::local_stream_acceptor&, boost::corosio::wait_type) :80 8x 100.0% 100.0% boost::corosio::local_stream_acceptor::wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :92 6x 100.0% 80.0% boost::corosio::local_stream_acceptor::move_accept_awaitable::move_accept_awaitable(boost::corosio::local_stream_acceptor&) :108 8x 100.0% 100.0% boost::corosio::local_stream_acceptor::move_accept_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :114 6x 100.0% 80.0% boost::corosio::local_stream_acceptor::move_accept_awaitable::~move_accept_awaitable() :123 16x 100.0% 100.0% boost::corosio::local_stream_acceptor::move_accept_awaitable::await_resume() const :130 6x 100.0% 100.0% boost::corosio::local_stream_acceptor::accept_awaitable::accept_awaitable(boost::corosio::local_stream_acceptor&, boost::corosio::local_stream_socket&) :152 33x 100.0% 100.0% boost::corosio::local_stream_acceptor::accept_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :160 29x 100.0% 80.0% boost::corosio::local_stream_acceptor::accept_awaitable::~accept_awaitable() :169 66x 100.0% 100.0% boost::corosio::local_stream_acceptor::accept_awaitable::await_resume() const :175 29x 100.0% 100.0% boost::corosio::local_stream_acceptor::local_stream_acceptor(boost::corosio::local_stream_acceptor&&) :257 2x 100.0% 100.0% boost::corosio::local_stream_acceptor::is_open() const :341 613x 100.0% 100.0% boost::corosio::local_stream_acceptor::accept(boost::corosio::local_stream_socket&) :363 33x 100.0% 100.0% boost::corosio::local_stream_acceptor::wait(boost::corosio::wait_type) :393 8x 100.0% 100.0% boost::corosio::local_stream_acceptor::accept() :418 8x 100.0% 100.0% void boost::corosio::local_stream_acceptor::set_option<boost::corosio::socket_option::no_delay>(boost::corosio::socket_option::no_delay const&) :518 2x 66.7% 78.0% void boost::corosio::local_stream_acceptor::set_option<boost::corosio::socket_option::reuse_address>(boost::corosio::socket_option::reuse_address const&) :518 4x 88.9% 94.0% boost::corosio::socket_option::no_delay boost::corosio::local_stream_acceptor::get_option<boost::corosio::socket_option::no_delay>() const :545 2x 66.7% 70.0% boost::corosio::socket_option::reuse_address boost::corosio::local_stream_acceptor::get_option<boost::corosio::socket_option::reuse_address>() const :545 4x 91.7% 95.0% boost::corosio::local_stream_acceptor::local_stream_acceptor(boost::corosio::io_object::handle, boost::capy::execution_context&) :670 18x 100.0% 100.0% boost::corosio::local_stream_acceptor::local_stream_acceptor(boost::capy::execution_context&, boost::corosio::local_stream_acceptor&&) :682 2x 100.0% 100.0% boost::corosio::local_stream_acceptor::reset_peer_impl(boost::corosio::local_stream_socket&, boost::corosio::io_object::implementation*) :699 8x 100.0% 100.0% boost::corosio::local_stream_acceptor::get() const :709 708x 100.0% 100.0%
Line 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_LOCAL_STREAM_ACCEPTOR_HPP
11 #define BOOST_COROSIO_LOCAL_STREAM_ACCEPTOR_HPP
12
13 #include <boost/corosio/family.hpp>
14 #include <boost/corosio/detail/config.hpp>
15 #include <boost/corosio/detail/except.hpp>
16 #include <boost/corosio/detail/op_base.hpp>
17 #include <boost/corosio/error.hpp>
18 #include <boost/corosio/wait_type.hpp>
19 #include <boost/corosio/io/io_object.hpp>
20 #include <boost/capy/results.hpp>
21 #include <boost/corosio/local_endpoint.hpp>
22 #include <boost/corosio/local_stream_socket.hpp>
23 #include <boost/capy/ex/executor_ref.hpp>
24 #include <boost/capy/ex/execution_context.hpp>
25 #include <boost/capy/ex/await_context.hpp>
26 #include <boost/capy/concept/executor.hpp>
27
28 #include <system_error>
29 #include <utility>
30
31 #include <cassert>
32 #include <concepts>
33 #include <boost/capy/continuation.hpp>
34
35 #include <coroutine>
36 #include <cstddef>
37 #include <stop_token>
38 #include <type_traits>
39
40 namespace boost::corosio {
41
42 /** Controls whether @ref local_stream_acceptor::bind() unlinks
43 an existing socket path before binding.
44 */
45 enum class bind_option
46 {
47 /// Bind without touching the socket path.
48 none,
49 /// Unlink the socket path before binding (ignored for abstract paths).
50 unlink_existing
51 };
52
53 /** Accepts inbound Unix domain stream connections, from a coroutine.
54
55 This class provides asynchronous Unix domain stream accept
56 operations that return awaitable types. The acceptor binds
57 to a local endpoint (filesystem path or abstract name) and
58 listens for incoming connections.
59
60 The library does NOT automatically unlink the socket path
61 on close. Callers are responsible for removing the socket
62 file before bind (via @ref bind_option::unlink_existing) or
63 after close.
64
65 @par Thread Safety
66 Distinct objects: Safe.@n
67 Shared objects: Unsafe. An acceptor must not have concurrent
68 accept operations.
69
70 @par Example
71 @par !example bind_listen_accept
72 */
73 class BOOST_COROSIO_DECL local_stream_acceptor : public io_object
74 {
75 struct wait_awaitable : detail::void_op_base<wait_awaitable>
76 {
77 private:
78 friend local_stream_acceptor;
79
80 8x wait_awaitable(local_stream_acceptor& acc, wait_type w) noexcept
81 16x : acc_(acc)
82 8x , w_(w)
83 {
84 8x }
85
86 friend detail::void_op_base<wait_awaitable>;
87
88 local_stream_acceptor& acc_;
89 wait_type w_;
90
91 std::coroutine_handle<>
92 6x dispatch(capy::continuation& cont, capy::executor_ref ex) const
93 {
94 6x return acc_.get().wait(cont, ex, w_, token_, &ec_);
95 }
96 };
97
98 struct move_accept_awaitable : detail::void_op_base<move_accept_awaitable>
99 {
100 private:
101 friend local_stream_acceptor;
102 friend detail::void_op_base<move_accept_awaitable>;
103
104 local_stream_acceptor& acc_;
105 mutable io_object::implementation* peer_impl_ = nullptr;
106
107
108 8x explicit move_accept_awaitable(local_stream_acceptor& acc) noexcept
109 8x : acc_(acc)
110 {
111 8x }
112
113 std::coroutine_handle<>
114 6x dispatch(capy::continuation& cont, capy::executor_ref ex) const
115 {
116 18x return acc_.get().accept(
117 18x cont, ex, this->token_, &this->ec_, &peer_impl_);
118 }
119
120 public:
121 // A peer accepted for an awaiter that never resumed is closed
122 // here, or nothing would own it.
123 16x ~move_accept_awaitable()
124 {
125 16x if (peer_impl_)
126 2x discard_peer(acc_, peer_impl_);
127 16x }
128
129 [[nodiscard]] capy::results<local_stream_socket>
130 6x await_resume() const noexcept
131 {
132 6x if (this->ec_ || !peer_impl_)
133 4x return {this->ec_, local_stream_socket()};
134
135 2x local_stream_socket peer(acc_.ctx_);
136 2x reset_peer_impl(peer, std::exchange(peer_impl_, nullptr));
137 2x return {this->ec_, std::move(peer)};
138 2x }
139 };
140
141 struct accept_awaitable : detail::void_op_base<accept_awaitable>
142 {
143 private:
144 friend local_stream_acceptor;
145 friend detail::void_op_base<accept_awaitable>;
146
147 local_stream_acceptor& acc_;
148 local_stream_socket& peer_;
149 mutable io_object::implementation* peer_impl_ = nullptr;
150
151
152 33x accept_awaitable(
153 local_stream_acceptor& acc, local_stream_socket& peer) noexcept
154 66x : acc_(acc)
155 33x , peer_(peer)
156 {
157 33x }
158
159 std::coroutine_handle<>
160 29x dispatch(capy::continuation& cont, capy::executor_ref ex) const
161 {
162 87x return acc_.get().accept(
163 87x cont, ex, this->token_, &this->ec_, &peer_impl_);
164 }
165
166 public:
167 // A peer accepted for an awaiter that never resumed is closed
168 // here, or nothing would own it.
169 66x ~accept_awaitable()
170 {
171 66x if (peer_impl_)
172 2x discard_peer(acc_, peer_impl_);
173 66x }
174
175 29x [[nodiscard]] capy::results<> await_resume() const noexcept
176 {
177 29x if (!this->ec_ && peer_impl_)
178 19x peer_.h_.reset(std::exchange(peer_impl_, nullptr));
179 29x return {this->ec_};
180 }
181 };
182
183 public:
184 /** Closes the acceptor if open, cancelling any pending operations.
185 */
186 ~local_stream_acceptor() override;
187
188 /** Construct an acceptor from an execution context.
189
190 @param ctx The execution context that owns this acceptor.
191 */
192 explicit local_stream_acceptor(capy::execution_context& ctx);
193
194 /** Convenience constructor: open + bind + listen.
195
196 Creates a fully-bound listening acceptor in a single
197 expression, throwing the codes the piecewise `open()` +
198 `bind()` + `listen()` path returns.
199
200 @param ctx The execution context that owns this acceptor.
201 @param ep The local endpoint to bind to.
202 @param backlog The maximum pending connection queue length.
203
204 @throws std::system_error on open, bind, or listen failure.
205 */
206 local_stream_acceptor(
207 capy::execution_context& ctx,
208 corosio::local_endpoint ep,
209 int backlog = 128);
210
211 /** Construct an acceptor from an executor.
212
213 The acceptor is associated with the executor's context.
214
215 @param ex The executor whose context owns the acceptor.
216
217 @tparam Ex A type satisfying @ref capy::Executor. Must not
218 be `local_stream_acceptor` itself (disables implicit
219 conversion from move).
220 */
221 template<class Ex>
222 requires(!std::
223 same_as<std::remove_cvref_t<Ex>, local_stream_acceptor>) &&
224 capy::Executor<Ex>
225 explicit local_stream_acceptor(Ex const& ex)
226 : local_stream_acceptor(ex.context())
227 {
228 }
229
230 /** Convenience constructor from an executor.
231
232 @param ex The executor whose context owns the acceptor.
233 @param ep The local endpoint to bind to.
234 @param backlog The maximum pending connection queue length.
235
236 @tparam Ex A type satisfying @ref capy::Executor.
237
238 @throws std::system_error on open, bind, or listen failure.
239 */
240 template<class Ex>
241 requires capy::Executor<Ex>
242 local_stream_acceptor(
243 Ex const& ex, corosio::local_endpoint ep, int backlog = 128)
244 : local_stream_acceptor(ex.context(), std::move(ep), backlog)
245 {
246 }
247
248 /** Transfers ownership of the acceptor resources from another
249 acceptor.
250
251 @param other The acceptor to move from.
252
253 @pre No awaitables returned by @p other's methods exist.
254 @pre The execution context associated with @p other must
255 outlive this acceptor.
256 */
257 2x local_stream_acceptor(local_stream_acceptor&& other) noexcept
258 2x : local_stream_acceptor(other.ctx_, std::move(other))
259 {
260 2x }
261
262 /** Closes any existing acceptor and transfers ownership from
263 another acceptor. Both acceptors must share the same
264 execution context.
265
266 @param other The acceptor to move from.
267
268 @return Reference to this acceptor.
269
270 @pre `&ctx_ == &other.ctx_` (same execution context).
271 @pre No awaitables returned by either `*this` or @p other's
272 methods exist.
273 */
274 local_stream_acceptor& operator=(local_stream_acceptor&& other) noexcept
275 {
276 assert(
277 &ctx_ == &other.ctx_ &&
278 "move-assign requires the same execution_context");
279 if (this != &other)
280 {
281 close();
282 io_object::operator=(std::move(other));
283 }
284 return *this;
285 }
286
287 /// Copy construction is disabled; the handle is uniquely owned.
288 local_stream_acceptor(local_stream_acceptor const&) = delete;
289 /// Copy assignment is disabled; the handle is uniquely owned.
290 local_stream_acceptor& operator=(local_stream_acceptor const&) = delete;
291
292 /** Create the acceptor socket.
293
294 Failures such as descriptor exhaustion are normal runtime
295 conditions and are reported through the returned error code.
296
297
298 @return The error code, empty on success.
299 */
300 [[nodiscard]] std::error_code open() noexcept;
301
302 /** Bind to a local endpoint.
303
304 @param ep The local endpoint (path) to bind to.
305 @param opt Bind options. Pass bind_option::unlink_existing
306 to unlink the socket path before binding (ignored for
307 abstract sockets and empty endpoints).
308
309 @return An error code on failure, empty on success.
310
311 A closed acceptor reports `errc::bad_file_descriptor`.
312 */
313 [[nodiscard]] std::error_code bind(
314 corosio::local_endpoint ep,
315 bind_option opt = bind_option::none) noexcept;
316
317 /** Start listening for incoming connections.
318
319 @param backlog The maximum pending connection queue length.
320
321 @return An error code on failure, empty on success.
322
323 A closed acceptor reports `errc::bad_file_descriptor`.
324 */
325 [[nodiscard]] std::error_code listen(int backlog = 128) noexcept;
326
327 /** Close the acceptor.
328
329 Cancels any pending accept operations and releases the
330 underlying socket. Has no effect if the acceptor is not
331 open.
332
333 @post is_open() == false
334 */
335 void close() noexcept;
336
337 /** Check if the acceptor has an open socket handle.
338
339 @return `true` if the acceptor holds an open handle.
340 */
341 613x bool is_open() const noexcept
342 {
343 613x return h_ && get().is_open();
344 }
345
346 /** Initiate an asynchronous accept into an existing socket.
347
348 Completes when a new connection is available. On success
349 @p peer is reset to the accepted connection. Only one
350 accept may be in flight at a time.
351
352 @param peer The socket to receive the accepted connection.
353
354 @par Cancellation
355 Supports cancellation via stop_token or cancel().
356 On cancellation, yields `capy::cond::canceled` and
357 @p peer is not modified.
358
359 @return An awaitable that completes with `results<>`.
360
361 A closed acceptor reports `errc::bad_file_descriptor`.
362 */
363 33x [[nodiscard]] auto accept(local_stream_socket& peer)
364 {
365 33x accept_awaitable aw(*this, peer);
366 33x if (!is_open())
367 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
368 33x return aw;
369 }
370
371 /** Wait for an incoming connection or readiness condition.
372
373 Suspends until the listen socket is ready in the
374 requested direction. For `wait_type::read`, completion
375 signals that a subsequent @ref accept succeeds
376 without blocking. A connection already queued when the
377 wait begins completes it immediately. No connection is
378 consumed.
379
380 @note `wait_type::write` is not usable on an acceptor:
381 writability carries no meaning for a listening socket, so
382 the wait fails with `errc::operation_not_supported` on
383 every backend.
384
385 @param w The wait direction.
386
387 @return An awaitable that completes with `results<>`.
388
389 A closed acceptor completes with `errc::bad_file_descriptor`.
390
391 @pre This acceptor must outlive the returned awaitable.
392 */
393 8x [[nodiscard]] auto wait(wait_type w)
394 {
395 8x wait_awaitable aw(*this, w);
396 8x if (!is_open())
397 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
398 8x return aw;
399 }
400
401 /** Initiate an asynchronous accept, returning the socket.
402
403 Completes when a new connection is available. Only one
404 accept may be in flight at a time.
405
406 @par Cancellation
407 Supports cancellation via stop_token or cancel().
408 On cancellation, yields `capy::cond::canceled` with
409 a default-constructed socket.
410
411 @return An awaitable that completes with
412 results<`local_stream_socket`>.
413
414 A closed acceptor reports `errc::bad_file_descriptor`.
415 On failure the returned socket is default-constructed and
416 may only be destroyed or assigned.
417 */
418 8x [[nodiscard]] auto accept()
419 {
420 8x move_accept_awaitable aw(*this);
421 8x if (!is_open())
422 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
423 8x return aw;
424 }
425
426 /** Cancel pending asynchronous accept operations.
427
428 Outstanding accept operations complete with
429 @c capy::cond::canceled. Safe to call when no
430 operations are pending (no-op).
431 */
432 void cancel() noexcept;
433
434 /** Release ownership of the native socket handle.
435
436 Deregisters the acceptor from the reactor and cancels
437 pending operations without closing the descriptor. The
438 caller takes ownership of the returned handle.
439
440 @note With the IOCP backend, a socket released while operations
441 on it are in flight stays bound to this context's completion
442 port for good. Windows refuses to unbind a handle with I/O
443 outstanding, so no context, this one included, can assign it
444 afterwards. Its cancelled operations still complete normally.
445
446 @return The native handle.
447
448 @throws std::system_error `errc::bad_file_descriptor` if the
449 acceptor is not open.
450
451 @post is_open() == false
452 */
453 native_handle_type release();
454
455 /** Get the native socket handle.
456
457 @return The native socket handle, or -1/INVALID_SOCKET if not
458 open.
459
460 @pre None. May be called on closed acceptors.
461 */
462 native_handle_type native_handle() const noexcept;
463
464 /** Assign an existing native socket to this acceptor.
465
466 Adopts a listening socket created outside the library —
467 received from a service manager, inherited, or made natively —
468 and registers it with the backend. The socket must be a
469 listening stream socket in the local IPC family. Adoption
470 never alters the descriptor's flags or options: on POSIX the
471 fd must already be non-blocking, and on Windows the socket
472 must be overlapped-capable.
473
474 Adoption does not verify listen state; @ref accept reports the
475 error if the socket is not listening.
476
477 The object must be closed. To replace a held socket, `close()`
478 or `release()` it first.
479
480 @par Exception Safety
481 Throws nothing. On failure the object is unchanged and the
482 caller retains ownership of `fd`.
483
484 @param fd The native socket to adopt. On success the object
485 owns it and closes it.
486
487 @return `error::already_open` if this object is open.
488 Otherwise the error code, empty on success. Validation and
489 registration failures are normal runtime conditions when
490 adopting foreign descriptors.
491 */
492 [[nodiscard]] std::error_code assign(native_handle_type fd) noexcept;
493
494 /** Return the local endpoint the acceptor is bound to.
495
496 Safe to call in any state.
497
498 @return The bound local endpoint, or a default-constructed
499 endpoint if the acceptor is not open or not yet bound.
500 */
501 corosio::local_endpoint local_endpoint() const noexcept;
502
503 /** Set a socket option on the acceptor.
504
505 Applies a type-safe socket option to the underlying socket.
506 The option type encodes the protocol level and option name.
507
508 @param opt The option to set.
509
510 @tparam Option A socket option type providing static
511 `level()` and `name()` members, and `data()` / `size()`
512 accessors.
513
514 @throws std::system_error `errc::bad_file_descriptor` if the
515 acceptor is not open; otherwise thrown on failure.
516 */
517 template<class Option>
518 6x void set_option(Option const& opt)
519 {
520 6x if (!is_open())
521 2x detail::throw_system_error(
522 4x make_error_code(std::errc::bad_file_descriptor),
523 "local_stream_acceptor::set_option");
524 4x auto const fam = get().family();
525 4x std::error_code ec = get().set_option(
526 opt.level(fam), opt.name(fam), opt.data(fam), opt.size(fam));
527 4x if (ec)
528 2x detail::throw_system_error(ec, "local_stream_acceptor::set_option");
529 2x }
530
531 /** Get a socket option from the acceptor.
532
533 Retrieves the current value of a type-safe socket option.
534
535 @return The current option value.
536
537 @tparam Option A socket option type providing static
538 `level()` and `name()` members, and `data()` / `size()`
539 / `resize()` members.
540
541 @throws std::system_error `errc::bad_file_descriptor` if the
542 acceptor is not open; otherwise thrown on failure.
543 */
544 template<class Option>
545 6x Option get_option() const
546 {
547 6x if (!is_open())
548 2x detail::throw_system_error(
549 4x make_error_code(std::errc::bad_file_descriptor),
550 "local_stream_acceptor::get_option");
551 4x Option opt{};
552 4x auto const fam = get().family();
553 4x std::size_t sz = opt.size(fam);
554 std::error_code ec =
555 4x get().get_option(opt.level(fam), opt.name(fam), opt.data(fam), &sz);
556 4x if (ec)
557 2x detail::throw_system_error(ec, "local_stream_acceptor::get_option");
558 2x opt.resize(fam, sz);
559 2x return opt;
560 }
561
562 /** Backends derive from this to implement accept, option, and
563 lifecycle management.
564 */
565 struct implementation : io_object::implementation
566 {
567 /** Initiate an asynchronous accept.
568
569 On completion the backend sets @p *ec and, on
570 success, stores a pointer to the new socket
571 implementation in @p *impl_out.
572
573 @param cont Continuation to resume on completion; it lives in
574 the awaiting frame until then.
575 @param ex Executor for dispatching the completion.
576 @param token Stop token for cancellation.
577 @param ec Output error code.
578 @param impl_out Output pointer for the accepted socket.
579 @return Coroutine handle to resume immediately.
580 */
581 virtual std::coroutine_handle<> accept(
582 capy::continuation& cont,
583 capy::executor_ref ex,
584 std::stop_token token,
585 std::error_code* ec,
586 io_object::implementation** impl_out) = 0;
587
588 /** Initiate an asynchronous wait for acceptor readiness.
589
590 Completes when the listen socket becomes ready for
591 the specified direction. No connection is consumed.
592
593 @param cont Continuation to resume on completion; it lives in
594 the awaiting frame until then.
595 @param ex Executor for dispatching the completion.
596 @param w The direction to wait on.
597 @param token Stop token for cancellation.
598 @param ec Output error code.
599
600 @return Coroutine handle to resume immediately.
601 */
602 virtual std::coroutine_handle<> wait(
603 capy::continuation& cont,
604 capy::executor_ref ex,
605 wait_type w,
606 std::stop_token token,
607 std::error_code* ec) = 0;
608
609 /// Return the cached local endpoint.
610 virtual corosio::local_endpoint local_endpoint() const noexcept = 0;
611
612 /// Return whether the underlying socket is open.
613 virtual bool is_open() const noexcept = 0;
614
615 /// Return the native handle, or the platform sentinel if closed.
616 virtual native_handle_type native_handle() const noexcept = 0;
617
618 /** Return the socket's address family.
619
620 Local sockets have no IP family; implementations return
621 `v4`, which the family-neutral options applicable to them
622 ignore.
623
624 @return The address family for option rendering.
625 */
626 virtual corosio::family family() const noexcept = 0;
627
628 /// Release and return the native handle without closing.
629 virtual native_handle_type release_socket() noexcept = 0;
630
631 /// Cancel pending accept operations.
632 virtual void cancel() noexcept = 0;
633
634 /** Set a raw socket option.
635
636 @param level The protocol level (e.g. `SOL_SOCKET`).
637 @param optname The option name.
638 @param data Pointer to the option value.
639 @param size Size of the option value in bytes.
640
641 @return The error code, empty on success.
642 */
643 virtual std::error_code set_option(
644 int level,
645 int optname,
646 void const* data,
647 std::size_t size) noexcept = 0;
648
649 /** Get a raw socket option.
650
651 @param level The protocol level (e.g. `SOL_SOCKET`).
652 @param optname The option name.
653 @param data Pointer to storage for the option value.
654 @param size In/out size of the storage, in bytes.
655
656 @return The error code, empty on success.
657 */
658 virtual std::error_code
659 get_option(int level, int optname, void* data, std::size_t* size)
660 const noexcept = 0;
661 };
662
663 protected:
664 /** Adopt an existing handle bound to a context.
665
666 @param h The handle the acceptor takes ownership of.
667
668 @param ctx The context the acceptor draws its service from.
669 */
670 18x local_stream_acceptor(handle h, capy::execution_context& ctx) noexcept
671 18x : io_object(std::move(h))
672 18x , ctx_(ctx)
673 {
674 18x }
675
676 /** Move construct, rebinding to a context.
677
678 @param ctx The context the acceptor draws its service from.
679
680 @param other The acceptor to take the handle from.
681 */
682 2x local_stream_acceptor(
683 capy::execution_context& ctx, local_stream_acceptor&& other) noexcept
684 2x : io_object(std::move(other))
685 2x , ctx_(ctx)
686 {
687 2x }
688
689 /** Install an accepted implementation into the peer socket.
690
691 Derived acceptors call this to hand the accepted connection to
692 the caller's socket, which cannot reach @ref io_object::handle
693 itself.
694
695 @param peer The socket receiving the accepted connection.
696
697 @param impl The accepted implementation, or `nullptr` on failure.
698 */
699 8x static void reset_peer_impl(
700 local_stream_socket& peer, io_object::implementation* impl) noexcept
701 {
702 8x if (impl)
703 8x peer.h_.reset(impl);
704 8x }
705
706 private:
707 capy::execution_context& ctx_;
708
709 708x inline implementation& get() const noexcept
710 {
711 708x return *static_cast<implementation*>(h_.get());
712 }
713
714 /// Close and release a non-null accepted peer no socket took over.
715 static void discard_peer(
716 local_stream_acceptor& acc, io_object::implementation* impl) noexcept;
717 };
718
719 } // namespace boost::corosio
720
721 #endif // BOOST_COROSIO_LOCAL_STREAM_ACCEPTOR_HPP
722