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