include/boost/corosio/tcp_acceptor.hpp

95.2% Lines (79/0/83) 100.0% List of functions (28/0/28)
tcp_acceptor.hpp
f(x) Functions (28)
Function Calls Lines Blocks
boost::corosio::tcp_acceptor::wait_awaitable::wait_awaitable(boost::corosio::tcp_acceptor&, boost::corosio::wait_type) :92 15x 100.0% 100.0% boost::corosio::tcp_acceptor::wait_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :95 15x 100.0% 80.0% boost::corosio::tcp_acceptor::accept_awaitable::accept_awaitable(boost::corosio::tcp_acceptor&, boost::corosio::tcp_socket&) :110 4368x 100.0% 100.0% boost::corosio::tcp_acceptor::accept_awaitable::await_ready() const :116 4368x 100.0% 100.0% boost::corosio::tcp_acceptor::accept_awaitable::await_resume() const :121 4366x 100.0% 100.0% boost::corosio::tcp_acceptor::accept_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :131 4368x 100.0% 82.0% boost::corosio::tcp_acceptor::accept_value_awaitable::accept_value_awaitable(boost::corosio::tcp_acceptor&) :148 27x 100.0% 100.0% boost::corosio::tcp_acceptor::accept_value_awaitable::await_ready() const :154 27x 100.0% 100.0% boost::corosio::tcp_acceptor::accept_value_awaitable::await_resume() :159 27x 71.4% 69.0% boost::corosio::tcp_acceptor::accept_value_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :170 27x 100.0% 82.0% boost::corosio::tcp_acceptor::tcp_acceptor<boost::corosio::io_context::executor_type>(boost::corosio::io_context::executor_type const&) :214 1x 100.0% 100.0% boost::corosio::tcp_acceptor::tcp_acceptor(boost::corosio::tcp_acceptor&&) :243 5x 100.0% 100.0% boost::corosio::tcp_acceptor::operator=(boost::corosio::tcp_acceptor&&) :258 3x 100.0% 100.0% boost::corosio::tcp_acceptor::is_open() const :344 7234x 100.0% 100.0% boost::corosio::tcp_acceptor::accept(boost::corosio::tcp_socket&) :387 4370x 100.0% 100.0% boost::corosio::tcp_acceptor::accept() :429 29x 100.0% 100.0% boost::corosio::tcp_acceptor::wait(boost::corosio::wait_type) :458 17x 100.0% 100.0% void boost::corosio::tcp_acceptor::set_option<boost::corosio::native_socket_option::boolean<1, 15> >(boost::corosio::native_socket_option::boolean<1, 15> const&) :570 2x 71.4% 86.0% void boost::corosio::tcp_acceptor::set_option<boost::corosio::native_socket_option::boolean<1, 2> >(boost::corosio::native_socket_option::boolean<1, 2> const&) :570 12x 71.4% 86.0% void boost::corosio::tcp_acceptor::set_option<boost::corosio::socket_option::reuse_address>(boost::corosio::socket_option::reuse_address const&) :570 382x 85.7% 93.0% void boost::corosio::tcp_acceptor::set_option<boost::corosio::socket_option::reuse_port>(boost::corosio::socket_option::reuse_port const&) :570 2x 71.4% 86.0% void boost::corosio::tcp_acceptor::set_option<boost::corosio::socket_option::v6_only>(boost::corosio::socket_option::v6_only const&) :570 2x 71.4% 86.0% boost::corosio::native_socket_option::boolean<1, 15> boost::corosio::tcp_acceptor::get_option<boost::corosio::native_socket_option::boolean<1, 15> >() const :595 2x 80.0% 88.0% boost::corosio::socket_option::reuse_address boost::corosio::tcp_acceptor::get_option<boost::corosio::socket_option::reuse_address>() const :595 4x 90.0% 94.0% boost::corosio::socket_option::reuse_port boost::corosio::tcp_acceptor::get_option<boost::corosio::socket_option::reuse_port>() const :595 2x 80.0% 88.0% boost::corosio::tcp_acceptor::tcp_acceptor(boost::corosio::io_object::handle) :686 21x 100.0% 100.0% boost::corosio::tcp_acceptor::reset_peer_impl(boost::corosio::tcp_socket&, boost::corosio::io_object::implementation*) :690 11x 100.0% 100.0% boost::corosio::tcp_acceptor::get() const :697 12436x 100.0% 100.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2026 Steve Gerbino
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #ifndef BOOST_COROSIO_TCP_ACCEPTOR_HPP
12 #define BOOST_COROSIO_TCP_ACCEPTOR_HPP
13
14 #include <boost/corosio/detail/config.hpp>
15 #include <boost/corosio/detail/except.hpp>
16 #include <boost/corosio/detail/native_handle.hpp>
17 #include <boost/corosio/detail/op_base.hpp>
18 #include <boost/corosio/wait_type.hpp>
19 #include <boost/corosio/io/io_object.hpp>
20 #include <boost/capy/io_result.hpp>
21 #include <boost/corosio/endpoint.hpp>
22 #include <boost/corosio/tcp.hpp>
23 #include <boost/corosio/tcp_socket.hpp>
24 #include <boost/capy/ex/executor_ref.hpp>
25 #include <boost/capy/ex/execution_context.hpp>
26 #include <boost/capy/ex/io_env.hpp>
27 #include <boost/capy/concept/executor.hpp>
28
29 #include <system_error>
30
31 #include <concepts>
32 #include <coroutine>
33 #include <cstddef>
34 #include <stop_token>
35 #include <type_traits>
36
37 namespace boost::corosio {
38
39 /** An asynchronous TCP acceptor for coroutine I/O.
40
41 This class provides asynchronous TCP accept operations that return
42 awaitable types. The acceptor binds to a local endpoint and listens
43 for incoming connections.
44
45 Each accept operation participates in the affine awaitable protocol,
46 ensuring coroutines resume on the correct executor.
47
48 @par Thread Safety
49 Distinct objects: Safe.@n
50 Shared objects: Unsafe. An acceptor must not have concurrent accept
51 operations.
52
53 @par Semantics
54 Wraps the platform TCP listener. Operations dispatch to
55 OS accept APIs via the io_context reactor.
56
57 @par Example
58 @code
59 // Convenience constructor: open + SO_REUSEADDR + bind + listen
60 io_context ioc;
61 tcp_acceptor acc( ioc, endpoint( 8080 ) );
62
63 tcp_socket peer( ioc );
64 auto [ec] = co_await acc.accept( peer );
65 if ( !ec ) {
66 // peer is now a connected socket
67 auto [ec2, n] = co_await peer.read_some( buf );
68 }
69 @endcode
70
71 @par Example
72 @code
73 // Fine-grained setup
74 tcp_acceptor acc( ioc );
75 acc.open( tcp::v6() );
76 acc.set_option( socket_option::reuse_address( true ) );
77 acc.set_option( socket_option::v6_only( true ) );
78 if ( auto ec = acc.bind( endpoint( ipv6_address::any(), 8080 ) ) )
79 return ec;
80 if ( auto ec = acc.listen() )
81 return ec;
82 @endcode
83 */
84 class BOOST_COROSIO_DECL tcp_acceptor : public io_object
85 {
86 struct wait_awaitable
87 : detail::void_op_base<wait_awaitable>
88 {
89 tcp_acceptor& acc_;
90 wait_type w_;
91
92 15x wait_awaitable(tcp_acceptor& acc, wait_type w) noexcept
93 15x : acc_(acc), w_(w) {}
94
95 15x std::coroutine_handle<> dispatch(
96 std::coroutine_handle<> h, capy::executor_ref ex) const
97 {
98 15x return acc_.get().wait(h, ex, w_, token_, &ec_);
99 }
100 };
101
102 struct accept_awaitable
103 {
104 tcp_acceptor& acc_;
105 tcp_socket& peer_;
106 std::stop_token token_;
107 mutable std::error_code ec_;
108 mutable io_object::implementation* peer_impl_ = nullptr;
109
110 4368x accept_awaitable(tcp_acceptor& acc, tcp_socket& peer) noexcept
111 4368x : acc_(acc)
112 4368x , peer_(peer)
113 {
114 4368x }
115
116 4368x bool await_ready() const noexcept
117 {
118 4368x return token_.stop_requested();
119 }
120
121 4366x [[nodiscard]] capy::io_result<> await_resume() const noexcept
122 {
123 4366x if (token_.stop_requested())
124 27x return {make_error_code(std::errc::operation_canceled)};
125
126 4339x if (!ec_ && peer_impl_)
127 4330x peer_.h_.reset(peer_impl_);
128 4339x return {ec_};
129 }
130
131 4368x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
132 -> std::coroutine_handle<>
133 {
134 4368x token_ = env->stop_token;
135 13104x return acc_.get().accept(
136 13104x h, env->executor, token_, &ec_, &peer_impl_);
137 }
138 };
139
140 struct accept_value_awaitable
141 {
142 tcp_acceptor& acc_;
143 tcp_socket peer_;
144 std::stop_token token_;
145 mutable std::error_code ec_;
146 mutable io_object::implementation* peer_impl_ = nullptr;
147
148 27x explicit accept_value_awaitable(tcp_acceptor& acc)
149 27x : acc_(acc)
150 27x , peer_(acc.context())
151 {
152 27x }
153
154 27x bool await_ready() const noexcept
155 {
156 27x return token_.stop_requested();
157 }
158
159 27x [[nodiscard]] capy::io_result<tcp_socket> await_resume() noexcept
160 {
161 27x if (token_.stop_requested())
162 return {make_error_code(std::errc::operation_canceled),
163 std::move(peer_)};
164
165 27x if (!ec_ && peer_impl_)
166 27x peer_.h_.reset(peer_impl_);
167 27x return {ec_, std::move(peer_)};
168 }
169
170 27x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
171 -> std::coroutine_handle<>
172 {
173 27x token_ = env->stop_token;
174 81x return acc_.get().accept(
175 81x h, env->executor, token_, &ec_, &peer_impl_);
176 }
177 };
178
179 public:
180 /** Destructor.
181
182 Closes the acceptor if open, cancelling any pending operations.
183 */
184 ~tcp_acceptor() override;
185
186 /** Construct an acceptor from an execution context.
187
188 @param ctx The execution context that will own this acceptor.
189 */
190 explicit tcp_acceptor(capy::execution_context& ctx);
191
192 /** Convenience constructor: open + SO_REUSEADDR + bind + listen.
193
194 Creates a fully-bound listening acceptor in a single
195 expression. The address family is deduced from @p ep.
196
197 @param ctx The execution context that will own this acceptor.
198 @param ep The local endpoint to bind to.
199 @param backlog The maximum pending connection queue length.
200
201 @throws std::system_error on bind or listen failure.
202 */
203 tcp_acceptor(capy::execution_context& ctx, endpoint ep, int backlog = 128);
204
205 /** Construct an acceptor from an executor.
206
207 The acceptor is associated with the executor's context.
208
209 @param ex The executor whose context will own the acceptor.
210 */
211 template<class Ex>
212 requires(!std::same_as<std::remove_cvref_t<Ex>, tcp_acceptor>) &&
213 capy::Executor<Ex>
214 1x explicit tcp_acceptor(Ex const& ex) : tcp_acceptor(ex.context())
215 {
216 1x }
217
218 /** Convenience constructor from an executor.
219
220 @param ex The executor whose context will own the acceptor.
221 @param ep The local endpoint to bind to.
222 @param backlog The maximum pending connection queue length.
223
224 @throws std::system_error on bind or listen failure.
225 */
226 template<class Ex>
227 requires capy::Executor<Ex>
228 tcp_acceptor(Ex const& ex, endpoint ep, int backlog = 128)
229 : tcp_acceptor(ex.context(), ep, backlog)
230 {
231 }
232
233 /** Move constructor.
234
235 Transfers ownership of the acceptor resources.
236
237 @param other The acceptor to move from.
238
239 @pre No awaitables returned by @p other's methods exist.
240 @pre The execution context associated with @p other must
241 outlive this acceptor.
242 */
243 5x tcp_acceptor(tcp_acceptor&& other) noexcept : io_object(std::move(other)) {}
244
245 /** Move assignment operator.
246
247 Closes any existing acceptor and transfers ownership.
248
249 @param other The acceptor to move from.
250
251 @pre No awaitables returned by either `*this` or @p other's
252 methods exist.
253 @pre The execution context associated with @p other must
254 outlive this acceptor.
255
256 @return Reference to this acceptor.
257 */
258 3x tcp_acceptor& operator=(tcp_acceptor&& other) noexcept
259 {
260 3x if (this != &other)
261 {
262 3x close();
263 3x h_ = std::move(other.h_);
264 }
265 3x return *this;
266 }
267
268 tcp_acceptor(tcp_acceptor const&) = delete;
269 tcp_acceptor& operator=(tcp_acceptor const&) = delete;
270
271 /** Create the acceptor socket without binding or listening.
272
273 Creates a TCP socket with dual-stack enabled for IPv6.
274 Does not set SO_REUSEADDR — call `set_option` explicitly
275 if needed.
276
277 If the acceptor is already open, this function is a no-op.
278
279 @param proto The protocol (IPv4 or IPv6). Defaults to
280 `tcp::v4()`.
281
282 @throws std::system_error on failure.
283
284 @par Example
285 @code
286 acc.open( tcp::v6() );
287 acc.set_option( socket_option::reuse_address( true ) );
288 acc.bind( endpoint( ipv6_address::any(), 8080 ) );
289 acc.listen();
290 @endcode
291
292 @see bind, listen
293 */
294 void open(tcp proto = tcp::v4());
295
296 /** Bind to a local endpoint.
297
298 The acceptor must be open. Binds the socket to @p ep and
299 caches the resolved local endpoint (useful when port 0 is
300 used to request an ephemeral port).
301
302 @param ep The local endpoint to bind to.
303
304 @return An error code indicating success or the reason for
305 failure.
306
307 @par Error Conditions
308 @li `errc::address_in_use`: The endpoint is already in use.
309 @li `errc::address_not_available`: The address is not available
310 on any local interface.
311 @li `errc::permission_denied`: Insufficient privileges to bind
312 to the endpoint (e.g., privileged port).
313
314 @throws std::logic_error if the acceptor is not open.
315 */
316 [[nodiscard]] std::error_code bind(endpoint ep);
317
318 /** Start listening for incoming connections.
319
320 The acceptor must be open and bound. Registers the acceptor
321 with the platform reactor.
322
323 @param backlog The maximum length of the queue of pending
324 connections. Defaults to 128.
325
326 @return An error code indicating success or the reason for
327 failure.
328
329 @throws std::logic_error if the acceptor is not open.
330 */
331 [[nodiscard]] std::error_code listen(int backlog = 128);
332
333 /** Close the acceptor.
334
335 Releases acceptor resources. Any pending operations complete
336 with `errc::operation_canceled`.
337 */
338 void close();
339
340 /** Check if the acceptor is listening.
341
342 @return `true` if the acceptor is open and listening.
343 */
344 7234x bool is_open() const noexcept
345 {
346 7234x return h_ && get().is_open();
347 }
348
349 /** Initiate an asynchronous accept operation.
350
351 Accepts an incoming connection and initializes the provided
352 socket with the new connection. The acceptor must be listening
353 before calling this function.
354
355 The operation supports cancellation via `std::stop_token` through
356 the affine awaitable protocol. If the associated stop token is
357 triggered, the operation completes immediately with
358 `errc::operation_canceled`.
359
360 @param peer The socket to receive the accepted connection. Any
361 existing connection on this socket will be closed.
362
363 @return An awaitable that completes with `io_result<>`.
364 Returns success on successful accept, or an error code on
365 failure including:
366 - operation_canceled: Cancelled via stop_token or cancel().
367 Check `ec == cond::canceled` for portable comparison.
368
369 @par Preconditions
370 The acceptor must be listening (`is_open() == true`).
371 The peer socket must be associated with the same execution context.
372
373 Both this acceptor and @p peer must outlive the returned
374 awaitable.
375
376 @par Example
377 @code
378 tcp_socket peer(ioc);
379 auto [ec] = co_await acc.accept(peer);
380 if (!ec) {
381 // Use peer socket
382 }
383 @endcode
384
385 @see accept()
386 */
387 4370x auto accept(tcp_socket& peer)
388 {
389 4370x if (!is_open())
390 2x detail::throw_logic_error("accept: acceptor not listening");
391 4368x return accept_awaitable(*this, peer);
392 }
393
394 /** Initiate an asynchronous accept operation, returning the peer.
395
396 Accepts an incoming connection and returns a newly constructed
397 socket for it, associated with this acceptor's execution context.
398 The acceptor must be listening before calling this function.
399
400 The caller does not pre-construct the peer socket; the returned
401 socket shares this acceptor's execution context.
402
403 The operation supports cancellation via `std::stop_token` through
404 the affine awaitable protocol. If the associated stop token is
405 triggered, the operation completes immediately with
406 `errc::operation_canceled`.
407
408 @return An awaitable that completes with `io_result<tcp_socket>`.
409 On success the payload is the connected peer socket; on failure
410 (including cancellation) the error code is set and the payload
411 socket is unconnected. Errors include:
412 - operation_canceled: Cancelled via stop_token or cancel().
413 Check `ec == cond::canceled` for portable comparison.
414
415 @par Preconditions
416 The acceptor must be listening (`is_open() == true`). This acceptor
417 must outlive the returned awaitable.
418
419 @par Example
420 @code
421 auto [ec, peer] = co_await acc.accept();
422 if (!ec) {
423 // peer is a connected socket
424 }
425 @endcode
426
427 @see accept(tcp_socket&)
428 */
429 29x auto accept()
430 {
431 29x if (!is_open())
432 2x detail::throw_logic_error("accept: acceptor not listening");
433 27x return accept_value_awaitable(*this);
434 }
435
436 /** Wait for an incoming connection or readiness condition.
437
438 Suspends until the listen socket is ready in the
439 requested direction, or an error condition is reported.
440 For `wait_type::read`, completion signals that a
441 subsequent @ref accept will succeed without blocking; a
442 connection already queued when the wait begins completes
443 it immediately. No connection is consumed.
444
445 @note `wait_type::write` is not usable on an acceptor:
446 writability carries no meaning for a listening socket, so
447 the wait fails with `errc::operation_not_supported` on
448 every backend.
449
450 @param w The wait direction.
451
452 @return An awaitable that completes with `io_result<>`.
453
454 @par Preconditions
455 The acceptor must be listening. This acceptor must
456 outlive the returned awaitable.
457 */
458 17x [[nodiscard]] auto wait(wait_type w)
459 {
460 17x if (!is_open())
461 2x detail::throw_logic_error("wait: acceptor not listening");
462 15x return wait_awaitable(*this, w);
463 }
464
465 /** Cancel any pending asynchronous operations.
466
467 All outstanding operations complete with `errc::operation_canceled`.
468 Check `ec == cond::canceled` for portable comparison.
469 */
470 void cancel();
471
472 /** Get the native socket handle.
473
474 Returns the underlying platform-specific socket descriptor.
475 On POSIX systems this is an `int` file descriptor.
476 On Windows this is a `SOCKET` handle.
477
478 @return The native socket handle, or -1/INVALID_SOCKET if not open.
479
480 @par Preconditions
481 None. May be called on closed acceptors.
482 */
483 native_handle_type native_handle() const noexcept;
484
485 /** Assign an existing native socket to this acceptor.
486
487 Adopts a listening socket created outside the library —
488 received from a service manager, inherited, or made natively —
489 and registers it with the backend. The socket must be a
490 listening stream socket in the `AF_INET` or `AF_INET6` family.
491 Adoption never alters the descriptor's flags or options: on
492 POSIX the fd must already be non-blocking, and on Windows the
493 socket must be overlapped-capable.
494
495 Adoption does not verify listen state; @ref accept reports the
496 error if the socket is not listening.
497
498 If this object is already open, pending operations complete
499 with `errc::operation_canceled` and the held socket is
500 closed before the new one is adopted.
501
502 @par Exception Safety
503 Strong guarantee on validation failure: the object is
504 unchanged. If backend registration fails, the object either
505 retains its previous socket or is left closed, depending on
506 the backend. In all failure cases the caller retains
507 ownership of `fd`.
508
509 @param fd The native socket to adopt. On success the object
510 owns it and will close it.
511
512 @throws std::system_error On validation or registration
513 failure.
514 */
515 void assign(native_handle_type fd);
516
517 /** Release ownership of the native socket handle.
518
519 Deregisters the socket from the backend and cancels pending
520 operations without closing the descriptor. The caller takes
521 ownership of the returned handle.
522
523 @return The native handle.
524
525 @throws std::logic_error if the acceptor is not open.
526
527 @post is_open() == false
528 */
529 native_handle_type release();
530
531 /** Get the local endpoint of the acceptor.
532
533 Returns the local address and port to which the acceptor is bound.
534 This is useful when binding to port 0 (ephemeral port) to discover
535 the OS-assigned port number. The endpoint is cached when bind()
536 is called.
537
538 @return The local endpoint, or a default endpoint (0.0.0.0:0) if
539 the acceptor is not open.
540
541 @par Thread Safety
542 The cached endpoint value is set during bind() and cleared
543 during close(). This function may be called concurrently with
544 accept operations, but must not be called concurrently with
545 bind() or close().
546 */
547 endpoint local_endpoint() const noexcept;
548
549 /** Set a socket option on the acceptor.
550
551 Applies a type-safe socket option to the underlying listening
552 socket. The socket must be open (via `open()` or `listen()`).
553 This is useful for setting options between `open()` and
554 `listen()`, such as `socket_option::reuse_port`.
555
556 @par Example
557 @code
558 acc.open( tcp::v6() );
559 acc.set_option( socket_option::reuse_port( true ) );
560 acc.bind( endpoint( ipv6_address::any(), 8080 ) );
561 acc.listen();
562 @endcode
563
564 @param opt The option to set.
565
566 @throws std::logic_error if the acceptor is not open.
567 @throws std::system_error on failure.
568 */
569 template<class Option>
570 400x void set_option(Option const& opt)
571 {
572 400x if (!is_open())
573 2x detail::throw_logic_error("set_option: acceptor not open");
574 398x std::error_code ec = get().set_option(
575 Option::level(), Option::name(), opt.data(), opt.size());
576 398x if (ec)
577 detail::throw_system_error(ec, "tcp_acceptor::set_option");
578 398x }
579
580 /** Get a socket option from the acceptor.
581
582 Retrieves the current value of a type-safe socket option.
583
584 @par Example
585 @code
586 auto opt = acc.get_option<socket_option::reuse_address>();
587 @endcode
588
589 @return The current option value.
590
591 @throws std::logic_error if the acceptor is not open.
592 @throws std::system_error on failure.
593 */
594 template<class Option>
595 8x Option get_option() const
596 {
597 8x if (!is_open())
598 2x detail::throw_logic_error("get_option: acceptor not open");
599 6x Option opt{};
600 6x std::size_t sz = opt.size();
601 std::error_code ec =
602 6x get().get_option(Option::level(), Option::name(), opt.data(), &sz);
603 6x if (ec)
604 detail::throw_system_error(ec, "tcp_acceptor::get_option");
605 6x opt.resize(sz);
606 6x return opt;
607 }
608
609 /** Define backend hooks for TCP acceptor operations.
610
611 Platform backends derive from this to implement
612 accept, endpoint query, open-state checks, cancellation,
613 and socket-option management.
614 */
615 struct implementation : io_object::implementation
616 {
617 /// Initiate an asynchronous accept operation.
618 virtual std::coroutine_handle<> accept(
619 std::coroutine_handle<>,
620 capy::executor_ref,
621 std::stop_token,
622 std::error_code*,
623 io_object::implementation**) = 0;
624
625 /** Initiate an asynchronous wait for acceptor readiness.
626
627 Completes when the listen socket becomes ready for
628 the specified direction (typically `wait_type::read`
629 for an incoming connection), or an error condition is
630 reported. No connection is consumed.
631 */
632 virtual std::coroutine_handle<> wait(
633 std::coroutine_handle<> h,
634 capy::executor_ref ex,
635 wait_type w,
636 std::stop_token token,
637 std::error_code* ec) = 0;
638
639 /// Returns the cached local endpoint.
640 virtual endpoint local_endpoint() const noexcept = 0;
641
642 /// Return true if the acceptor has a kernel resource open.
643 virtual bool is_open() const noexcept = 0;
644
645 /// Return the native handle, or the platform sentinel if closed.
646 virtual native_handle_type native_handle() const noexcept = 0;
647
648 /// Release and return the native handle without closing.
649 virtual native_handle_type release_socket() noexcept = 0;
650
651 /** Cancel any pending asynchronous operations.
652
653 All outstanding operations complete with operation_canceled error.
654 */
655 virtual void cancel() noexcept = 0;
656
657 /** Set a socket option.
658
659 @param level The protocol level.
660 @param optname The option name.
661 @param data Pointer to the option value.
662 @param size Size of the option value in bytes.
663 @return Error code on failure, empty on success.
664 */
665 virtual std::error_code set_option(
666 int level,
667 int optname,
668 void const* data,
669 std::size_t size) noexcept = 0;
670
671 /** Get a socket option.
672
673 @param level The protocol level.
674 @param optname The option name.
675 @param data Pointer to receive the option value.
676 @param size On entry, the size of the buffer. On exit,
677 the size of the option value.
678 @return Error code on failure, empty on success.
679 */
680 virtual std::error_code
681 get_option(int level, int optname, void* data, std::size_t* size)
682 const noexcept = 0;
683 };
684
685 protected:
686 21x explicit tcp_acceptor(handle h) noexcept : io_object(std::move(h)) {}
687
688 /// Transfer accepted peer impl to the peer socket.
689 static void
690 11x reset_peer_impl(tcp_socket& peer, io_object::implementation* impl) noexcept
691 {
692 11x if (impl)
693 11x peer.h_.reset(impl);
694 11x }
695
696 private:
697 12436x inline implementation& get() const noexcept
698 {
699 12436x return *static_cast<implementation*>(h_.get());
700 }
701 };
702
703 } // namespace boost::corosio
704
705 #endif
706