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