95.88% Lines (93/97) 100.00% Functions (14/14)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
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_NATIVE_DETAIL_ENDPOINT_CONVERT_HPP 10   #ifndef BOOST_COROSIO_NATIVE_DETAIL_ENDPOINT_CONVERT_HPP
11   #define BOOST_COROSIO_NATIVE_DETAIL_ENDPOINT_CONVERT_HPP 11   #define BOOST_COROSIO_NATIVE_DETAIL_ENDPOINT_CONVERT_HPP
12   12  
13   #include <boost/corosio/endpoint.hpp> 13   #include <boost/corosio/endpoint.hpp>
14   #include <boost/corosio/local_endpoint.hpp> 14   #include <boost/corosio/local_endpoint.hpp>
15   #include <boost/corosio/detail/platform.hpp> 15   #include <boost/corosio/detail/platform.hpp>
16   16  
17   #include <algorithm> 17   #include <algorithm>
18   #include <cstring> 18   #include <cstring>
19   19  
20   #if BOOST_COROSIO_POSIX 20   #if BOOST_COROSIO_POSIX
21   #include <sys/socket.h> 21   #include <sys/socket.h>
22   #include <sys/un.h> 22   #include <sys/un.h>
23   #include <netinet/in.h> 23   #include <netinet/in.h>
24   #include <arpa/inet.h> 24   #include <arpa/inet.h>
25   #else 25   #else
26   #ifndef WIN32_LEAN_AND_MEAN 26   #ifndef WIN32_LEAN_AND_MEAN
27   #define WIN32_LEAN_AND_MEAN 27   #define WIN32_LEAN_AND_MEAN
28   #endif 28   #endif
29   #ifndef NOMINMAX 29   #ifndef NOMINMAX
30   #define NOMINMAX 30   #define NOMINMAX
31   #endif 31   #endif
32   #include <WinSock2.h> 32   #include <WinSock2.h>
33   #include <Ws2tcpip.h> 33   #include <Ws2tcpip.h>
34   #endif 34   #endif
35   35  
36   #include <cstddef> // offsetof 36   #include <cstddef> // offsetof
37   37  
38   #ifndef AF_UNIX 38   #ifndef AF_UNIX
39   #define AF_UNIX 1 39   #define AF_UNIX 1
40   #endif 40   #endif
41   41  
42   namespace boost::corosio::detail { 42   namespace boost::corosio::detail {
43   43  
44   /** Convert IPv4 endpoint to sockaddr_in. 44   /** Convert IPv4 endpoint to sockaddr_in.
45   45  
46   @param ep The endpoint to convert. Must be IPv4 (is_v4() == true). 46   @param ep The endpoint to convert. Must be IPv4 (is_v4() == true).
47   @return A sockaddr_in structure with fields in network byte order. 47   @return A sockaddr_in structure with fields in network byte order.
48   */ 48   */
49   inline sockaddr_in 49   inline sockaddr_in
HITCBC 50   6544 to_sockaddr_in(endpoint const& ep) noexcept 50   7754 to_sockaddr_in(endpoint const& ep) noexcept
51   { 51   {
HITCBC 52   6544 sockaddr_in sa{}; 52   7754 sockaddr_in sa{};
HITCBC 53   6544 sa.sin_family = AF_INET; 53   7754 sa.sin_family = AF_INET;
HITCBC 54   6544 sa.sin_port = htons(ep.port()); 54   7754 sa.sin_port = htons(ep.port());
HITCBC 55   6544 auto bytes = ep.v4_address().to_bytes(); 55   7754 auto bytes = ep.v4_address().to_bytes();
HITCBC 56   6544 std::memcpy(&sa.sin_addr, bytes.data(), 4); 56   7754 std::memcpy(&sa.sin_addr, bytes.data(), 4);
HITCBC 57   6544 return sa; 57   7754 return sa;
58   } 58   }
59   59  
60   /** Convert IPv6 endpoint to sockaddr_in6. 60   /** Convert IPv6 endpoint to sockaddr_in6.
61   61  
62   @param ep The endpoint to convert. Must be IPv6 (is_v6() == true). 62   @param ep The endpoint to convert. Must be IPv6 (is_v6() == true).
63   @return A sockaddr_in6 structure with fields in network byte order. 63   @return A sockaddr_in6 structure with fields in network byte order.
64   */ 64   */
65   inline sockaddr_in6 65   inline sockaddr_in6
HITCBC 66   40 to_sockaddr_in6(endpoint const& ep) noexcept 66   40 to_sockaddr_in6(endpoint const& ep) noexcept
67   { 67   {
HITCBC 68   40 sockaddr_in6 sa{}; 68   40 sockaddr_in6 sa{};
HITCBC 69   40 sa.sin6_family = AF_INET6; 69   40 sa.sin6_family = AF_INET6;
HITCBC 70   40 sa.sin6_port = htons(ep.port()); 70   40 sa.sin6_port = htons(ep.port());
HITCBC 71   40 auto bytes = ep.v6_address().to_bytes(); 71   40 auto bytes = ep.v6_address().to_bytes();
HITCBC 72   40 std::memcpy(&sa.sin6_addr, bytes.data(), 16); 72   40 std::memcpy(&sa.sin6_addr, bytes.data(), 16);
HITCBC 73   40 return sa; 73   40 return sa;
74   } 74   }
75   75  
76   /** Create endpoint from sockaddr_in. 76   /** Create endpoint from sockaddr_in.
77   77  
78   @param sa The sockaddr_in structure with fields in network byte order. 78   @param sa The sockaddr_in structure with fields in network byte order.
79   @return An endpoint with address and port extracted from sa. 79   @return An endpoint with address and port extracted from sa.
80   */ 80   */
81   inline endpoint 81   inline endpoint
HITCBC 82   12811 from_sockaddr_in(sockaddr_in const& sa) noexcept 82   15233 from_sockaddr_in(sockaddr_in const& sa) noexcept
83   { 83   {
84   ipv4_address::bytes_type bytes; 84   ipv4_address::bytes_type bytes;
HITCBC 85   12811 std::memcpy(bytes.data(), &sa.sin_addr, 4); 85   15233 std::memcpy(bytes.data(), &sa.sin_addr, 4);
HITCBC 86   12811 return endpoint(ipv4_address(bytes), ntohs(sa.sin_port)); 86   15233 return endpoint(ipv4_address(bytes), ntohs(sa.sin_port));
87   } 87   }
88   88  
89   /** Create endpoint from sockaddr_in6. 89   /** Create endpoint from sockaddr_in6.
90   90  
91   @param sa The sockaddr_in6 structure with fields in network byte order. 91   @param sa The sockaddr_in6 structure with fields in network byte order.
92   @return An endpoint with address and port extracted from sa. 92   @return An endpoint with address and port extracted from sa.
93   */ 93   */
94   inline endpoint 94   inline endpoint
HITCBC 95   58 from_sockaddr_in6(sockaddr_in6 const& sa) noexcept 95   58 from_sockaddr_in6(sockaddr_in6 const& sa) noexcept
96   { 96   {
97   ipv6_address::bytes_type bytes; 97   ipv6_address::bytes_type bytes;
HITCBC 98   58 std::memcpy(bytes.data(), &sa.sin6_addr, 16); 98   58 std::memcpy(bytes.data(), &sa.sin6_addr, 16);
HITCBC 99   58 return endpoint(ipv6_address(bytes), ntohs(sa.sin6_port)); 99   58 return endpoint(ipv6_address(bytes), ntohs(sa.sin6_port));
100   } 100   }
101   101  
102   /** Convert an IPv4 endpoint to an IPv4-mapped IPv6 sockaddr_in6. 102   /** Convert an IPv4 endpoint to an IPv4-mapped IPv6 sockaddr_in6.
103   103  
104   Produces a `sockaddr_in6` with the `::ffff:` prefix, suitable 104   Produces a `sockaddr_in6` with the `::ffff:` prefix, suitable
105   for passing an IPv4 destination to a dual-stack IPv6 socket. 105   for passing an IPv4 destination to a dual-stack IPv6 socket.
106   106  
107   @param ep The endpoint to convert. Must be IPv4 (is_v4() == true). 107   @param ep The endpoint to convert. Must be IPv4 (is_v4() == true).
108   @return A sockaddr_in6 with the IPv4-mapped address. 108   @return A sockaddr_in6 with the IPv4-mapped address.
109   */ 109   */
110   inline sockaddr_in6 110   inline sockaddr_in6
HITCBC 111   2 to_v4_mapped_sockaddr_in6(endpoint const& ep) noexcept 111   2 to_v4_mapped_sockaddr_in6(endpoint const& ep) noexcept
112   { 112   {
HITCBC 113   2 sockaddr_in6 sa{}; 113   2 sockaddr_in6 sa{};
HITCBC 114   2 sa.sin6_family = AF_INET6; 114   2 sa.sin6_family = AF_INET6;
HITCBC 115   2 sa.sin6_port = htons(ep.port()); 115   2 sa.sin6_port = htons(ep.port());
116   // ::ffff:0:0/96 prefix 116   // ::ffff:0:0/96 prefix
HITCBC 117   2 sa.sin6_addr.s6_addr[10] = 0xff; 117   2 sa.sin6_addr.s6_addr[10] = 0xff;
HITCBC 118   2 sa.sin6_addr.s6_addr[11] = 0xff; 118   2 sa.sin6_addr.s6_addr[11] = 0xff;
HITCBC 119   2 auto bytes = ep.v4_address().to_bytes(); 119   2 auto bytes = ep.v4_address().to_bytes();
HITCBC 120   2 std::memcpy(&sa.sin6_addr.s6_addr[12], bytes.data(), 4); 120   2 std::memcpy(&sa.sin6_addr.s6_addr[12], bytes.data(), 4);
HITCBC 121   2 return sa; 121   2 return sa;
122   } 122   }
123   123  
124   /** Convert endpoint to sockaddr_storage. 124   /** Convert endpoint to sockaddr_storage.
125   125  
126   Dispatches to @ref to_sockaddr_in or @ref to_sockaddr_in6 126   Dispatches to @ref to_sockaddr_in or @ref to_sockaddr_in6
127   based on the endpoint's address family. 127   based on the endpoint's address family.
128   128  
129   @param ep The endpoint to convert. 129   @param ep The endpoint to convert.
130   @param storage Output parameter filled with the sockaddr. 130   @param storage Output parameter filled with the sockaddr.
131   @return The length of the filled sockaddr structure. 131   @return The length of the filled sockaddr structure.
132   */ 132   */
133   inline socklen_t 133   inline socklen_t
HITCBC 134   6574 to_sockaddr(endpoint const& ep, sockaddr_storage& storage) noexcept 134   7784 to_sockaddr(endpoint const& ep, sockaddr_storage& storage) noexcept
135   { 135   {
HITCBC 136   6574 std::memset(&storage, 0, sizeof(storage)); 136   7784 std::memset(&storage, 0, sizeof(storage));
HITCBC 137   6574 if (ep.is_v4()) 137   7784 if (ep.is_v4())
138   { 138   {
HITCBC 139   6536 auto sa = to_sockaddr_in(ep); 139   7746 auto sa = to_sockaddr_in(ep);
HITCBC 140   6536 std::memcpy(&storage, &sa, sizeof(sa)); 140   7746 std::memcpy(&storage, &sa, sizeof(sa));
HITCBC 141   6536 return sizeof(sa); 141   7746 return sizeof(sa);
142   } 142   }
HITCBC 143   38 auto sa6 = to_sockaddr_in6(ep); 143   38 auto sa6 = to_sockaddr_in6(ep);
HITCBC 144   38 std::memcpy(&storage, &sa6, sizeof(sa6)); 144   38 std::memcpy(&storage, &sa6, sizeof(sa6));
HITCBC 145   38 return sizeof(sa6); 145   38 return sizeof(sa6);
146   } 146   }
147   147  
148   /** Convert endpoint to sockaddr_storage for a specific socket family. 148   /** Convert endpoint to sockaddr_storage for a specific socket family.
149   149  
150   When the socket is AF_INET6 and the endpoint is IPv4, the address 150   When the socket is AF_INET6 and the endpoint is IPv4, the address
151   is converted to an IPv4-mapped IPv6 address (`::ffff:x.x.x.x`) so 151   is converted to an IPv4-mapped IPv6 address (`::ffff:x.x.x.x`) so
152   dual-stack sockets can connect to IPv4 destinations. 152   dual-stack sockets can connect to IPv4 destinations.
153   153  
154   @param ep The endpoint to convert. 154   @param ep The endpoint to convert.
155   @param socket_family The address family of the socket (AF_INET or 155   @param socket_family The address family of the socket (AF_INET or
156   AF_INET6). 156   AF_INET6).
157   @param storage Output parameter filled with the sockaddr. 157   @param storage Output parameter filled with the sockaddr.
158   @return The length of the filled sockaddr structure. 158   @return The length of the filled sockaddr structure.
159   */ 159   */
160   inline socklen_t 160   inline socklen_t
HITCBC 161   6410 to_sockaddr( 161   7620 to_sockaddr(
162   endpoint const& ep, int socket_family, sockaddr_storage& storage) noexcept 162   endpoint const& ep, int socket_family, sockaddr_storage& storage) noexcept
163   { 163   {
164   // IPv4 endpoint on IPv6 socket: use IPv4-mapped address 164   // IPv4 endpoint on IPv6 socket: use IPv4-mapped address
HITCBC 165   6410 if (ep.is_v4() && socket_family == AF_INET6) 165   7620 if (ep.is_v4() && socket_family == AF_INET6)
166   { 166   {
HITCBC 167   2 std::memset(&storage, 0, sizeof(storage)); 167   2 std::memset(&storage, 0, sizeof(storage));
HITCBC 168   2 auto sa6 = to_v4_mapped_sockaddr_in6(ep); 168   2 auto sa6 = to_v4_mapped_sockaddr_in6(ep);
HITCBC 169   2 std::memcpy(&storage, &sa6, sizeof(sa6)); 169   2 std::memcpy(&storage, &sa6, sizeof(sa6));
HITCBC 170   2 return sizeof(sa6); 170   2 return sizeof(sa6);
171   } 171   }
HITCBC 172   6408 return to_sockaddr(ep, storage); 172   7618 return to_sockaddr(ep, storage);
173   } 173   }
174   174  
175   /** Create endpoint from sockaddr_storage. 175   /** Create endpoint from sockaddr_storage.
176   176  
177   Dispatches on `ss_family` to reconstruct the appropriate 177   Dispatches on `ss_family` to reconstruct the appropriate
178   IPv4 or IPv6 endpoint. 178   IPv4 or IPv6 endpoint.
179   179  
180   @param storage The sockaddr_storage with fields in network byte order. 180   @param storage The sockaddr_storage with fields in network byte order.
181   @return An endpoint with address and port extracted from storage. 181   @return An endpoint with address and port extracted from storage.
182   */ 182   */
183   inline endpoint 183   inline endpoint
HITCBC 184   12856 from_sockaddr(sockaddr_storage const& storage) noexcept 184   15278 from_sockaddr(sockaddr_storage const& storage) noexcept
185   { 185   {
HITCBC 186   12856 if (storage.ss_family == AF_INET) 186   15278 if (storage.ss_family == AF_INET)
187   { 187   {
188   sockaddr_in sa; 188   sockaddr_in sa;
HITCBC 189   12800 std::memcpy(&sa, &storage, sizeof(sa)); 189   15222 std::memcpy(&sa, &storage, sizeof(sa));
HITCBC 190   12800 return from_sockaddr_in(sa); 190   15222 return from_sockaddr_in(sa);
191   } 191   }
HITCBC 192   56 if (storage.ss_family == AF_INET6) 192   56 if (storage.ss_family == AF_INET6)
193   { 193   {
194   sockaddr_in6 sa6; 194   sockaddr_in6 sa6;
HITCBC 195   56 std::memcpy(&sa6, &storage, sizeof(sa6)); 195   56 std::memcpy(&sa6, &storage, sizeof(sa6));
HITCBC 196   56 return from_sockaddr_in6(sa6); 196   56 return from_sockaddr_in6(sa6);
197   } 197   }
MISUBC 198   return endpoint{}; 198   return endpoint{};
199   } 199   }
200   200  
201   /** Return the native address family for an endpoint. 201   /** Return the native address family for an endpoint.
202   202  
203   @param ep The endpoint to query. 203   @param ep The endpoint to query.
204   @return `AF_INET` for IPv4, `AF_INET6` for IPv6. 204   @return `AF_INET` for IPv4, `AF_INET6` for IPv6.
205   */ 205   */
206   inline int 206   inline int
207   endpoint_family(endpoint const& ep) noexcept 207   endpoint_family(endpoint const& ep) noexcept
208   { 208   {
209   return ep.is_v6() ? AF_INET6 : AF_INET; 209   return ep.is_v6() ? AF_INET6 : AF_INET;
210   } 210   }
211   211  
212   /** Return the address family of a socket descriptor. 212   /** Return the address family of a socket descriptor.
213   213  
214   @param fd The socket file descriptor. 214   @param fd The socket file descriptor.
215   @return AF_INET, AF_INET6, or AF_UNSPEC on failure. 215   @return AF_INET, AF_INET6, or AF_UNSPEC on failure.
216   */ 216   */
217   inline int 217   inline int
HITCBC 218   6436 socket_family( 218   7646 socket_family(
219   #if BOOST_COROSIO_POSIX 219   #if BOOST_COROSIO_POSIX
220   int fd 220   int fd
221   #else 221   #else
222   std::uintptr_t fd 222   std::uintptr_t fd
223   #endif 223   #endif
224   ) noexcept 224   ) noexcept
225   { 225   {
HITCBC 226   6436 sockaddr_storage storage{}; 226   7646 sockaddr_storage storage{};
HITCBC 227   6436 socklen_t len = sizeof(storage); 227   7646 socklen_t len = sizeof(storage);
HITCBC 228   6436 if (getsockname( 228   7646 if (getsockname(
229   #if BOOST_COROSIO_POSIX 229   #if BOOST_COROSIO_POSIX
230   fd, 230   fd,
231   #else 231   #else
232   static_cast<SOCKET>(fd), 232   static_cast<SOCKET>(fd),
233   #endif 233   #endif
HITCBC 234   6436 reinterpret_cast<sockaddr*>(&storage), &len) != 0) 234   7646 reinterpret_cast<sockaddr*>(&storage), &len) != 0)
MISUBC 235   return AF_UNSPEC; 235   return AF_UNSPEC;
HITCBC 236   6436 return storage.ss_family; 236   7646 return storage.ss_family;
237   } 237   }
238   238  
239   //---------------------------------------------------------- 239   //----------------------------------------------------------
240   // local_endpoint (AF_UNIX) conversions 240   // local_endpoint (AF_UNIX) conversions
241   //---------------------------------------------------------- 241   //----------------------------------------------------------
242   242  
243   // Platform-agnostic sockaddr_un alias. POSIX uses the real 243   // Platform-agnostic sockaddr_un alias. POSIX uses the real
244   // sockaddr_un from <sys/un.h>; Windows uses a private struct 244   // sockaddr_un from <sys/un.h>; Windows uses a private struct
245   // matching the layout (same approach as Boost.Asio). 245   // matching the layout (same approach as Boost.Asio).
246   #if BOOST_COROSIO_POSIX 246   #if BOOST_COROSIO_POSIX
247   using un_sa_t = sockaddr_un; 247   using un_sa_t = sockaddr_un;
248   #else 248   #else
249   struct un_sa_t { u_short sun_family; char sun_path[108]; }; 249   struct un_sa_t { u_short sun_family; char sun_path[108]; };
250   #endif 250   #endif
251   251  
252   /** Convert a local_endpoint to sockaddr_storage. 252   /** Convert a local_endpoint to sockaddr_storage.
253   253  
254   @param ep The local endpoint to convert. 254   @param ep The local endpoint to convert.
255   @param storage Output parameter filled with the sockaddr_un. 255   @param storage Output parameter filled with the sockaddr_un.
256   @return The length of the filled sockaddr structure. 256   @return The length of the filled sockaddr structure.
257   */ 257   */
258   inline socklen_t 258   inline socklen_t
HITCBC 259   38 to_sockaddr(local_endpoint const& ep, sockaddr_storage& storage) noexcept 259   38 to_sockaddr(local_endpoint const& ep, sockaddr_storage& storage) noexcept
260   { 260   {
HITCBC 261   38 std::memset(&storage, 0, sizeof(storage)); 261   38 std::memset(&storage, 0, sizeof(storage));
HITCBC 262   38 un_sa_t sa{}; 262   38 un_sa_t sa{};
HITCBC 263   38 sa.sun_family = AF_UNIX; 263   38 sa.sun_family = AF_UNIX;
HITCBC 264   38 auto path = ep.path(); 264   38 auto path = ep.path();
HITCBC 265   38 auto copy_len = (std::min)(path.size(), sizeof(sa.sun_path)); 265   38 auto copy_len = (std::min)(path.size(), sizeof(sa.sun_path));
HITCBC 266   38 if (copy_len > 0) 266   38 if (copy_len > 0)
HITCBC 267   38 std::memcpy(sa.sun_path, path.data(), copy_len); 267   38 std::memcpy(sa.sun_path, path.data(), copy_len);
HITCBC 268   38 std::memcpy(&storage, &sa, sizeof(sa)); 268   38 std::memcpy(&storage, &sa, sizeof(sa));
269   269  
HITCBC 270   38 if (ep.is_abstract()) 270   38 if (ep.is_abstract())
271   return static_cast<socklen_t>( 271   return static_cast<socklen_t>(
HITCBC 272   6 offsetof(un_sa_t, sun_path) + copy_len); 272   6 offsetof(un_sa_t, sun_path) + copy_len);
HITCBC 273   32 return static_cast<socklen_t>(sizeof(sa)); 273   32 return static_cast<socklen_t>(sizeof(sa));
274   } 274   }
275   275  
276   /** Convert a local_endpoint to sockaddr_storage (family-aware overload). 276   /** Convert a local_endpoint to sockaddr_storage (family-aware overload).
277   277  
278   The socket_family parameter is ignored for Unix sockets since 278   The socket_family parameter is ignored for Unix sockets since
279   there is no dual-stack mapping. 279   there is no dual-stack mapping.
280   280  
281   @param ep The local endpoint to convert. 281   @param ep The local endpoint to convert.
282   @param socket_family Ignored. 282   @param socket_family Ignored.
283   @param storage Output parameter filled with the sockaddr_un. 283   @param storage Output parameter filled with the sockaddr_un.
284   @return The length of the filled sockaddr structure. 284   @return The length of the filled sockaddr structure.
285   */ 285   */
286   inline socklen_t 286   inline socklen_t
HITCBC 287   26 to_sockaddr( 287   26 to_sockaddr(
288   local_endpoint const& ep, 288   local_endpoint const& ep,
289   int /*socket_family*/, 289   int /*socket_family*/,
290   sockaddr_storage& storage) noexcept 290   sockaddr_storage& storage) noexcept
291   { 291   {
HITCBC 292   26 return to_sockaddr(ep, storage); 292   26 return to_sockaddr(ep, storage);
293   } 293   }
294   294  
295   /** Create a local_endpoint from sockaddr_storage. 295   /** Create a local_endpoint from sockaddr_storage.
296   296  
297   @param storage The sockaddr_storage (must have ss_family == AF_UNIX). 297   @param storage The sockaddr_storage (must have ss_family == AF_UNIX).
298   @param len The address length returned by the kernel. 298   @param len The address length returned by the kernel.
299   @return A local_endpoint with the path extracted from the 299   @return A local_endpoint with the path extracted from the
300   sockaddr_un, or an empty endpoint if the family is not AF_UNIX. 300   sockaddr_un, or an empty endpoint if the family is not AF_UNIX.
301   */ 301   */
302   inline local_endpoint 302   inline local_endpoint
HITCBC 303   100 from_sockaddr_local( 303   100 from_sockaddr_local(
304   sockaddr_storage const& storage, socklen_t len) noexcept 304   sockaddr_storage const& storage, socklen_t len) noexcept
305   { 305   {
HITCBC 306   100 if (storage.ss_family != AF_UNIX) 306   100 if (storage.ss_family != AF_UNIX)
MISUBC 307   return local_endpoint{}; 307   return local_endpoint{};
308   308  
HITCBC 309   100 un_sa_t sa{}; 309   100 un_sa_t sa{};
HITCBC 310   100 std::memcpy( 310   100 std::memcpy(
311   &sa, &storage, 311   &sa, &storage,
HITCBC 312   100 (std::min)(static_cast<std::size_t>(len), sizeof(sa))); 312   100 (std::min)(static_cast<std::size_t>(len), sizeof(sa)));
313   313  
HITCBC 314   100 auto path_offset = offsetof(un_sa_t, sun_path); 314   100 auto path_offset = offsetof(un_sa_t, sun_path);
HITCBC 315   100 if (static_cast<std::size_t>(len) <= path_offset) 315   100 if (static_cast<std::size_t>(len) <= path_offset)
HITCBC 316   68 return local_endpoint{}; 316   68 return local_endpoint{};
317   317  
HITCBC 318   32 auto path_len = static_cast<std::size_t>(len) - path_offset; 318   32 auto path_len = static_cast<std::size_t>(len) - path_offset;
319   319  
320   // Non-abstract paths may be null-terminated by the kernel 320   // Non-abstract paths may be null-terminated by the kernel
HITCBC 321   32 if (path_len > 0 && sa.sun_path[0] != '\0') 321   32 if (path_len > 0 && sa.sun_path[0] != '\0')
322   { 322   {
323   auto* end = static_cast<char const*>( 323   auto* end = static_cast<char const*>(
HITCBC 324   26 std::memchr(sa.sun_path, '\0', path_len)); 324   26 std::memchr(sa.sun_path, '\0', path_len));
HITCBC 325   26 if (end) 325   26 if (end)
HITCBC 326   26 path_len = static_cast<std::size_t>(end - sa.sun_path); 326   26 path_len = static_cast<std::size_t>(end - sa.sun_path);
327   } 327   }
328   328  
HITCBC 329   32 std::error_code ec; 329   32 std::error_code ec;
HITCBC 330   32 local_endpoint ep(std::string_view(sa.sun_path, path_len), ec); 330   32 local_endpoint ep(std::string_view(sa.sun_path, path_len), ec);
HITCBC 331   32 if (ec) 331   32 if (ec)
MISUBC 332   return local_endpoint{}; 332   return local_endpoint{};
HITCBC 333   32 return ep; 333   32 return ep;
334   } 334   }
335   335  
336   //---------------------------------------------------------- 336   //----------------------------------------------------------
337   // Tag-dispatch helpers for templatized reactor code. 337   // Tag-dispatch helpers for templatized reactor code.
338   // Overload resolution selects the correct conversion based 338   // Overload resolution selects the correct conversion based
339   // on the Endpoint type. 339   // on the Endpoint type.
340   //---------------------------------------------------------- 340   //----------------------------------------------------------
341   341  
342   /** Convert sockaddr_storage to an IP endpoint (tag overload). 342   /** Convert sockaddr_storage to an IP endpoint (tag overload).
343   343  
344   @param storage The sockaddr_storage with fields in network byte order. 344   @param storage The sockaddr_storage with fields in network byte order.
345   @param len The address length returned by the kernel. 345   @param len The address length returned by the kernel.
346   @return An endpoint with address and port extracted from storage. 346   @return An endpoint with address and port extracted from storage.
347   */ 347   */
348   inline endpoint 348   inline endpoint
HITCBC 349   12856 from_sockaddr_as( 349   15278 from_sockaddr_as(
350   sockaddr_storage const& storage, socklen_t /*len*/, endpoint const&) noexcept 350   sockaddr_storage const& storage, socklen_t /*len*/, endpoint const&) noexcept
351   { 351   {
HITCBC 352   12856 return from_sockaddr(storage); 352   15278 return from_sockaddr(storage);
353   } 353   }
354   354  
355   /** Convert sockaddr_storage to a local_endpoint (tag overload). 355   /** Convert sockaddr_storage to a local_endpoint (tag overload).
356   356  
357   @param storage The sockaddr_storage. 357   @param storage The sockaddr_storage.
358   @param len The address length returned by the kernel. 358   @param len The address length returned by the kernel.
359   @return A local_endpoint with path extracted from storage. 359   @return A local_endpoint with path extracted from storage.
360   */ 360   */
361   inline local_endpoint 361   inline local_endpoint
HITCBC 362   100 from_sockaddr_as( 362   100 from_sockaddr_as(
363   sockaddr_storage const& storage, 363   sockaddr_storage const& storage,
364   socklen_t len, 364   socklen_t len,
365   local_endpoint const&) noexcept 365   local_endpoint const&) noexcept
366   { 366   {
HITCBC 367   100 return from_sockaddr_local(storage, len); 367   100 return from_sockaddr_local(storage, len);
368   } 368   }
369   369  
370   } // namespace boost::corosio::detail 370   } // namespace boost::corosio::detail
371   371  
372   #endif 372   #endif