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