100.00% Lines (53/53) 100.00% Functions (13/13)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Michael Vandeberg 2   // Copyright (c) 2026 Michael Vandeberg
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP 10   #ifndef BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP
11   #define BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP 11   #define BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP
12   12  
13   #include <boost/corosio/family.hpp> 13   #include <boost/corosio/family.hpp>
14   #include <boost/corosio/detail/config.hpp> 14   #include <boost/corosio/detail/config.hpp>
15   #include <boost/corosio/detail/platform.hpp> 15   #include <boost/corosio/detail/platform.hpp>
16   #include <boost/corosio/detail/except.hpp> 16   #include <boost/corosio/detail/except.hpp>
17   #include <boost/corosio/detail/native_handle.hpp> 17   #include <boost/corosio/detail/native_handle.hpp>
18   #include <boost/corosio/detail/op_base.hpp> 18   #include <boost/corosio/detail/op_base.hpp>
19   #include <boost/corosio/io/io_stream.hpp> 19   #include <boost/corosio/io/io_stream.hpp>
20   #include <boost/capy/io_result.hpp> 20   #include <boost/capy/io_result.hpp>
21   #include <boost/corosio/detail/buffer_param.hpp> 21   #include <boost/corosio/detail/buffer_param.hpp>
22   #include <boost/corosio/error.hpp> 22   #include <boost/corosio/error.hpp>
23   #include <boost/corosio/local_endpoint.hpp> 23   #include <boost/corosio/local_endpoint.hpp>
24   #include <boost/corosio/shutdown_type.hpp> 24   #include <boost/corosio/shutdown_type.hpp>
25   #include <boost/corosio/wait_type.hpp> 25   #include <boost/corosio/wait_type.hpp>
26   #include <boost/capy/ex/executor_ref.hpp> 26   #include <boost/capy/ex/executor_ref.hpp>
27   #include <boost/capy/ex/execution_context.hpp> 27   #include <boost/capy/ex/execution_context.hpp>
28   #include <boost/capy/ex/io_env.hpp> 28   #include <boost/capy/ex/io_env.hpp>
29   #include <boost/capy/concept/executor.hpp> 29   #include <boost/capy/concept/executor.hpp>
30   30  
31   #include <system_error> 31   #include <system_error>
32   32  
33   #include <concepts> 33   #include <concepts>
34   #include <coroutine> 34   #include <coroutine>
35   #include <cstddef> 35   #include <cstddef>
36   #include <stop_token> 36   #include <stop_token>
37   #include <type_traits> 37   #include <type_traits>
38   38  
39   namespace boost::corosio { 39   namespace boost::corosio {
40   40  
41   /** Reads and writes a Unix domain stream, from a coroutine. 41   /** Reads and writes a Unix domain stream, from a coroutine.
42   42  
43   This class provides asynchronous Unix domain stream socket 43   This class provides asynchronous Unix domain stream socket
44   operations that return awaitable types. Each operation 44   operations that return awaitable types. Each operation
45   participates in the affine awaitable protocol, ensuring 45   participates in the affine awaitable protocol, ensuring
46   coroutines resume on the correct executor. 46   coroutines resume on the correct executor.
47   47  
48   The socket must be opened before performing I/O operations. 48   The socket must be opened before performing I/O operations.
49   Operations support cancellation through `std::stop_token` via 49   Operations support cancellation through `std::stop_token` via
50   the affine protocol, or explicitly through the `cancel()` 50   the affine protocol, or explicitly through the `cancel()`
51   member function. 51   member function.
52   52  
53   @par Thread Safety 53   @par Thread Safety
54   Distinct objects: Safe.@n 54   Distinct objects: Safe.@n
55   Shared objects: Unsafe. A socket must not have concurrent 55   Shared objects: Unsafe. A socket must not have concurrent
56   operations of the same type (e.g., two simultaneous reads). 56   operations of the same type (e.g., two simultaneous reads).
57   One read and one write may be in flight simultaneously. 57   One read and one write may be in flight simultaneously.
58   58  
59   @par Semantics 59   @par Semantics
60   Wraps the platform Unix domain socket stack. Operations 60   Wraps the platform Unix domain socket stack. Operations
61   dispatch to OS socket APIs via the `io_context` backend 61   dispatch to OS socket APIs via the `io_context` backend
62   (epoll, kqueue, select, or IOCP). Satisfies @ref capy::Stream. 62   (epoll, kqueue, select, or IOCP). Satisfies @ref capy::Stream.
63   63  
64   @par Example 64   @par Example
65   @par !example connect_and_read 65   @par !example connect_and_read
66   */ 66   */
67   class BOOST_COROSIO_DECL local_stream_socket : public io_stream 67   class BOOST_COROSIO_DECL local_stream_socket : public io_stream
68   { 68   {
69   public: 69   public:
70   /// The endpoint type used by this socket. 70   /// The endpoint type used by this socket.
71   using endpoint_type = corosio::local_endpoint; 71   using endpoint_type = corosio::local_endpoint;
72   72  
73   /// The shutdown direction type used by this socket. 73   /// The shutdown direction type used by this socket.
74   using shutdown_type = corosio::shutdown_type; 74   using shutdown_type = corosio::shutdown_type;
75   using enum corosio::shutdown_type; 75   using enum corosio::shutdown_type;
76   76  
77   /** Define backend hooks for local stream socket operations. 77   /** Define backend hooks for local stream socket operations.
78   78  
79   Platform backends (epoll, kqueue, select) derive from this 79   Platform backends (epoll, kqueue, select) derive from this
80   to implement socket I/O, connection, and option management. 80   to implement socket I/O, connection, and option management.
81   */ 81   */
82   struct implementation : io_stream::implementation 82   struct implementation : io_stream::implementation
83   { 83   {
84   /** Initiate an asynchronous connect to the given endpoint. 84   /** Initiate an asynchronous connect to the given endpoint.
85   85  
86   @param h Coroutine handle to resume on completion. 86   @param h Coroutine handle to resume on completion.
87   @param ex Executor for dispatching the completion. 87   @param ex Executor for dispatching the completion.
88   @param ep The local endpoint (path) to connect to. 88   @param ep The local endpoint (path) to connect to.
89   @param token Stop token for cancellation. 89   @param token Stop token for cancellation.
90   @param ec Output error code. 90   @param ec Output error code.
91   91  
92   @return Coroutine handle to resume immediately. 92   @return Coroutine handle to resume immediately.
93   */ 93   */
94   virtual std::coroutine_handle<> connect( 94   virtual std::coroutine_handle<> connect(
95   std::coroutine_handle<> h, 95   std::coroutine_handle<> h,
96   capy::executor_ref ex, 96   capy::executor_ref ex,
97   corosio::local_endpoint ep, 97   corosio::local_endpoint ep,
98   std::stop_token token, 98   std::stop_token token,
99   std::error_code* ec) = 0; 99   std::error_code* ec) = 0;
100   100  
101   /** Initiate an asynchronous wait for socket readiness. 101   /** Initiate an asynchronous wait for socket readiness.
102   102  
103   Completes when the socket becomes ready for the 103   Completes when the socket becomes ready for the
104   specified direction, or an error condition is 104   specified direction, or an error condition is
105   reported. No bytes are transferred. 105   reported. No bytes are transferred.
106   106  
107   @param h Coroutine handle to resume on completion. 107   @param h Coroutine handle to resume on completion.
108   @param ex Executor for dispatching the completion. 108   @param ex Executor for dispatching the completion.
109   @param w The direction to wait on. 109   @param w The direction to wait on.
110   @param token Stop token for cancellation. 110   @param token Stop token for cancellation.
111   @param ec Output error code. 111   @param ec Output error code.
112   112  
113   @return Coroutine handle to resume immediately. 113   @return Coroutine handle to resume immediately.
114   */ 114   */
115   virtual std::coroutine_handle<> wait( 115   virtual std::coroutine_handle<> wait(
116   std::coroutine_handle<> h, 116   std::coroutine_handle<> h,
117   capy::executor_ref ex, 117   capy::executor_ref ex,
118   wait_type w, 118   wait_type w,
119   std::stop_token token, 119   std::stop_token token,
120   std::error_code* ec) = 0; 120   std::error_code* ec) = 0;
121   121  
122   /** Shut down the socket for the given direction(s). 122   /** Shut down the socket for the given direction(s).
123   123  
124   @param what The shutdown direction. 124   @param what The shutdown direction.
125   125  
126   @return Error code on failure, empty on success. 126   @return Error code on failure, empty on success.
127   */ 127   */
128   virtual std::error_code shutdown(shutdown_type what) noexcept = 0; 128   virtual std::error_code shutdown(shutdown_type what) noexcept = 0;
129   129  
130   /// Return the platform socket descriptor. 130   /// Return the platform socket descriptor.
131   virtual native_handle_type native_handle() const noexcept = 0; 131   virtual native_handle_type native_handle() const noexcept = 0;
132   132  
133   /** Return the socket's address family. 133   /** Return the socket's address family.
134   134  
135   Local sockets have no IP family; implementations return 135   Local sockets have no IP family; implementations return
136   `v4`, which the family-neutral options applicable to them 136   `v4`, which the family-neutral options applicable to them
137   ignore. 137   ignore.
138   138  
139   @return The address family for option rendering. 139   @return The address family for option rendering.
140   */ 140   */
141   virtual corosio::family family() const noexcept = 0; 141   virtual corosio::family family() const noexcept = 0;
142   142  
143   /** Release ownership of the native socket handle. 143   /** Release ownership of the native socket handle.
144   144  
145   Deregisters the socket from the reactor without closing 145   Deregisters the socket from the reactor without closing
146   the descriptor. The caller takes ownership. 146   the descriptor. The caller takes ownership.
147   147  
148   @return The native handle. 148   @return The native handle.
149   */ 149   */
150   virtual native_handle_type release_socket() noexcept = 0; 150   virtual native_handle_type release_socket() noexcept = 0;
151   151  
152   /** Request cancellation of pending asynchronous operations. 152   /** Request cancellation of pending asynchronous operations.
153   153  
154   Operations still in flight complete with `operation_canceled`; an 154   Operations still in flight complete with `operation_canceled`; an
155   operation whose result is already decided reports that result. 155   operation whose result is already decided reports that result.
156   Check `ec == cond::canceled` for portable comparison. 156   Check `ec == cond::canceled` for portable comparison.
157   */ 157   */
158   virtual void cancel() noexcept = 0; 158   virtual void cancel() noexcept = 0;
159   159  
160   /** Set a socket option. 160   /** Set a socket option.
161   161  
162   @param level The protocol level (e.g. `SOL_SOCKET`). 162   @param level The protocol level (e.g. `SOL_SOCKET`).
163   @param optname The option name (e.g. `SO_KEEPALIVE`). 163   @param optname The option name (e.g. `SO_KEEPALIVE`).
164   @param data Pointer to the option value. 164   @param data Pointer to the option value.
165   @param size Size of the option value in bytes. 165   @param size Size of the option value in bytes.
166   @return Error code on failure, empty on success. 166   @return Error code on failure, empty on success.
167   */ 167   */
168   virtual std::error_code set_option( 168   virtual std::error_code set_option(
169   int level, 169   int level,
170   int optname, 170   int optname,
171   void const* data, 171   void const* data,
172   std::size_t size) noexcept = 0; 172   std::size_t size) noexcept = 0;
173   173  
174   /** Get a socket option. 174   /** Get a socket option.
175   175  
176   @param level The protocol level (e.g. `SOL_SOCKET`). 176   @param level The protocol level (e.g. `SOL_SOCKET`).
177   @param optname The option name (e.g. `SO_KEEPALIVE`). 177   @param optname The option name (e.g. `SO_KEEPALIVE`).
178   @param data Pointer to receive the option value. 178   @param data Pointer to receive the option value.
179   @param size On entry, the size of the buffer. On exit, 179   @param size On entry, the size of the buffer. On exit,
180   the size of the option value. 180   the size of the option value.
181   @return Error code on failure, empty on success. 181   @return Error code on failure, empty on success.
182   */ 182   */
183   virtual std::error_code 183   virtual std::error_code
184   get_option(int level, int optname, void* data, std::size_t* size) 184   get_option(int level, int optname, void* data, std::size_t* size)
185   const noexcept = 0; 185   const noexcept = 0;
186   186  
187   /// Return the cached local endpoint. 187   /// Return the cached local endpoint.
188   virtual corosio::local_endpoint local_endpoint() const noexcept = 0; 188   virtual corosio::local_endpoint local_endpoint() const noexcept = 0;
189   189  
190   /// Return the cached remote endpoint. 190   /// Return the cached remote endpoint.
191   virtual corosio::local_endpoint remote_endpoint() const noexcept = 0; 191   virtual corosio::local_endpoint remote_endpoint() const noexcept = 0;
192   }; 192   };
193   193  
194   /// Represent the awaitable returned by @ref connect. 194   /// Represent the awaitable returned by @ref connect.
195   struct connect_awaitable : detail::void_op_base<connect_awaitable> 195   struct connect_awaitable : detail::void_op_base<connect_awaitable>
196   { 196   {
197   private: 197   private:
198   friend local_stream_socket; 198   friend local_stream_socket;
199   199  
HITCBC 200   25 connect_awaitable( 200   25 connect_awaitable(
201   local_stream_socket& s, corosio::local_endpoint ep) noexcept 201   local_stream_socket& s, corosio::local_endpoint ep) noexcept
HITCBC 202   50 : s_(s) 202   50 : s_(s)
HITCBC 203   25 , endpoint_(ep) 203   25 , endpoint_(ep)
204   { 204   {
HITCBC 205   25 } 205   25 }
206   206  
207   friend detail::void_op_base<connect_awaitable>; 207   friend detail::void_op_base<connect_awaitable>;
208   208  
209   local_stream_socket& s_; 209   local_stream_socket& s_;
210   corosio::local_endpoint endpoint_; 210   corosio::local_endpoint endpoint_;
211   211  
212   std::coroutine_handle<> 212   std::coroutine_handle<>
HITCBC 213   23 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 213   23 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
214   { 214   {
HITCBC 215   23 return s_.get().connect(h, ex, endpoint_, token_, &ec_); 215   23 return s_.get().connect(h, ex, endpoint_, token_, &ec_);
216   } 216   }
217   }; 217   };
218   218  
219   /// Represent the awaitable returned by @ref wait. 219   /// Represent the awaitable returned by @ref wait.
220   struct wait_awaitable : detail::void_op_base<wait_awaitable> 220   struct wait_awaitable : detail::void_op_base<wait_awaitable>
221   { 221   {
222   private: 222   private:
223   friend local_stream_socket; 223   friend local_stream_socket;
224   224  
HITCBC 225   16 wait_awaitable(local_stream_socket& s, wait_type w) noexcept 225   16 wait_awaitable(local_stream_socket& s, wait_type w) noexcept
HITCBC 226   32 : s_(s) 226   32 : s_(s)
HITCBC 227   16 , w_(w) 227   16 , w_(w)
228   { 228   {
HITCBC 229   16 } 229   16 }
230   230  
231   friend detail::void_op_base<wait_awaitable>; 231   friend detail::void_op_base<wait_awaitable>;
232   232  
233   local_stream_socket& s_; 233   local_stream_socket& s_;
234   wait_type w_; 234   wait_type w_;
235   235  
236   std::coroutine_handle<> 236   std::coroutine_handle<>
HITCBC 237   14 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 237   14 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
238   { 238   {
HITCBC 239   14 return s_.get().wait(h, ex, w_, token_, &ec_); 239   14 return s_.get().wait(h, ex, w_, token_, &ec_);
240   } 240   }
241   }; 241   };
242   242  
243   public: 243   public:
244   /** Destructor. 244   /** Destructor.
245   245  
246   Closes the socket if open, cancelling any pending operations. 246   Closes the socket if open, cancelling any pending operations.
247   */ 247   */
248   ~local_stream_socket() override; 248   ~local_stream_socket() override;
249   249  
250   /** Construct a socket from an execution context. 250   /** Construct a socket from an execution context.
251   251  
252   @param ctx The execution context that owns this socket. 252   @param ctx The execution context that owns this socket.
253   */ 253   */
254   explicit local_stream_socket(capy::execution_context& ctx); 254   explicit local_stream_socket(capy::execution_context& ctx);
255   255  
256   /** Construct a socket from an executor. 256   /** Construct a socket from an executor.
257   257  
258   The socket is associated with the executor's context. 258   The socket is associated with the executor's context.
259   259  
260   @tparam Ex A type satisfying capy::Executor. 260   @tparam Ex A type satisfying capy::Executor.
261   261  
262   @param ex The executor whose context owns the socket. 262   @param ex The executor whose context owns the socket.
263   */ 263   */
264   template<class Ex> 264   template<class Ex>
265   requires(!std::same_as<std::remove_cvref_t<Ex>, local_stream_socket>) && 265   requires(!std::same_as<std::remove_cvref_t<Ex>, local_stream_socket>) &&
266   capy::Executor<Ex> 266   capy::Executor<Ex>
267   explicit local_stream_socket(Ex const& ex) 267   explicit local_stream_socket(Ex const& ex)
268   : local_stream_socket(ex.context()) 268   : local_stream_socket(ex.context())
269   { 269   {
270   } 270   }
271   271  
272   /** Move constructor. 272   /** Move constructor.
273   273  
274   Transfers ownership of the socket resources. 274   Transfers ownership of the socket resources.
275   275  
276   @param other The socket to move from. 276   @param other The socket to move from.
277   277  
278   @pre No awaitables returned by @p other's methods exist. 278   @pre No awaitables returned by @p other's methods exist.
279   @pre The execution context associated with @p other must 279   @pre The execution context associated with @p other must
280   outlive this socket. 280   outlive this socket.
281   */ 281   */
HITCBC 282   14 local_stream_socket(local_stream_socket&& other) noexcept 282   14 local_stream_socket(local_stream_socket&& other) noexcept
HITCBC 283   14 : io_object(std::move(other)) 283   14 : io_object(std::move(other))
284   { 284   {
HITCBC 285   14 } 285   14 }
286   286  
287   /** Move assignment operator. 287   /** Move assignment operator.
288   288  
289   Closes any existing socket and transfers ownership. 289   Closes any existing socket and transfers ownership.
290   290  
291   @param other The socket to move from. 291   @param other The socket to move from.
292   292  
293   @pre No awaitables returned by either `*this` or @p other's 293   @pre No awaitables returned by either `*this` or @p other's
294   methods exist. 294   methods exist.
295   @pre The execution context associated with @p other must 295   @pre The execution context associated with @p other must
296   outlive this socket. 296   outlive this socket.
297   297  
298   @return Reference to this socket. 298   @return Reference to this socket.
299   */ 299   */
HITCBC 300   4 local_stream_socket& operator=(local_stream_socket&& other) noexcept 300   4 local_stream_socket& operator=(local_stream_socket&& other) noexcept
301   { 301   {
HITCBC 302   4 if (this != &other) 302   4 if (this != &other)
303   { 303   {
HITCBC 304   2 close(); 304   2 close();
HITCBC 305   2 io_object::operator=(std::move(other)); 305   2 io_object::operator=(std::move(other));
306   } 306   }
HITCBC 307   4 return *this; 307   4 return *this;
308   } 308   }
309   309  
310   /// Copy construction is disabled; the handle is uniquely owned. 310   /// Copy construction is disabled; the handle is uniquely owned.
311   local_stream_socket(local_stream_socket const&) = delete; 311   local_stream_socket(local_stream_socket const&) = delete;
312   /// Copy assignment is disabled; the handle is uniquely owned. 312   /// Copy assignment is disabled; the handle is uniquely owned.
313   local_stream_socket& operator=(local_stream_socket const&) = delete; 313   local_stream_socket& operator=(local_stream_socket const&) = delete;
314   314  
315   /** Open the socket. 315   /** Open the socket.
316   316  
317   Creates a Unix stream socket and associates it with 317   Creates a Unix stream socket and associates it with
318   the platform reactor. 318   the platform reactor.
319   319  
320   Failures such as descriptor exhaustion are normal runtime 320   Failures such as descriptor exhaustion are normal runtime
321   conditions and are reported through the returned error code. 321   conditions and are reported through the returned error code.
322   Opening an already-open socket is a no-op that reports 322   Opening an already-open socket is a no-op that reports
323   success. 323   success.
324   324  
325   325  
326   @return The error code, empty on success. 326   @return The error code, empty on success.
327   */ 327   */
328   [[nodiscard]] std::error_code open() noexcept; 328   [[nodiscard]] std::error_code open() noexcept;
329   329  
330   /** Close the socket. 330   /** Close the socket.
331   331  
332   Releases socket resources. Any pending operations complete 332   Releases socket resources. Any pending operations complete
333   with `errc::operation_canceled`. 333   with `errc::operation_canceled`.
334   */ 334   */
335   void close() noexcept; 335   void close() noexcept;
336   336  
337   /** Check if the socket is open. 337   /** Check if the socket is open.
338   338  
339   @return `true` if the socket is open and ready for operations. 339   @return `true` if the socket is open and ready for operations.
340   */ 340   */
HITCBC 341   1062 bool is_open() const noexcept 341   1062 bool is_open() const noexcept
342   { 342   {
343   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS) 343   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
344   return h_ && get().native_handle() != ~native_handle_type(0); 344   return h_ && get().native_handle() != ~native_handle_type(0);
345   #else 345   #else
HITCBC 346   1062 return h_ && get().native_handle() >= 0; 346   1062 return h_ && get().native_handle() >= 0;
347   #endif 347   #endif
348   } 348   }
349   349  
350   /** Initiate an asynchronous connect operation. 350   /** Initiate an asynchronous connect operation.
351   351  
352   If the socket is not already open, it is opened automatically. 352   If the socket is not already open, it is opened automatically.
353   353  
354   @param ep The local endpoint (path) to connect to. 354   @param ep The local endpoint (path) to connect to.
355   355  
356   @return An awaitable that completes with io_result<>. 356   @return An awaitable that completes with io_result<>.
357   357  
358   If the socket needs to be opened and the open fails, the 358   If the socket needs to be opened and the open fails, the
359   awaitable completes immediately with that error. 359   awaitable completes immediately with that error.
360   */ 360   */
HITCBC 361   25 [[nodiscard]] auto connect(corosio::local_endpoint ep) 361   25 [[nodiscard]] auto connect(corosio::local_endpoint ep)
362   { 362   {
HITCBC 363   25 connect_awaitable aw(*this, ep); 363   25 connect_awaitable aw(*this, ep);
HITCBC 364   25 if (!is_open()) 364   25 if (!is_open())
HITCBC 365   17 aw.ec_ = open(); 365   17 aw.ec_ = open();
HITCBC 366   25 return aw; 366   25 return aw;
367   } 367   }
368   368  
369   /** Wait for the socket to become ready in a given direction. 369   /** Wait for the socket to become ready in a given direction.
370   370  
371   Suspends until the socket is ready for the requested 371   Suspends until the socket is ready for the requested
372   direction, or an error condition is reported. No bytes 372   direction, or an error condition is reported. No bytes
373   are transferred. 373   are transferred.
374   374  
375   @param w The wait direction (read, write, or error). 375   @param w The wait direction (read, write, or error).
376   376  
377   @return An awaitable that completes with `io_result<>`. 377   @return An awaitable that completes with `io_result<>`.
378   378  
379   A closed socket completes with `errc::bad_file_descriptor`. 379   A closed socket completes with `errc::bad_file_descriptor`.
380   380  
381   @pre This socket must outlive the returned awaitable. 381   @pre This socket must outlive the returned awaitable.
382   */ 382   */
HITCBC 383   16 [[nodiscard]] auto wait(wait_type w) 383   16 [[nodiscard]] auto wait(wait_type w)
384   { 384   {
HITCBC 385   16 return wait_awaitable(*this, w); 385   16 return wait_awaitable(*this, w);
386   } 386   }
387   387  
388   /** Cancel any pending asynchronous operations. 388   /** Cancel any pending asynchronous operations.
389   389  
390   Operations still in flight complete with `errc::operation_canceled`; 390   Operations still in flight complete with `errc::operation_canceled`;
391   an operation whose result is already decided reports that result. 391   an operation whose result is already decided reports that result.
392   Check `ec == cond::canceled` for portable comparison. 392   Check `ec == cond::canceled` for portable comparison.
393   */ 393   */
394   void cancel() noexcept; 394   void cancel() noexcept;
395   395  
396   /** Get the native socket handle. 396   /** Get the native socket handle.
397   397  
398   Returns the underlying platform-specific socket descriptor. 398   Returns the underlying platform-specific socket descriptor.
399   On POSIX systems this is an `int` file descriptor. 399   On POSIX systems this is an `int` file descriptor.
400   400  
401   @return The native socket handle, or an invalid sentinel 401   @return The native socket handle, or an invalid sentinel
402   if not open. 402   if not open.
403   */ 403   */
404   native_handle_type native_handle() const noexcept; 404   native_handle_type native_handle() const noexcept;
405   405  
406   /** Query the number of bytes available for reading. 406   /** Query the number of bytes available for reading.
407   407  
408   @return The number of bytes that can be read without blocking. 408   @return The number of bytes that can be read without blocking.
409   409  
410   @throws std::system_error `errc::bad_file_descriptor` if the 410   @throws std::system_error `errc::bad_file_descriptor` if the
411   socket is not open; otherwise thrown on ioctl failure. 411   socket is not open; otherwise thrown on ioctl failure.
412   */ 412   */
413   std::size_t available() const; 413   std::size_t available() const;
414   414  
415   /** Release ownership of the native socket handle. 415   /** Release ownership of the native socket handle.
416   416  
417   Deregisters the socket from the backend and cancels pending 417   Deregisters the socket from the backend and cancels pending
418   operations without closing the descriptor. The caller takes 418   operations without closing the descriptor. The caller takes
419   ownership of the returned handle. 419   ownership of the returned handle.
420   420  
421   @return The native handle. 421   @return The native handle.
422   422  
423   @throws std::system_error `errc::bad_file_descriptor` if the 423   @throws std::system_error `errc::bad_file_descriptor` if the
424   socket is not open. 424   socket is not open.
425   425  
426   @post is_open() == false 426   @post is_open() == false
427   */ 427   */
428   native_handle_type release(); 428   native_handle_type release();
429   429  
430   /** Disable sends or receives on the socket. 430   /** Disable sends or receives on the socket.
431   431  
432   Unix stream connections are full-duplex: each direction 432   Unix stream connections are full-duplex: each direction
433   (send and receive) operates independently. This function 433   (send and receive) operates independently. This function
434   allows you to close one or both directions without 434   allows you to close one or both directions without
435   destroying the socket. 435   destroying the socket.
436   436  
437   Failures such as a peer that already disconnected are 437   Failures such as a peer that already disconnected are
438   normal runtime conditions and are reported through the 438   normal runtime conditions and are reported through the
439   returned error code. A closed socket reports 439   returned error code. A closed socket reports
440   `errc::bad_file_descriptor`. 440   `errc::bad_file_descriptor`.
441   441  
442   @param what Determines which operations are no longer 442   @param what Determines which operations are no longer
443   allowed. 443   allowed.
444   444  
445   @return The error code, empty on success. 445   @return The error code, empty on success.
446   */ 446   */
447   [[nodiscard]] std::error_code shutdown(shutdown_type what) noexcept; 447   [[nodiscard]] std::error_code shutdown(shutdown_type what) noexcept;
448   448  
449   /** Set a socket option. 449   /** Set a socket option.
450   450  
451   Applies a type-safe socket option to the underlying socket. 451   Applies a type-safe socket option to the underlying socket.
452   The option type encodes the protocol level and option name. 452   The option type encodes the protocol level and option name.
453   453  
454   @param opt The option to set. 454   @param opt The option to set.
455   455  
456   @throws std::system_error `errc::bad_file_descriptor` if the 456   @throws std::system_error `errc::bad_file_descriptor` if the
457   socket is not open; otherwise thrown on failure. 457   socket is not open; otherwise thrown on failure.
458   */ 458   */
459   template<class Option> 459   template<class Option>
HITCBC 460   14 void set_option(Option const& opt) 460   14 void set_option(Option const& opt)
461   { 461   {
HITCBC 462   14 if (!is_open()) 462   14 if (!is_open())
HITCBC 463   2 detail::throw_system_error( 463   2 detail::throw_system_error(
HITCBC 464   4 make_error_code(std::errc::bad_file_descriptor), 464   4 make_error_code(std::errc::bad_file_descriptor),
465   "local_stream_socket::set_option"); 465   "local_stream_socket::set_option");
HITCBC 466   12 auto const fam = get().family(); 466   12 auto const fam = get().family();
HITCBC 467   12 std::error_code ec = get().set_option( 467   12 std::error_code ec = get().set_option(
468   opt.level(fam), opt.name(fam), opt.data(fam), opt.size(fam)); 468   opt.level(fam), opt.name(fam), opt.data(fam), opt.size(fam));
HITCBC 469   12 if (ec) 469   12 if (ec)
HITCBC 470   2 detail::throw_system_error(ec, "local_stream_socket::set_option"); 470   2 detail::throw_system_error(ec, "local_stream_socket::set_option");
HITCBC 471   10 } 471   10 }
472   472  
473   /** Get a socket option. 473   /** Get a socket option.
474   474  
475   Retrieves the current value of a type-safe socket option. 475   Retrieves the current value of a type-safe socket option.
476   476  
477   @return The current option value. 477   @return The current option value.
478   478  
479   @throws std::system_error `errc::bad_file_descriptor` if the 479   @throws std::system_error `errc::bad_file_descriptor` if the
480   socket is not open; otherwise thrown on failure. 480   socket is not open; otherwise thrown on failure.
481   */ 481   */
482   template<class Option> 482   template<class Option>
HITCBC 483   10 Option get_option() const 483   10 Option get_option() const
484   { 484   {
HITCBC 485   10 if (!is_open()) 485   10 if (!is_open())
HITCBC 486   2 detail::throw_system_error( 486   2 detail::throw_system_error(
HITCBC 487   4 make_error_code(std::errc::bad_file_descriptor), 487   4 make_error_code(std::errc::bad_file_descriptor),
488   "local_stream_socket::get_option"); 488   "local_stream_socket::get_option");
HITCBC 489   8 Option opt{}; 489   8 Option opt{};
HITCBC 490   8 auto const fam = get().family(); 490   8 auto const fam = get().family();
HITCBC 491   8 std::size_t sz = opt.size(fam); 491   8 std::size_t sz = opt.size(fam);
492   std::error_code ec = 492   std::error_code ec =
HITCBC 493   8 get().get_option(opt.level(fam), opt.name(fam), opt.data(fam), &sz); 493   8 get().get_option(opt.level(fam), opt.name(fam), opt.data(fam), &sz);
HITCBC 494   8 if (ec) 494   8 if (ec)
HITCBC 495   2 detail::throw_system_error(ec, "local_stream_socket::get_option"); 495   2 detail::throw_system_error(ec, "local_stream_socket::get_option");
HITCBC 496   6 opt.resize(fam, sz); 496   6 opt.resize(fam, sz);
HITCBC 497   6 return opt; 497   6 return opt;
498   } 498   }
499   499  
500   /** Assign an existing native socket to this object. 500   /** Assign an existing native socket to this object.
501   501  
502   Adopts a Unix domain stream socket created outside the 502   Adopts a Unix domain stream socket created outside the
503   library — from `socketpair()`, received over `SCM_RIGHTS`, 503   library — from `socketpair()`, received over `SCM_RIGHTS`,
504   or made natively — and registers it with the backend. The 504   or made natively — and registers it with the backend. The
505   socket must be a stream socket in the `AF_UNIX` family. 505   socket must be a stream socket in the `AF_UNIX` family.
506   Adoption never alters the descriptor's flags or options: on 506   Adoption never alters the descriptor's flags or options: on
507   POSIX the fd must already be non-blocking, and on Windows 507   POSIX the fd must already be non-blocking, and on Windows
508   the socket must be overlapped-capable. 508   the socket must be overlapped-capable.
509   509  
510   The object must be closed. To replace a held socket, `close()` 510   The object must be closed. To replace a held socket, `close()`
511   or `release()` it first. 511   or `release()` it first.
512   512  
513   @par Exception Safety 513   @par Exception Safety
514   Throws nothing. On failure the object is unchanged and the 514   Throws nothing. On failure the object is unchanged and the
515   caller retains ownership of `fd`. 515   caller retains ownership of `fd`.
516   516  
517   @param fd The native socket to adopt. On success the object 517   @param fd The native socket to adopt. On success the object
518   owns it and closes it. 518   owns it and closes it.
519   519  
520   @return `error::already_open` if this object is open. 520   @return `error::already_open` if this object is open.
521   Otherwise the error code, empty on success. Validation and 521   Otherwise the error code, empty on success. Validation and
522   registration failures are normal runtime conditions when 522   registration failures are normal runtime conditions when
523   adopting foreign descriptors. 523   adopting foreign descriptors.
524   */ 524   */
525   [[nodiscard]] std::error_code assign(native_handle_type fd) noexcept; 525   [[nodiscard]] std::error_code assign(native_handle_type fd) noexcept;
526   526  
527   /** Get the local endpoint of the socket. 527   /** Get the local endpoint of the socket.
528   528  
529   Returns the local address (path) to which the socket is bound. 529   Returns the local address (path) to which the socket is bound.
530   The endpoint is cached when the connection is established. 530   The endpoint is cached when the connection is established.
531   531  
532   @return The local endpoint, or a default endpoint if the socket 532   @return The local endpoint, or a default endpoint if the socket
533   is not connected. 533   is not connected.
534   */ 534   */
535   corosio::local_endpoint local_endpoint() const noexcept; 535   corosio::local_endpoint local_endpoint() const noexcept;
536   536  
537   /** Get the remote endpoint of the socket. 537   /** Get the remote endpoint of the socket.
538   538  
539   Returns the remote address (path) to which the socket is connected. 539   Returns the remote address (path) to which the socket is connected.
540   The endpoint is cached when the connection is established. 540   The endpoint is cached when the connection is established.
541   541  
542   @return The remote endpoint, or a default endpoint if the socket 542   @return The remote endpoint, or a default endpoint if the socket
543   is not connected. 543   is not connected.
544   */ 544   */
545   corosio::local_endpoint remote_endpoint() const noexcept; 545   corosio::local_endpoint remote_endpoint() const noexcept;
546   546  
547   protected: 547   protected:
548   /// Default construct a closed socket for a derived class to open. 548   /// Default construct a closed socket for a derived class to open.
HITCBC 549   44 local_stream_socket() noexcept = default; 549   44 local_stream_socket() noexcept = default;
550   550  
551   /** Adopt an existing handle. 551   /** Adopt an existing handle.
552   552  
553   @param h The handle the socket takes ownership of. 553   @param h The handle the socket takes ownership of.
554   */ 554   */
555   explicit local_stream_socket(handle h) noexcept : io_object(std::move(h)) {} 555   explicit local_stream_socket(handle h) noexcept : io_object(std::move(h)) {}
556   556  
557   private: 557   private:
558   friend class local_stream_acceptor; 558   friend class local_stream_acceptor;
559   559  
560   [[nodiscard]] std::error_code 560   [[nodiscard]] std::error_code
561   open_for_family(int family, int type, int protocol) noexcept; 561   open_for_family(int family, int type, int protocol) noexcept;
562   562  
HITCBC 563   1166 inline implementation& get() const noexcept 563   1166 inline implementation& get() const noexcept
564   { 564   {
HITCBC 565   1166 return *static_cast<implementation*>(h_.get()); 565   1166 return *static_cast<implementation*>(h_.get());
566   } 566   }
567   }; 567   };
568   568  
569   } // namespace boost::corosio 569   } // namespace boost::corosio
570   570  
571   #endif // BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP 571   #endif // BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP