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