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   @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 : detail::void_op_base<connect_awaitable> 182 + struct connect_awaitable
  183 + : detail::void_op_base<connect_awaitable>
183   { 184   {
184   local_stream_socket& s_; 185   local_stream_socket& s_;
185   corosio::local_endpoint endpoint_; 186   corosio::local_endpoint endpoint_;
186   187  
HITCBC 187   25 connect_awaitable( 188   25 connect_awaitable(
188   local_stream_socket& s, corosio::local_endpoint ep) noexcept 189   local_stream_socket& s, corosio::local_endpoint ep) noexcept
HITCBC 189 - 50 : s_(s) 190 + 25 : s_(s), endpoint_(ep) {}
DCB 190 - 25 , endpoint_(ep)  
191 - {  
DCB 192 - 25 }  
193   191  
HITGIC 194 - std::coroutine_handle<> 192 + 25 std::coroutine_handle<> dispatch(
ECB 195 - 25 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 193 + std::coroutine_handle<> h, capy::executor_ref ex) const
196   { 194   {
HITCBC 197   25 return s_.get().connect(h, ex, endpoint_, token_, &ec_); 195   25 return s_.get().connect(h, ex, endpoint_, token_, &ec_);
198   } 196   }
199   }; 197   };
200   198  
201   /// Represent the awaitable returned by @ref wait. 199   /// Represent the awaitable returned by @ref wait.
202 - struct wait_awaitable : detail::void_op_base<wait_awaitable> 200 + struct wait_awaitable
  201 + : detail::void_op_base<wait_awaitable>
203   { 202   {
204   local_stream_socket& s_; 203   local_stream_socket& s_;
205   wait_type w_; 204   wait_type w_;
206   205  
HITCBC 207   16 wait_awaitable(local_stream_socket& s, wait_type w) noexcept 206   16 wait_awaitable(local_stream_socket& s, wait_type w) noexcept
HITCBC 208 - 32 : s_(s) 207 + 16 : s_(s), w_(w) {}
DCB 209 - 16 , w_(w)  
210 - {  
DCB 211 - 16 }  
212   208  
HITGIC 213 - std::coroutine_handle<> 209 + 16 std::coroutine_handle<> dispatch(
ECB 214 - 16 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 210 + std::coroutine_handle<> h, capy::executor_ref ex) const
215   { 211   {
HITCBC 216   16 return s_.get().wait(h, ex, w_, token_, &ec_); 212   16 return s_.get().wait(h, ex, w_, token_, &ec_);
217   } 213   }
218   }; 214   };
219   215  
220   public: 216   public:
221   /** Destructor. 217   /** Destructor.
222   218  
223   Closes the socket if open, cancelling any pending operations. 219   Closes the socket if open, cancelling any pending operations.
224   */ 220   */
225   ~local_stream_socket() override; 221   ~local_stream_socket() override;
226   222  
227   /** Construct a socket from an execution context. 223   /** Construct a socket from an execution context.
228   224  
229   @param ctx The execution context that will own this socket. 225   @param ctx The execution context that will own this socket.
230   */ 226   */
231   explicit local_stream_socket(capy::execution_context& ctx); 227   explicit local_stream_socket(capy::execution_context& ctx);
232   228  
233   /** Construct a socket from an executor. 229   /** Construct a socket from an executor.
234   230  
235   The socket is associated with the executor's context. 231   The socket is associated with the executor's context.
236   232  
237   @param ex The executor whose context will own the socket. 233   @param ex The executor whose context will own the socket.
238   */ 234   */
239   template<class Ex> 235   template<class Ex>
240   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>) &&
241   capy::Executor<Ex> 237   capy::Executor<Ex>
242 - explicit local_stream_socket(Ex const& ex) 238 + explicit local_stream_socket(Ex const& ex) : local_stream_socket(ex.context())
243 - : local_stream_socket(ex.context())  
244   { 239   {
245   } 240   }
246   241  
247   /** Move constructor. 242   /** Move constructor.
248   243  
249   Transfers ownership of the socket resources. 244   Transfers ownership of the socket resources.
250   245  
251   @param other The socket to move from. 246   @param other The socket to move from.
252   247  
253   @pre No awaitables returned by @p other's methods exist. 248   @pre No awaitables returned by @p other's methods exist.
254   @pre The execution context associated with @p other must 249   @pre The execution context associated with @p other must
255   outlive this socket. 250   outlive this socket.
256   */ 251   */
HITCBC 257   14 local_stream_socket(local_stream_socket&& other) noexcept 252   14 local_stream_socket(local_stream_socket&& other) noexcept
HITCBC 258   14 : io_object(std::move(other)) 253   14 : io_object(std::move(other))
259   { 254   {
HITCBC 260   14 } 255   14 }
261   256  
262   /** Move assignment operator. 257   /** Move assignment operator.
263   258  
264   Closes any existing socket and transfers ownership. 259   Closes any existing socket and transfers ownership.
265   260  
266   @param other The socket to move from. 261   @param other The socket to move from.
267   262  
268   @pre No awaitables returned by either `*this` or @p other's 263   @pre No awaitables returned by either `*this` or @p other's
269   methods exist. 264   methods exist.
270   @pre The execution context associated with @p other must 265   @pre The execution context associated with @p other must
271   outlive this socket. 266   outlive this socket.
272   267  
273   @return Reference to this socket. 268   @return Reference to this socket.
274   */ 269   */
HITCBC 275   4 local_stream_socket& operator=(local_stream_socket&& other) noexcept 270   4 local_stream_socket& operator=(local_stream_socket&& other) noexcept
276   { 271   {
HITCBC 277   4 if (this != &other) 272   4 if (this != &other)
278   { 273   {
HITCBC 279   2 close(); 274   2 close();
HITCBC 280   2 io_object::operator=(std::move(other)); 275   2 io_object::operator=(std::move(other));
281   } 276   }
HITCBC 282   4 return *this; 277   4 return *this;
283   } 278   }
284   279  
285   local_stream_socket(local_stream_socket const&) = delete; 280   local_stream_socket(local_stream_socket const&) = delete;
286   local_stream_socket& operator=(local_stream_socket const&) = delete; 281   local_stream_socket& operator=(local_stream_socket const&) = delete;
287   282  
288   /** Open the socket. 283   /** Open the socket.
289   284  
290   Creates a Unix stream socket and associates it with 285   Creates a Unix stream socket and associates it with
291   the platform reactor. 286   the platform reactor.
292   287  
293   Failures such as descriptor exhaustion are normal runtime 288   Failures such as descriptor exhaustion are normal runtime
294   conditions and are reported through the returned error code. 289   conditions and are reported through the returned error code.
295   Opening an already-open socket is a no-op that reports 290   Opening an already-open socket is a no-op that reports
296   success. 291   success.
297   292  
298   @param proto The protocol. Defaults to local_stream{}. 293   @param proto The protocol. Defaults to local_stream{}.
299   294  
300   @return The error code, empty on success. 295   @return The error code, empty on success.
301   */ 296   */
302   [[nodiscard]] std::error_code open(local_stream proto = {}) noexcept; 297   [[nodiscard]] std::error_code open(local_stream proto = {}) noexcept;
303   298  
304   /** Close the socket. 299   /** Close the socket.
305   300  
306   Releases socket resources. Any pending operations complete 301   Releases socket resources. Any pending operations complete
307   with `errc::operation_canceled`. 302   with `errc::operation_canceled`.
308   */ 303   */
309   void close() noexcept; 304   void close() noexcept;
310   305  
311   /** Check if the socket is open. 306   /** Check if the socket is open.
312   307  
313   @return `true` if the socket is open and ready for operations. 308   @return `true` if the socket is open and ready for operations.
314   */ 309   */
HITCBC 315   869 bool is_open() const noexcept 310   869 bool is_open() const noexcept
316   { 311   {
317   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS) 312   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
318   return h_ && get().native_handle() != ~native_handle_type(0); 313   return h_ && get().native_handle() != ~native_handle_type(0);
319   #else 314   #else
HITCBC 320   869 return h_ && get().native_handle() >= 0; 315   869 return h_ && get().native_handle() >= 0;
321   #endif 316   #endif
322   } 317   }
323   318  
324   /** Initiate an asynchronous connect operation. 319   /** Initiate an asynchronous connect operation.
325   320  
326   If the socket is not already open, it is opened automatically. 321   If the socket is not already open, it is opened automatically.
327   322  
328   @param ep The local endpoint (path) to connect to. 323   @param ep The local endpoint (path) to connect to.
329   324  
330   @return An awaitable that completes with io_result<>. 325   @return An awaitable that completes with io_result<>.
331   326  
332   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
333   awaitable completes immediately with that error. 328   awaitable completes immediately with that error.
334   */ 329   */
HITCBC 335   25 [[nodiscard]] auto connect(corosio::local_endpoint ep) 330   25 [[nodiscard]] auto connect(corosio::local_endpoint ep)
336   { 331   {
HITCBC 337   25 connect_awaitable aw(*this, ep); 332   25 connect_awaitable aw(*this, ep);
HITCBC 338   25 if (!is_open()) 333   25 if (!is_open())
HITCBC 339   17 aw.ec_ = open(); 334   17 aw.ec_ = open();
HITCBC 340   25 return aw; 335   25 return aw;
341   } 336   }
342   337  
343   /** Wait for the socket to become ready in a given direction. 338   /** Wait for the socket to become ready in a given direction.
344   339  
345   Suspends until the socket is ready for the requested 340   Suspends until the socket is ready for the requested
346   direction, or an error condition is reported. No bytes 341   direction, or an error condition is reported. No bytes
347   are transferred. 342   are transferred.
348   343  
349   @param w The wait direction (read, write, or error). 344   @param w The wait direction (read, write, or error).
350   345  
351   @return An awaitable that completes with `io_result<>`. 346   @return An awaitable that completes with `io_result<>`.
352   347  
353   A closed socket completes with `errc::bad_file_descriptor`. 348   A closed socket completes with `errc::bad_file_descriptor`.
354   349  
355   @par Preconditions 350   @par Preconditions
356   This socket must outlive the returned awaitable. 351   This socket must outlive the returned awaitable.
357   */ 352   */
HITCBC 358   16 [[nodiscard]] auto wait(wait_type w) 353   16 [[nodiscard]] auto wait(wait_type w)
359   { 354   {
HITCBC 360   16 return wait_awaitable(*this, w); 355   16 return wait_awaitable(*this, w);
361   } 356   }
362   357  
363   /** Cancel any pending asynchronous operations. 358   /** Cancel any pending asynchronous operations.
364   359  
365   All outstanding operations complete with `errc::operation_canceled`. 360   All outstanding operations complete with `errc::operation_canceled`.
366   Check `ec == cond::canceled` for portable comparison. 361   Check `ec == cond::canceled` for portable comparison.
367   */ 362   */
368   void cancel() noexcept; 363   void cancel() noexcept;
369   364  
370   /** Get the native socket handle. 365   /** Get the native socket handle.
371   366  
372   Returns the underlying platform-specific socket descriptor. 367   Returns the underlying platform-specific socket descriptor.
373   On POSIX systems this is an `int` file descriptor. 368   On POSIX systems this is an `int` file descriptor.
374   369  
375   @return The native socket handle, or an invalid sentinel 370   @return The native socket handle, or an invalid sentinel
376   if not open. 371   if not open.
377   */ 372   */
378   native_handle_type native_handle() const noexcept; 373   native_handle_type native_handle() const noexcept;
379   374  
380   /** Query the number of bytes available for reading. 375   /** Query the number of bytes available for reading.
381   376  
382   @return The number of bytes that can be read without blocking. 377   @return The number of bytes that can be read without blocking.
383   378  
384   @throws std::system_error `errc::bad_file_descriptor` if the 379   @throws std::system_error `errc::bad_file_descriptor` if the
385   socket is not open; otherwise thrown on ioctl failure. 380   socket is not open; otherwise thrown on ioctl failure.
386   */ 381   */
387   std::size_t available() const; 382   std::size_t available() const;
388   383  
389   /** Release ownership of the native socket handle. 384   /** Release ownership of the native socket handle.
390   385  
391   Deregisters the socket from the backend and cancels pending 386   Deregisters the socket from the backend and cancels pending
392   operations without closing the descriptor. The caller takes 387   operations without closing the descriptor. The caller takes
393   ownership of the returned handle. 388   ownership of the returned handle.
394   389  
395   @return The native handle. 390   @return The native handle.
396   391  
397   @throws std::system_error `errc::bad_file_descriptor` if the 392   @throws std::system_error `errc::bad_file_descriptor` if the
398   socket is not open. 393   socket is not open.
399   394  
400   @post is_open() == false 395   @post is_open() == false
401   */ 396   */
402   native_handle_type release(); 397   native_handle_type release();
403   398  
404   /** Disable sends or receives on the socket. 399   /** Disable sends or receives on the socket.
405   400  
406   Unix stream connections are full-duplex: each direction 401   Unix stream connections are full-duplex: each direction
407   (send and receive) operates independently. This function 402   (send and receive) operates independently. This function
408   allows you to close one or both directions without 403   allows you to close one or both directions without
409   destroying the socket. 404   destroying the socket.
410   405  
411   Failures such as a peer that already disconnected are 406   Failures such as a peer that already disconnected are
412   normal runtime conditions and are reported through the 407   normal runtime conditions and are reported through the
413   returned error code. A closed socket reports 408   returned error code. A closed socket reports
414   `errc::bad_file_descriptor`. 409   `errc::bad_file_descriptor`.
415   410  
416   @param what Determines what operations will no longer 411   @param what Determines what operations will no longer
417   be allowed. 412   be allowed.
418   413  
419   @return The error code, empty on success. 414   @return The error code, empty on success.
420   */ 415   */
421   [[nodiscard]] std::error_code shutdown(shutdown_type what) noexcept; 416   [[nodiscard]] std::error_code shutdown(shutdown_type what) noexcept;
422   417  
423   /** Set a socket option. 418   /** Set a socket option.
424   419  
425   Applies a type-safe socket option to the underlying socket. 420   Applies a type-safe socket option to the underlying socket.
426   The option type encodes the protocol level and option name. 421   The option type encodes the protocol level and option name.
427   422  
428   @param opt The option to set. 423   @param opt The option to set.
429   424  
430   @throws std::system_error `errc::bad_file_descriptor` if the 425   @throws std::system_error `errc::bad_file_descriptor` if the
431   socket is not open; otherwise thrown on failure. 426   socket is not open; otherwise thrown on failure.
432   */ 427   */
433   template<class Option> 428   template<class Option>
HITCBC 434   14 void set_option(Option const& opt) 429   14 void set_option(Option const& opt)
435   { 430   {
HITCBC 436   14 if (!is_open()) 431   14 if (!is_open())
HITCBC 437   2 detail::throw_system_error( 432   2 detail::throw_system_error(
HITCBC 438   4 make_error_code(std::errc::bad_file_descriptor), 433   4 make_error_code(std::errc::bad_file_descriptor),
439   "local_stream_socket::set_option"); 434   "local_stream_socket::set_option");
HITCBC 440   12 std::error_code ec = get().set_option( 435   12 std::error_code ec = get().set_option(
441   Option::level(), Option::name(), opt.data(), opt.size()); 436   Option::level(), Option::name(), opt.data(), opt.size());
HITCBC 442   12 if (ec) 437   12 if (ec)
HITCBC 443   2 detail::throw_system_error(ec, "local_stream_socket::set_option"); 438   2 detail::throw_system_error(ec, "local_stream_socket::set_option");
HITCBC 444   10 } 439   10 }
445   440  
446   /** Get a socket option. 441   /** Get a socket option.
447   442  
448   Retrieves the current value of a type-safe socket option. 443   Retrieves the current value of a type-safe socket option.
449   444  
450   @return The current option value. 445   @return The current option value.
451   446  
452   @throws std::system_error `errc::bad_file_descriptor` if the 447   @throws std::system_error `errc::bad_file_descriptor` if the
453   socket is not open; otherwise thrown on failure. 448   socket is not open; otherwise thrown on failure.
454   */ 449   */
455   template<class Option> 450   template<class Option>
HITCBC 456   10 Option get_option() const 451   10 Option get_option() const
457   { 452   {
HITCBC 458   10 if (!is_open()) 453   10 if (!is_open())
HITCBC 459   2 detail::throw_system_error( 454   2 detail::throw_system_error(
HITCBC 460   4 make_error_code(std::errc::bad_file_descriptor), 455   4 make_error_code(std::errc::bad_file_descriptor),
461   "local_stream_socket::get_option"); 456   "local_stream_socket::get_option");
HITCBC 462   8 Option opt{}; 457   8 Option opt{};
HITCBC 463   8 std::size_t sz = opt.size(); 458   8 std::size_t sz = opt.size();
464   std::error_code ec = 459   std::error_code ec =
HITCBC 465   8 get().get_option(Option::level(), Option::name(), opt.data(), &sz); 460   8 get().get_option(Option::level(), Option::name(), opt.data(), &sz);
HITCBC 466   8 if (ec) 461   8 if (ec)
HITCBC 467   2 detail::throw_system_error(ec, "local_stream_socket::get_option"); 462   2 detail::throw_system_error(ec, "local_stream_socket::get_option");
HITCBC 468   6 opt.resize(sz); 463   6 opt.resize(sz);
HITCBC 469   6 return opt; 464   6 return opt;
470   } 465   }
471   466  
472   /** Assign an existing native socket to this object. 467   /** Assign an existing native socket to this object.
473   468  
474   Adopts a Unix domain stream socket created outside the 469   Adopts a Unix domain stream socket created outside the
475   library — from `socketpair()`, received over `SCM_RIGHTS`, 470   library — from `socketpair()`, received over `SCM_RIGHTS`,
476   or made natively — and registers it with the backend. The 471   or made natively — and registers it with the backend. The
477   socket must be a stream socket in the `AF_UNIX` family. 472   socket must be a stream socket in the `AF_UNIX` family.
478   Adoption never alters the descriptor's flags or options: on 473   Adoption never alters the descriptor's flags or options: on
479   POSIX the fd must already be non-blocking, and on Windows 474   POSIX the fd must already be non-blocking, and on Windows
480   the socket must be overlapped-capable. 475   the socket must be overlapped-capable.
481   476  
482   If this object is already open, pending operations complete 477   If this object is already open, pending operations complete
483   with `errc::operation_canceled` and the held socket is 478   with `errc::operation_canceled` and the held socket is
484   closed before the new one is adopted. 479   closed before the new one is adopted.
485   480  
486   @par Exception Safety 481   @par Exception Safety
487   Strong guarantee on validation failure: the object is 482   Strong guarantee on validation failure: the object is
488   unchanged. If backend registration fails, the object either 483   unchanged. If backend registration fails, the object either
489   retains its previous socket or is left closed, depending on 484   retains its previous socket or is left closed, depending on
490   the backend. In all failure cases the caller retains 485   the backend. In all failure cases the caller retains
491   ownership of `fd`. 486   ownership of `fd`.
492   487  
493   @param fd The native socket to adopt. On success the object 488   @param fd The native socket to adopt. On success the object
494   owns it and will close it. 489   owns it and will close it.
495   490  
496   @return The error code, empty on success. Validation and 491   @return The error code, empty on success. Validation and
497   registration failures are normal runtime conditions when 492   registration failures are normal runtime conditions when
498   adopting foreign descriptors. 493   adopting foreign descriptors.
499   */ 494   */
500   [[nodiscard]] std::error_code assign(native_handle_type fd) noexcept; 495   [[nodiscard]] std::error_code assign(native_handle_type fd) noexcept;
501   496  
502   /** Get the local endpoint of the socket. 497   /** Get the local endpoint of the socket.
503   498  
504   Returns the local address (path) to which the socket is bound. 499   Returns the local address (path) to which the socket is bound.
505   The endpoint is cached when the connection is established. 500   The endpoint is cached when the connection is established.
506   501  
507   @return The local endpoint, or a default endpoint if the socket 502   @return The local endpoint, or a default endpoint if the socket
508   is not connected. 503   is not connected.
509   */ 504   */
510   corosio::local_endpoint local_endpoint() const noexcept; 505   corosio::local_endpoint local_endpoint() const noexcept;
511   506  
512   /** Get the remote endpoint of the socket. 507   /** Get the remote endpoint of the socket.
513   508  
514   Returns the remote address (path) to which the socket is connected. 509   Returns the remote address (path) to which the socket is connected.
515   The endpoint is cached when the connection is established. 510   The endpoint is cached when the connection is established.
516   511  
517   @return The remote endpoint, or a default endpoint if the socket 512   @return The remote endpoint, or a default endpoint if the socket
518   is not connected. 513   is not connected.
519   */ 514   */
520   corosio::local_endpoint remote_endpoint() const noexcept; 515   corosio::local_endpoint remote_endpoint() const noexcept;
521   516  
522   protected: 517   protected:
HITCBC 523   44 local_stream_socket() noexcept = default; 518   44 local_stream_socket() noexcept = default;
524   519  
525   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)) {}
526   521  
527   private: 522   private:
528   friend class local_stream_acceptor; 523   friend class local_stream_acceptor;
529   524  
530   [[nodiscard]] std::error_code 525   [[nodiscard]] std::error_code
531   open_for_family(int family, int type, int protocol) noexcept; 526   open_for_family(int family, int type, int protocol) noexcept;
532   527  
HITCBC 533   951 inline implementation& get() const noexcept 528   951 inline implementation& get() const noexcept
534   { 529   {
HITCBC 535   951 return *static_cast<implementation*>(h_.get()); 530   951 return *static_cast<implementation*>(h_.get());
536   } 531   }
537   }; 532   };
538   533  
539   } // namespace boost::corosio 534   } // namespace boost::corosio
540   535  
541   #endif // BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP 536   #endif // BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP