include/boost/corosio/tcp_acceptor.hpp

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