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