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   8214 local_endpoint() noexcept = default; 54   8214 local_endpoint() noexcept = default;
55   55  
56   /** Construct from a path. 56   /** Construct from a path.
57   57  
58   An over-long path is a precondition violation: the limit is 58   An over-long path is a precondition violation: the limit is
59   the public @ref max_path_length constant, so callers with 59   the public @ref max_path_length constant, so callers with
60   runtime-derived paths can check 60   runtime-derived paths can check
61   `path.size() <= max_path_length` before constructing. 61   `path.size() <= max_path_length` before constructing.
62   62  
63   @param path The filesystem path for the socket. 63   @param path The filesystem path for the socket.
64   Must not exceed @ref max_path_length bytes. 64   Must not exceed @ref max_path_length bytes.
65   65  
66   @throws std::system_error `errc::filename_too_long` if the 66   @throws std::system_error `errc::filename_too_long` if the
67   path is too long. 67   path is too long.
68   */ 68   */
69   explicit local_endpoint(std::string_view path); 69   explicit local_endpoint(std::string_view path);
70   70  
  71 +
71   /** Return the socket path. 72   /** Return the socket path.
72   73  
73   For abstract sockets, the returned view includes the 74   For abstract sockets, the returned view includes the
74   leading null byte. 75   leading null byte.
75   76  
76   @return A view over the stored path bytes. 77   @return A view over the stored path bytes.
77   */ 78   */
HITCBC 78   322 std::string_view path() const noexcept 79   322 std::string_view path() const noexcept
79   { 80   {
HITCBC 80   322 return std::string_view(path_, len_); 81   322 return std::string_view(path_, len_);
81   } 82   }
82   83  
83   /** Check if this is an abstract socket (Linux-only). 84   /** Check if this is an abstract socket (Linux-only).
84   85  
85   Abstract sockets live in a kernel namespace rather than 86   Abstract sockets live in a kernel namespace rather than
86   the filesystem. They are identified by a leading null byte 87   the filesystem. They are identified by a leading null byte
87   in the path. 88   in the path.
88   89  
89   @return `true` if the path starts with '\\0'. 90   @return `true` if the path starts with '\\0'.
90   */ 91   */
HITCBC 91   301 bool is_abstract() const noexcept 92   301 bool is_abstract() const noexcept
92   { 93   {
HITCBC 93   301 return len_ > 0 && path_[0] == '\0'; 94   301 return len_ > 0 && path_[0] == '\0';
94   } 95   }
95   96  
96   /// Return true if the endpoint has no path. 97   /// Return true if the endpoint has no path.
HITCBC 97   26 bool empty() const noexcept 98   26 bool empty() const noexcept
98   { 99   {
HITCBC 99   26 return len_ == 0; 100   26 return len_ == 0;
100   } 101   }
101   102  
102   /// Compare endpoints for equality. 103   /// Compare endpoints for equality.
103   friend bool 104   friend bool
HITCBC 104   9 operator==(local_endpoint const& a, local_endpoint const& b) noexcept 105   9 operator==(local_endpoint const& a, local_endpoint const& b) noexcept
105   { 106   {
HITCBC 106 - 9 return a.len_ == b.len_ && std::memcmp(a.path_, b.path_, a.len_) == 0; 107 + 16 return a.len_ == b.len_ &&
HITGNC   108 + 16 std::memcmp(a.path_, b.path_, a.len_) == 0;
107   } 109   }
108   110  
109   /** Format the endpoint for stream output. 111   /** Format the endpoint for stream output.
110   112  
111   Non-abstract paths are printed as-is. Abstract paths 113   Non-abstract paths are printed as-is. Abstract paths
112   (leading null byte) are printed as `[abstract:name]`. 114   (leading null byte) are printed as `[abstract:name]`.
113   Empty endpoints produce no output. 115   Empty endpoints produce no output.
114   116  
115   @param os The output stream. 117   @param os The output stream.
116   @param ep The endpoint to format. 118   @param ep The endpoint to format.
117   119  
118   @return A reference to @p os. 120   @return A reference to @p os.
119   */ 121   */
120   friend BOOST_COROSIO_DECL std::ostream& 122   friend BOOST_COROSIO_DECL std::ostream&
121   operator<<(std::ostream& os, local_endpoint const& ep); 123   operator<<(std::ostream& os, local_endpoint const& ep);
122   124  
123   /// Lexicographic ordering on stored path bytes. 125   /// Lexicographic ordering on stored path bytes.
124   friend std::strong_ordering 126   friend std::strong_ordering
HITCBC 125   44 operator<=>(local_endpoint const& a, local_endpoint const& b) noexcept 127   44 operator<=>(local_endpoint const& a, local_endpoint const& b) noexcept
126   { 128   {
HITCBC 127   44 auto common = (std::min)(a.len_, b.len_); 129   44 auto common = (std::min)(a.len_, b.len_);
HITCBC 128   44 if (int cmp = std::memcmp(a.path_, b.path_, common); cmp != 0) 130   44 if (int cmp = std::memcmp(a.path_, b.path_, common); cmp != 0)
HITCBC 129   19 return cmp <=> 0; 131   19 return cmp <=> 0;
HITCBC 130   25 return a.len_ <=> b.len_; 132   25 return a.len_ <=> b.len_;
131   } 133   }
132   }; 134   };
133   135  
134   } // namespace boost::corosio 136   } // namespace boost::corosio
135   137  
136   #endif // BOOST_COROSIO_LOCAL_ENDPOINT_HPP 138   #endif // BOOST_COROSIO_LOCAL_ENDPOINT_HPP