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 -
    /// The endpoint type used by this socket.
 
80 -
    using endpoint_type = corosio::local_endpoint;
 
81 -

 
82  
public:
79  
public:
83  
    using shutdown_type = corosio::shutdown_type;
80  
    using shutdown_type = corosio::shutdown_type;
84  
    using enum corosio::shutdown_type;
81  
    using enum corosio::shutdown_type;
85  

82  

86  
    /** Define backend hooks for local stream socket operations.
83  
    /** Define backend hooks for local stream socket operations.
87  

84  

88  
        Platform backends (epoll, kqueue, select) derive from this
85  
        Platform backends (epoll, kqueue, select) derive from this
89  
        to implement socket I/O, connection, and option management.
86  
        to implement socket I/O, connection, and option management.
90  
    */
87  
    */
91  
    struct implementation : io_stream::implementation
88  
    struct implementation : io_stream::implementation
92  
    {
89  
    {
93  
        /** Initiate an asynchronous connect to the given endpoint.
90  
        /** Initiate an asynchronous connect to the given endpoint.
94  

91  

95  
            @param h Coroutine handle to resume on completion.
92  
            @param h Coroutine handle to resume on completion.
96  
            @param ex Executor for dispatching the completion.
93  
            @param ex Executor for dispatching the completion.
97  
            @param ep The local endpoint (path) to connect to.
94  
            @param ep The local endpoint (path) to connect to.
98  
            @param token Stop token for cancellation.
95  
            @param token Stop token for cancellation.
99  
            @param ec Output error code.
96  
            @param ec Output error code.
100  

97  

101  
            @return Coroutine handle to resume immediately.
98  
            @return Coroutine handle to resume immediately.
102  
        */
99  
        */
103  
        virtual std::coroutine_handle<> connect(
100  
        virtual std::coroutine_handle<> connect(
104  
            std::coroutine_handle<> h,
101  
            std::coroutine_handle<> h,
105  
            capy::executor_ref ex,
102  
            capy::executor_ref ex,
106  
            corosio::local_endpoint ep,
103  
            corosio::local_endpoint ep,
107  
            std::stop_token token,
104  
            std::stop_token token,
108  
            std::error_code* ec) = 0;
105  
            std::error_code* ec) = 0;
109  

106  

110  
        /** Shut down the socket for the given direction(s).
107  
        /** Shut down the socket for the given direction(s).
111  

108  

112  
            @param what The shutdown direction.
109  
            @param what The shutdown direction.
113  

110  

114  
            @return Error code on failure, empty on success.
111  
            @return Error code on failure, empty on success.
115  
        */
112  
        */
116  
        virtual std::error_code shutdown(shutdown_type what) noexcept = 0;
113  
        virtual std::error_code shutdown(shutdown_type what) noexcept = 0;
117  

114  

118  
        /// Return the platform socket descriptor.
115  
        /// Return the platform socket descriptor.
119  
        virtual native_handle_type native_handle() const noexcept = 0;
116  
        virtual native_handle_type native_handle() const noexcept = 0;
120  

117  

121  
        /** Release ownership of the native socket handle.
118  
        /** Release ownership of the native socket handle.
122  

119  

123  
            Deregisters the socket from the reactor without closing
120  
            Deregisters the socket from the reactor without closing
124  
            the descriptor. The caller takes ownership.
121  
            the descriptor. The caller takes ownership.
125  

122  

126  
            @return The native handle.
123  
            @return The native handle.
127  
        */
124  
        */
128  
        virtual native_handle_type release_socket() noexcept = 0;
125  
        virtual native_handle_type release_socket() noexcept = 0;
129  

126  

130  
        /** Request cancellation of pending asynchronous operations.
127  
        /** Request cancellation of pending asynchronous operations.
131  

128  

132  
            All outstanding operations complete with operation_canceled error.
129  
            All outstanding operations complete with operation_canceled error.
133  
            Check `ec == cond::canceled` for portable comparison.
130  
            Check `ec == cond::canceled` for portable comparison.
134  
        */
131  
        */
135  
        virtual void cancel() noexcept = 0;
132  
        virtual void cancel() noexcept = 0;
136  

133  

137  
        /** Set a socket option.
134  
        /** Set a socket option.
138  

135  

139  
            @param level The protocol level (e.g. `SOL_SOCKET`).
136  
            @param level The protocol level (e.g. `SOL_SOCKET`).
140  
            @param optname The option name (e.g. `SO_KEEPALIVE`).
137  
            @param optname The option name (e.g. `SO_KEEPALIVE`).
141  
            @param data Pointer to the option value.
138  
            @param data Pointer to the option value.
142  
            @param size Size of the option value in bytes.
139  
            @param size Size of the option value in bytes.
143  
            @return Error code on failure, empty on success.
140  
            @return Error code on failure, empty on success.
144  
        */
141  
        */
145  
        virtual std::error_code set_option(
142  
        virtual std::error_code set_option(
146  
            int level,
143  
            int level,
147  
            int optname,
144  
            int optname,
148  
            void const* data,
145  
            void const* data,
149  
            std::size_t size) noexcept = 0;
146  
            std::size_t size) noexcept = 0;
150  

147  

151  
        /** Get a socket option.
148  
        /** Get a socket option.
152  

149  

153  
            @param level The protocol level (e.g. `SOL_SOCKET`).
150  
            @param level The protocol level (e.g. `SOL_SOCKET`).
154  
            @param optname The option name (e.g. `SO_KEEPALIVE`).
151  
            @param optname The option name (e.g. `SO_KEEPALIVE`).
155  
            @param data Pointer to receive the option value.
152  
            @param data Pointer to receive the option value.
156  
            @param size On entry, the size of the buffer. On exit,
153  
            @param size On entry, the size of the buffer. On exit,
157  
                the size of the option value.
154  
                the size of the option value.
158  
            @return Error code on failure, empty on success.
155  
            @return Error code on failure, empty on success.
159  
        */
156  
        */
160  
        virtual std::error_code
157  
        virtual std::error_code
161  
        get_option(int level, int optname, void* data, std::size_t* size)
158  
        get_option(int level, int optname, void* data, std::size_t* size)
162  
            const noexcept = 0;
159  
            const noexcept = 0;
163  

160  

164  
        /// Return the cached local endpoint.
161  
        /// Return the cached local endpoint.
165  
        virtual corosio::local_endpoint local_endpoint() const noexcept = 0;
162  
        virtual corosio::local_endpoint local_endpoint() const noexcept = 0;
166  

163  

167  
        /// Return the cached remote endpoint.
164  
        /// Return the cached remote endpoint.
168  
        virtual corosio::local_endpoint remote_endpoint() const noexcept = 0;
165  
        virtual corosio::local_endpoint remote_endpoint() const noexcept = 0;
169  
    };
166  
    };
170  

167  

171  
    /// Represent the awaitable returned by @ref connect.
168  
    /// Represent the awaitable returned by @ref connect.
172  
    struct connect_awaitable
169  
    struct connect_awaitable
173  
        : detail::void_op_base<connect_awaitable>
170  
        : detail::void_op_base<connect_awaitable>
174  
    {
171  
    {
175  
        local_stream_socket& s_;
172  
        local_stream_socket& s_;
176  
        corosio::local_endpoint endpoint_;
173  
        corosio::local_endpoint endpoint_;
177  

174  

178  
        connect_awaitable(
175  
        connect_awaitable(
179  
            local_stream_socket& s, corosio::local_endpoint ep) noexcept
176  
            local_stream_socket& s, corosio::local_endpoint ep) noexcept
180  
            : s_(s), endpoint_(ep) {}
177  
            : s_(s), endpoint_(ep) {}
181  

178  

182  
        std::coroutine_handle<> dispatch(
179  
        std::coroutine_handle<> dispatch(
183  
            std::coroutine_handle<> h, capy::executor_ref ex) const
180  
            std::coroutine_handle<> h, capy::executor_ref ex) const
184  
        {
181  
        {
185  
            return s_.get().connect(h, ex, endpoint_, token_, &ec_);
182  
            return s_.get().connect(h, ex, endpoint_, token_, &ec_);
186  
        }
183  
        }
187  
    };
184  
    };
188  

185  

189  
public:
186  
public:
190  
    /** Destructor.
187  
    /** Destructor.
191  

188  

192  
        Closes the socket if open, cancelling any pending operations.
189  
        Closes the socket if open, cancelling any pending operations.
193  
    */
190  
    */
194  
    ~local_stream_socket() override;
191  
    ~local_stream_socket() override;
195  

192  

196  
    /** Construct a socket from an execution context.
193  
    /** Construct a socket from an execution context.
197  

194  

198  
        @param ctx The execution context that will own this socket.
195  
        @param ctx The execution context that will own this socket.
199  
    */
196  
    */
200  
    explicit local_stream_socket(capy::execution_context& ctx);
197  
    explicit local_stream_socket(capy::execution_context& ctx);
201  

198  

202  
    /** Construct a socket from an executor.
199  
    /** Construct a socket from an executor.
203  

200  

204  
        The socket is associated with the executor's context.
201  
        The socket is associated with the executor's context.
205  

202  

206  
        @param ex The executor whose context will own the socket.
203  
        @param ex The executor whose context will own the socket.
207  
    */
204  
    */
208  
    template<class Ex>
205  
    template<class Ex>
209  
        requires(!std::same_as<std::remove_cvref_t<Ex>, local_stream_socket>) &&
206  
        requires(!std::same_as<std::remove_cvref_t<Ex>, local_stream_socket>) &&
210  
        capy::Executor<Ex>
207  
        capy::Executor<Ex>
211  
    explicit local_stream_socket(Ex const& ex) : local_stream_socket(ex.context())
208  
    explicit local_stream_socket(Ex const& ex) : local_stream_socket(ex.context())
212  
    {
209  
    {
213  
    }
210  
    }
214  

211  

215  
    /** Move constructor.
212  
    /** Move constructor.
216  

213  

217  
        Transfers ownership of the socket resources.
214  
        Transfers ownership of the socket resources.
218  

215  

219  
        @param other The socket to move from.
216  
        @param other The socket to move from.
220  

217  

221  
        @pre No awaitables returned by @p other's methods exist.
218  
        @pre No awaitables returned by @p other's methods exist.
222  
        @pre The execution context associated with @p other must
219  
        @pre The execution context associated with @p other must
223  
            outlive this socket.
220  
            outlive this socket.
224  
    */
221  
    */
225  
    local_stream_socket(local_stream_socket&& other) noexcept
222  
    local_stream_socket(local_stream_socket&& other) noexcept
226  
        : io_object(std::move(other))
223  
        : io_object(std::move(other))
227  
    {
224  
    {
228  
    }
225  
    }
229  

226  

230  
    /** Move assignment operator.
227  
    /** Move assignment operator.
231  

228  

232  
        Closes any existing socket and transfers ownership.
229  
        Closes any existing socket and transfers ownership.
233  

230  

234  
        @param other The socket to move from.
231  
        @param other The socket to move from.
235  

232  

236  
        @pre No awaitables returned by either `*this` or @p other's
233  
        @pre No awaitables returned by either `*this` or @p other's
237  
            methods exist.
234  
            methods exist.
238  
        @pre The execution context associated with @p other must
235  
        @pre The execution context associated with @p other must
239  
            outlive this socket.
236  
            outlive this socket.
240  

237  

241  
        @return Reference to this socket.
238  
        @return Reference to this socket.
242  
    */
239  
    */
243  
    local_stream_socket& operator=(local_stream_socket&& other) noexcept
240  
    local_stream_socket& operator=(local_stream_socket&& other) noexcept
244  
    {
241  
    {
245  
        if (this != &other)
242  
        if (this != &other)
246  
        {
243  
        {
247  
            close();
244  
            close();
248  
            io_object::operator=(std::move(other));
245  
            io_object::operator=(std::move(other));
249  
        }
246  
        }
250  
        return *this;
247  
        return *this;
251  
    }
248  
    }
252  

249  

253  
    local_stream_socket(local_stream_socket const&)            = delete;
250  
    local_stream_socket(local_stream_socket const&)            = delete;
254  
    local_stream_socket& operator=(local_stream_socket const&) = delete;
251  
    local_stream_socket& operator=(local_stream_socket const&) = delete;
255  

252  

256  
    /** Open the socket.
253  
    /** Open the socket.
257  

254  

258  
        Creates a Unix stream socket and associates it with
255  
        Creates a Unix stream socket and associates it with
259  
        the platform reactor.
256  
        the platform reactor.
260  

257  

261  
        @param proto The protocol. Defaults to local_stream{}.
258  
        @param proto The protocol. Defaults to local_stream{}.
262  

259  

263  
        @throws std::system_error on failure.
260  
        @throws std::system_error on failure.
264  
    */
261  
    */
265  
    void open(local_stream proto = {});
262  
    void open(local_stream proto = {});
266  

263  

267  
    /** Close the socket.
264  
    /** Close the socket.
268  

265  

269  
        Releases socket resources. Any pending operations complete
266  
        Releases socket resources. Any pending operations complete
270  
        with `errc::operation_canceled`.
267  
        with `errc::operation_canceled`.
271  
    */
268  
    */
272  
    void close();
269  
    void close();
273  

270  

274  
    /** Check if the socket is open.
271  
    /** Check if the socket is open.
275  

272  

276  
        @return `true` if the socket is open and ready for operations.
273  
        @return `true` if the socket is open and ready for operations.
277  
    */
274  
    */
278  
    bool is_open() const noexcept
275  
    bool is_open() const noexcept
279  
    {
276  
    {
280  
#if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
277  
#if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
281  
        return h_ && get().native_handle() != ~native_handle_type(0);
278  
        return h_ && get().native_handle() != ~native_handle_type(0);
282  
#else
279  
#else
283  
        return h_ && get().native_handle() >= 0;
280  
        return h_ && get().native_handle() >= 0;
284  
#endif
281  
#endif
285  
    }
282  
    }
286  

283  

287  
    /** Initiate an asynchronous connect operation.
284  
    /** Initiate an asynchronous connect operation.
288  

285  

289  
        If the socket is not already open, it is opened automatically.
286  
        If the socket is not already open, it is opened automatically.
290  

287  

291  
        @param ep The local endpoint (path) to connect to.
288  
        @param ep The local endpoint (path) to connect to.
292  

289  

293  
        @return An awaitable that completes with io_result<>.
290  
        @return An awaitable that completes with io_result<>.
294  

291  

295  
        @throws std::system_error if the socket needs to be opened
292  
        @throws std::system_error if the socket needs to be opened
296  
            and the open fails.
293  
            and the open fails.
297  
    */
294  
    */
298  
    auto connect(corosio::local_endpoint ep)
295  
    auto connect(corosio::local_endpoint ep)
299  
    {
296  
    {
300  
        if (!is_open())
297  
        if (!is_open())
301  
            open();
298  
            open();
302  
        return connect_awaitable(*this, ep);
299  
        return connect_awaitable(*this, ep);
303  
    }
300  
    }
304  

301  

305  
    /** Cancel any pending asynchronous operations.
302  
    /** Cancel any pending asynchronous operations.
306  

303  

307  
        All outstanding operations complete with `errc::operation_canceled`.
304  
        All outstanding operations complete with `errc::operation_canceled`.
308  
        Check `ec == cond::canceled` for portable comparison.
305  
        Check `ec == cond::canceled` for portable comparison.
309  
    */
306  
    */
310  
    void cancel();
307  
    void cancel();
311  

308  

312  
    /** Get the native socket handle.
309  
    /** Get the native socket handle.
313  

310  

314  
        Returns the underlying platform-specific socket descriptor.
311  
        Returns the underlying platform-specific socket descriptor.
315  
        On POSIX systems this is an `int` file descriptor.
312  
        On POSIX systems this is an `int` file descriptor.
316  

313  

317  
        @return The native socket handle, or an invalid sentinel
314  
        @return The native socket handle, or an invalid sentinel
318  
            if not open.
315  
            if not open.
319  
    */
316  
    */
320  
    native_handle_type native_handle() const noexcept;
317  
    native_handle_type native_handle() const noexcept;
321  

318  

322  
    /** Query the number of bytes available for reading.
319  
    /** Query the number of bytes available for reading.
323  

320  

324  
        @return The number of bytes that can be read without blocking.
321  
        @return The number of bytes that can be read without blocking.
325  

322  

326  
        @throws std::logic_error if the socket is not open.
323  
        @throws std::logic_error if the socket is not open.
327  
        @throws std::system_error on ioctl failure.
324  
        @throws std::system_error on ioctl failure.
328  
    */
325  
    */
329  
    std::size_t available() const;
326  
    std::size_t available() const;
330  

327  

331  
    /** Release ownership of the native socket handle.
328  
    /** Release ownership of the native socket handle.
332  

329  

333  
        Deregisters the socket from the backend and cancels pending
330  
        Deregisters the socket from the backend and cancels pending
334  
        operations without closing the descriptor. The caller takes
331  
        operations without closing the descriptor. The caller takes
335  
        ownership of the returned handle.
332  
        ownership of the returned handle.
336  

333  

337  
        @return The native handle.
334  
        @return The native handle.
338  

335  

339  
        @throws std::logic_error if the socket is not open.
336  
        @throws std::logic_error if the socket is not open.
340  

337  

341  
        @post is_open() == false
338  
        @post is_open() == false
342  
    */
339  
    */
343  
    native_handle_type release();
340  
    native_handle_type release();
344  

341  

345  
    /** Disable sends or receives on the socket.
342  
    /** Disable sends or receives on the socket.
346  

343  

347  
        Unix stream connections are full-duplex: each direction
344  
        Unix stream connections are full-duplex: each direction
348  
        (send and receive) operates independently. This function
345  
        (send and receive) operates independently. This function
349  
        allows you to close one or both directions without
346  
        allows you to close one or both directions without
350  
        destroying the socket.
347  
        destroying the socket.
351  

348  

352  
        @param what Determines what operations will no longer
349  
        @param what Determines what operations will no longer
353  
            be allowed.
350  
            be allowed.
354  

351  

355  
        @throws std::system_error on failure.
352  
        @throws std::system_error on failure.
356  
    */
353  
    */
357  
    void shutdown(shutdown_type what);
354  
    void shutdown(shutdown_type what);
358  

355  

359  
    /** Shut down part or all of the socket (non-throwing).
356  
    /** Shut down part or all of the socket (non-throwing).
360  

357  

361  
        @param what Which direction to shut down.
358  
        @param what Which direction to shut down.
362  
        @param ec Set to the error code on failure.
359  
        @param ec Set to the error code on failure.
363  
    */
360  
    */
364  
    void shutdown(shutdown_type what, std::error_code& ec) noexcept;
361  
    void shutdown(shutdown_type what, std::error_code& ec) noexcept;
365  

362  

366  
    /** Set a socket option.
363  
    /** Set a socket option.
367  

364  

368  
        Applies a type-safe socket option to the underlying socket.
365  
        Applies a type-safe socket option to the underlying socket.
369  
        The option type encodes the protocol level and option name.
366  
        The option type encodes the protocol level and option name.
370  

367  

371  
        @param opt The option to set.
368  
        @param opt The option to set.
372  

369  

373  
        @throws std::logic_error if the socket is not open.
370  
        @throws std::logic_error if the socket is not open.
374  
        @throws std::system_error on failure.
371  
        @throws std::system_error on failure.
375  
    */
372  
    */
376  
    template<class Option>
373  
    template<class Option>
377  
    void set_option(Option const& opt)
374  
    void set_option(Option const& opt)
378  
    {
375  
    {
379  
        if (!is_open())
376  
        if (!is_open())
380  
            detail::throw_logic_error("set_option: socket not open");
377  
            detail::throw_logic_error("set_option: socket not open");
381  
        std::error_code ec = get().set_option(
378  
        std::error_code ec = get().set_option(
382  
            Option::level(), Option::name(), opt.data(), opt.size());
379  
            Option::level(), Option::name(), opt.data(), opt.size());
383  
        if (ec)
380  
        if (ec)
384  
            detail::throw_system_error(ec, "local_stream_socket::set_option");
381  
            detail::throw_system_error(ec, "local_stream_socket::set_option");
385  
    }
382  
    }
386  

383  

387  
    /** Get a socket option.
384  
    /** Get a socket option.
388  

385  

389  
        Retrieves the current value of a type-safe socket option.
386  
        Retrieves the current value of a type-safe socket option.
390  

387  

391  
        @return The current option value.
388  
        @return The current option value.
392  

389  

393  
        @throws std::logic_error if the socket is not open.
390  
        @throws std::logic_error if the socket is not open.
394  
        @throws std::system_error on failure.
391  
        @throws std::system_error on failure.
395  
    */
392  
    */
396  
    template<class Option>
393  
    template<class Option>
397  
    Option get_option() const
394  
    Option get_option() const
398  
    {
395  
    {
399  
        if (!is_open())
396  
        if (!is_open())
400  
            detail::throw_logic_error("get_option: socket not open");
397  
            detail::throw_logic_error("get_option: socket not open");
401  
        Option opt{};
398  
        Option opt{};
402  
        std::size_t sz = opt.size();
399  
        std::size_t sz = opt.size();
403  
        std::error_code ec =
400  
        std::error_code ec =
404  
            get().get_option(Option::level(), Option::name(), opt.data(), &sz);
401  
            get().get_option(Option::level(), Option::name(), opt.data(), &sz);
405  
        if (ec)
402  
        if (ec)
406  
            detail::throw_system_error(ec, "local_stream_socket::get_option");
403  
            detail::throw_system_error(ec, "local_stream_socket::get_option");
407  
        opt.resize(sz);
404  
        opt.resize(sz);
408  
        return opt;
405  
        return opt;
409  
    }
406  
    }
410  

407  

411  
    /** Assign an existing file descriptor to this socket.
408  
    /** Assign an existing file descriptor to this socket.
412  

409  

413  
        The socket must not already be open. The fd is adopted
410  
        The socket must not already be open. The fd is adopted
414  
        and registered with the platform reactor. Used by
411  
        and registered with the platform reactor. Used by
415  
        make_local_stream_pair() to wrap socketpair() fds.
412  
        make_local_stream_pair() to wrap socketpair() fds.
416  

413  

417  
        @param fd The file descriptor to adopt. Must be a valid,
414  
        @param fd The file descriptor to adopt. Must be a valid,
418  
            open, non-blocking Unix stream socket.
415  
            open, non-blocking Unix stream socket.
419  

416  

420  
        @throws std::system_error on failure.
417  
        @throws std::system_error on failure.
421  
    */
418  
    */
422  
    void assign(native_handle_type fd);
419  
    void assign(native_handle_type fd);
423  

420  

424  
    /** Get the local endpoint of the socket.
421  
    /** Get the local endpoint of the socket.
425  

422  

426  
        Returns the local address (path) to which the socket is bound.
423  
        Returns the local address (path) to which the socket is bound.
427  
        The endpoint is cached when the connection is established.
424  
        The endpoint is cached when the connection is established.
428  

425  

429  
        @return The local endpoint, or a default endpoint if the socket
426  
        @return The local endpoint, or a default endpoint if the socket
430  
            is not connected.
427  
            is not connected.
431  
    */
428  
    */
432  
    corosio::local_endpoint local_endpoint() const noexcept;
429  
    corosio::local_endpoint local_endpoint() const noexcept;
433  

430  

434  
    /** Get the remote endpoint of the socket.
431  
    /** Get the remote endpoint of the socket.
435  

432  

436  
        Returns the remote address (path) to which the socket is connected.
433  
        Returns the remote address (path) to which the socket is connected.
437  
        The endpoint is cached when the connection is established.
434  
        The endpoint is cached when the connection is established.
438  

435  

439  
        @return The remote endpoint, or a default endpoint if the socket
436  
        @return The remote endpoint, or a default endpoint if the socket
440  
            is not connected.
437  
            is not connected.
441  
    */
438  
    */
442  
    corosio::local_endpoint remote_endpoint() const noexcept;
439  
    corosio::local_endpoint remote_endpoint() const noexcept;
443  

440  

444  
protected:
441  
protected:
445  
    local_stream_socket() noexcept = default;
442  
    local_stream_socket() noexcept = default;
446  

443  

447  
    explicit local_stream_socket(handle h) noexcept : io_object(std::move(h)) {}
444  
    explicit local_stream_socket(handle h) noexcept : io_object(std::move(h)) {}
448  

445  

449  
private:
446  
private:
450  
    friend class local_stream_acceptor;
447  
    friend class local_stream_acceptor;
451  

448  

452  
    void open_for_family(int family, int type, int protocol);
449  
    void open_for_family(int family, int type, int protocol);
453  

450  

454  
    inline implementation& get() const noexcept
451  
    inline implementation& get() const noexcept
455  
    {
452  
    {
456  
        return *static_cast<implementation*>(h_.get());
453  
        return *static_cast<implementation*>(h_.get());
457  
    }
454  
    }
458  
};
455  
};
459  

456  

460  
} // namespace boost::corosio
457  
} // namespace boost::corosio
461  

458  

462  
#endif // BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP
459  
#endif // BOOST_COROSIO_LOCAL_STREAM_SOCKET_HPP