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