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