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