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