1 +
//
 
2 +
// Copyright (c) 2026 Michael Vandeberg
 
3 +
//
 
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)
 
6 +
//
 
7 +
// Official repository: https://github.com/cppalliance/corosio
 
8 +
//
 
9 +

 
10 +
#ifndef BOOST_COROSIO_LOCAL_ENDPOINT_HPP
 
11 +
#define BOOST_COROSIO_LOCAL_ENDPOINT_HPP
 
12 +

 
13 +
#include <boost/corosio/detail/config.hpp>
 
14 +

 
15 +
#include <algorithm>
 
16 +
#include <compare>
 
17 +
#include <cstddef>
 
18 +
#include <cstdint>
 
19 +
#include <cstring>
 
20 +
#include <iosfwd>
 
21 +
#include <string_view>
 
22 +
#include <system_error>
 
23 +

 
24 +
namespace boost::corosio {
 
25 +

 
26 +
/* A Unix domain socket endpoint (filesystem path).
 
27 +

 
28 +
   Stores the path in a fixed-size buffer, avoiding heap
 
29 +
   allocation. The object is trivially copyable.
 
30 +

 
31 +
   Abstract sockets (Linux-only) are represented by paths whose
 
32 +
   first character is '\0'. The full path including the leading
 
33 +
   null byte is stored.
 
34 +

 
35 +
   The library does NOT automatically unlink the socket path on
 
36 +
   close — callers are responsible for cleanup.
 
37 +

 
38 +
   Thread Safety:
 
39 +
     Distinct objects: Safe.
 
40 +
     Shared objects: Safe.
 
41 +
*/
 
42 +
class BOOST_COROSIO_DECL local_endpoint
 
43 +
{
 
44 +
    // sun_path is 108 on Linux, 104 on macOS/FreeBSD. Use the
 
45 +
    // minimum so local_endpoint is portable across all three.
 
46 +
    char path_[104]{};
 
47 +
    std::uint8_t len_ = 0;
 
48 +

 
49 +
public:
 
50 +
    /// Maximum path length for a Unix domain socket (excluding null terminator).
 
51 +
    static constexpr std::size_t max_path_length = 103;
 
52 +

 
53 +
    /// Default constructor. Creates an empty (unbound) endpoint.
 
54 +
    local_endpoint() noexcept = default;
 
55 +

 
56 +
    /** Construct from a path.
 
57 +

 
58 +
        @param path The filesystem path for the socket.
 
59 +
            Must not exceed @ref max_path_length bytes.
 
60 +

 
61 +
        @throws std::system_error if the path is too long.
 
62 +
    */
 
63 +
    explicit local_endpoint(std::string_view path);
 
64 +

 
65 +
    /** Construct from a path (no-throw).
 
66 +

 
67 +
        @param path The filesystem path for the socket.
 
68 +
        @param ec Set to an error if the path is too long.
 
69 +
    */
 
70 +
    local_endpoint(std::string_view path, std::error_code& ec) noexcept;
 
71 +

 
72 +
    /// Return the socket path.
 
73 +
    std::string_view path() const noexcept
 
74 +
    {
 
75 +
        return std::string_view(path_, len_);
 
76 +
    }
 
77 +

 
78 +
    /** Check if this is an abstract socket (Linux-only).
 
79 +

 
80 +
        Abstract sockets live in a kernel namespace rather than
 
81 +
        the filesystem. They are identified by a leading null byte
 
82 +
        in the path.
 
83 +

 
84 +
        @return `true` if the path starts with '\\0'.
 
85 +
    */
 
86 +
    bool is_abstract() const noexcept
 
87 +
    {
 
88 +
        return len_ > 0 && path_[0] == '\0';
 
89 +
    }
 
90 +

 
91 +
    /// Return true if the endpoint has no path.
 
92 +
    bool empty() const noexcept
 
93 +
    {
 
94 +
        return len_ == 0;
 
95 +
    }
 
96 +

 
97 +
    /// Compare endpoints for equality.
 
98 +
    friend bool
 
99 +
    operator==(local_endpoint const& a, local_endpoint const& b) noexcept
 
100 +
    {
 
101 +
        return a.len_ == b.len_ &&
 
102 +
            std::memcmp(a.path_, b.path_, a.len_) == 0;
 
103 +
    }
 
104 +

 
105 +
    /** Format the endpoint for stream output.
 
106 +

 
107 +
        Non-abstract paths are printed as-is. Abstract paths
 
108 +
        (leading null byte) are printed as `[abstract:name]`.
 
109 +
        Empty endpoints produce no output.
 
110 +
    */
 
111 +
    friend BOOST_COROSIO_DECL std::ostream&
 
112 +
    operator<<(std::ostream& os, local_endpoint const& ep);
 
113 +

 
114 +
    /// Lexicographic ordering on stored path bytes.
 
115 +
    friend std::strong_ordering
 
116 +
    operator<=>(local_endpoint const& a, local_endpoint const& b) noexcept
 
117 +
    {
 
118 +
        auto common = (std::min)(a.len_, b.len_);
 
119 +
        if (int cmp = std::memcmp(a.path_, b.path_, common); cmp != 0)
 
120 +
            return cmp <=> 0;
 
121 +
        return a.len_ <=> b.len_;
 
122 +
    }
 
123 +
};
 
124 +

 
125 +
} // namespace boost::corosio
 
126 +

 
127 +
#endif // BOOST_COROSIO_LOCAL_ENDPOINT_HPP