TLA Line data Source code
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 <boost/capy/results.hpp>
16 :
17 : #include <algorithm>
18 : #include <compare>
19 : #include <cstddef>
20 : #include <cstdint>
21 : #include <cstring>
22 : #include <iosfwd>
23 : #include <string_view>
24 : #include <system_error>
25 :
26 : namespace boost::corosio {
27 :
28 : /** Holds the filesystem path that names a Unix domain socket.
29 :
30 : Stores the path in a fixed-size buffer, avoiding heap
31 : allocation. The object is trivially copyable.
32 :
33 : Abstract sockets (Linux-only) are represented by paths whose
34 : first character is '\0'. The full path including the leading
35 : null byte is stored.
36 :
37 : The library does NOT automatically unlink the socket path on
38 : close. Callers are responsible for cleanup.
39 :
40 : @par Thread Safety
41 : Distinct objects: Safe.@n
42 : Shared objects: Safe.
43 :
44 : @see @ref boost::corosio::make_local_endpoint
45 : */
46 : class BOOST_COROSIO_DECL local_endpoint
47 : {
48 : struct from_path_t
49 : {};
50 :
51 : // Callers have already checked the length against max_path_length.
52 : local_endpoint(from_path_t, std::string_view path) noexcept;
53 :
54 : friend BOOST_COROSIO_DECL capy::results<local_endpoint>
55 : make_local_endpoint(std::string_view path) noexcept;
56 :
57 : // sun_path is 108 on Linux, 104 on macOS/FreeBSD. Use the
58 : // minimum so local_endpoint is portable across all three.
59 : char path_[104]{};
60 : std::uint8_t len_ = 0;
61 :
62 : public:
63 : /// Maximum path length for a Unix domain socket (excluding null terminator).
64 : static constexpr std::size_t max_path_length = 103;
65 :
66 : /// Default constructor. Creates an empty (unbound) endpoint.
67 HIT 9231 : local_endpoint() noexcept = default;
68 :
69 : /** Return the socket path.
70 :
71 : For abstract sockets, the returned view includes the
72 : leading null byte.
73 :
74 : @return A view over the stored path bytes.
75 : */
76 328 : std::string_view path() const noexcept
77 : {
78 328 : return std::string_view(path_, len_);
79 : }
80 :
81 : /** Check if this is an abstract socket (Linux-only).
82 :
83 : Abstract sockets live in a kernel namespace rather than
84 : the filesystem. They are identified by a leading null byte
85 : in the path.
86 :
87 : @return `true` if the path starts with '\\0'.
88 : */
89 307 : bool is_abstract() const noexcept
90 : {
91 307 : return len_ > 0 && path_[0] == '\0';
92 : }
93 :
94 : /// Return true if the endpoint has no path.
95 31 : bool empty() const noexcept
96 : {
97 31 : return len_ == 0;
98 : }
99 :
100 : /// Compare endpoints for equality.
101 : friend bool
102 9 : operator==(local_endpoint const& a, local_endpoint const& b) noexcept
103 : {
104 9 : return a.len_ == b.len_ && std::memcmp(a.path_, b.path_, a.len_) == 0;
105 : }
106 :
107 : /** Format the endpoint for stream output.
108 :
109 : Non-abstract paths are printed as-is. Abstract paths
110 : (leading null byte) are printed as `[abstract:name]`.
111 : Empty endpoints produce no output.
112 :
113 : @param os The output stream.
114 : @param ep The endpoint to format.
115 :
116 : @return A reference to @p os.
117 : */
118 : friend BOOST_COROSIO_DECL std::ostream&
119 : operator<<(std::ostream& os, local_endpoint const& ep);
120 :
121 : /// Lexicographic ordering on stored path bytes.
122 : friend std::strong_ordering
123 44 : operator<=>(local_endpoint const& a, local_endpoint const& b) noexcept
124 : {
125 44 : auto common = (std::min)(a.len_, b.len_);
126 44 : if (int cmp = std::memcmp(a.path_, b.path_, common); cmp != 0)
127 19 : return cmp <=> 0;
128 25 : return a.len_ <=> b.len_;
129 : }
130 : };
131 :
132 : /** Make a local endpoint from a filesystem path.
133 :
134 : A path longer than @ref local_endpoint::max_path_length cannot be
135 : represented in a socket address. Such a path reports
136 : `errc::filename_too_long` with an empty endpoint.
137 :
138 : @par Example
139 : @par !example make_local_endpoint
140 :
141 : @param path The socket path; an empty path yields an unbound endpoint.
142 :
143 : @return The error code and the endpoint.
144 : */
145 : [[nodiscard]] BOOST_COROSIO_DECL capy::results<local_endpoint>
146 : make_local_endpoint(std::string_view path) noexcept;
147 :
148 : } // namespace boost::corosio
149 :
150 : #endif // BOOST_COROSIO_LOCAL_ENDPOINT_HPP
|