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.
 
81 +
    using endpoint_type = corosio::local_endpoint;
 
82 +

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

85  

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

87  

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

94  

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

100  

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

109  

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

111  

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

113  

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

117  

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

120  

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

122  

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

125  

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

129  

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

131  

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

136  

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

138  

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

150  

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

152  

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

163  

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

166  

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

170  

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

177  

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

181  

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

188  

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

191  

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

195  

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

197  

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

201  

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

203  

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

205  

203  
        @param ex The executor whose context will own the socket.
206  
        @param ex The executor whose context will own the socket.
204  
    */
207  
    */
205  
    template<class Ex>
208  
    template<class Ex>
206  
        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>) &&
207  
        capy::Executor<Ex>
210  
        capy::Executor<Ex>
208  
    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())
209  
    {
212  
    {
210  
    }
213  
    }
211  

214  

212  
    /** Move constructor.
215  
    /** Move constructor.
213  

216  

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

218  

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

220  

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

229  

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

231  

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

233  

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

235  

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

240  

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

252  

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

255  

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

257  

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

260  

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

262  

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

266  

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

268  

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

273  

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

275  

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

286  

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

288  

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

290  

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

292  

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

294  

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

304  

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

306  

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

311  

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

313  

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

316  

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

321  

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

323  

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

325  

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

330  

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

332  

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

336  

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

338  

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

340  

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

344  

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

346  

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

351  

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

354  

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

358  

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

360  

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

365  

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

367  

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

370  

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

372  

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

386  

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

388  

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

390  

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

392  

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

410  

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

412  

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

416  

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

419  

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

423  

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

425  

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

428  

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

433  

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

435  

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

438  

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

443  

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

446  

444  
    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)) {}
445  

448  

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

451  

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

453  

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

459  

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

461  

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