LCOV - code coverage report
Current view: top level - corosio/native/detail - endpoint_convert.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 96.7 % 60 58 2
Test Date: 2026-02-27 19:39:18 Functions: 100.0 % 9 9

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
       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_NATIVE_DETAIL_ENDPOINT_CONVERT_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_ENDPOINT_CONVERT_HPP
      12                 : 
      13                 : #include <boost/corosio/endpoint.hpp>
      14                 : #include <boost/corosio/detail/platform.hpp>
      15                 : 
      16                 : #include <cstring>
      17                 : 
      18                 : #if BOOST_COROSIO_POSIX
      19                 : #include <sys/socket.h>
      20                 : #include <netinet/in.h>
      21                 : #include <arpa/inet.h>
      22                 : #else
      23                 : #ifndef WIN32_LEAN_AND_MEAN
      24                 : #define WIN32_LEAN_AND_MEAN
      25                 : #endif
      26                 : #ifndef NOMINMAX
      27                 : #define NOMINMAX
      28                 : #endif
      29                 : #include <WinSock2.h>
      30                 : #include <Ws2tcpip.h>
      31                 : #endif
      32                 : 
      33                 : namespace boost::corosio::detail {
      34                 : 
      35                 : /** Convert IPv4 endpoint to sockaddr_in.
      36                 : 
      37                 :     @param ep The endpoint to convert. Must be IPv4 (is_v4() == true).
      38                 :     @return A sockaddr_in structure with fields in network byte order.
      39                 : */
      40                 : inline sockaddr_in
      41 HIT        8355 : to_sockaddr_in(endpoint const& ep) noexcept
      42                 : {
      43            8355 :     sockaddr_in sa{};
      44            8355 :     sa.sin_family = AF_INET;
      45            8355 :     sa.sin_port   = htons(ep.port());
      46            8355 :     auto bytes    = ep.v4_address().to_bytes();
      47            8355 :     std::memcpy(&sa.sin_addr, bytes.data(), 4);
      48            8355 :     return sa;
      49                 : }
      50                 : 
      51                 : /** Convert IPv6 endpoint to sockaddr_in6.
      52                 : 
      53                 :     @param ep The endpoint to convert. Must be IPv6 (is_v6() == true).
      54                 :     @return A sockaddr_in6 structure with fields in network byte order.
      55                 : */
      56                 : inline sockaddr_in6
      57              24 : to_sockaddr_in6(endpoint const& ep) noexcept
      58                 : {
      59              24 :     sockaddr_in6 sa{};
      60              24 :     sa.sin6_family = AF_INET6;
      61              24 :     sa.sin6_port   = htons(ep.port());
      62              24 :     auto bytes     = ep.v6_address().to_bytes();
      63              24 :     std::memcpy(&sa.sin6_addr, bytes.data(), 16);
      64              24 :     return sa;
      65                 : }
      66                 : 
      67                 : /** Create endpoint from sockaddr_in.
      68                 : 
      69                 :     @param sa The sockaddr_in structure with fields in network byte order.
      70                 :     @return An endpoint with address and port extracted from sa.
      71                 : */
      72                 : inline endpoint
      73           20057 : from_sockaddr_in(sockaddr_in const& sa) noexcept
      74                 : {
      75                 :     ipv4_address::bytes_type bytes;
      76           20057 :     std::memcpy(bytes.data(), &sa.sin_addr, 4);
      77           20057 :     return endpoint(ipv4_address(bytes), ntohs(sa.sin_port));
      78                 : }
      79                 : 
      80                 : /** Create endpoint from sockaddr_in6.
      81                 : 
      82                 :     @param sa The sockaddr_in6 structure with fields in network byte order.
      83                 :     @return An endpoint with address and port extracted from sa.
      84                 : */
      85                 : inline endpoint
      86              41 : from_sockaddr_in6(sockaddr_in6 const& sa) noexcept
      87                 : {
      88                 :     ipv6_address::bytes_type bytes;
      89              41 :     std::memcpy(bytes.data(), &sa.sin6_addr, 16);
      90              41 :     return endpoint(ipv6_address(bytes), ntohs(sa.sin6_port));
      91                 : }
      92                 : 
      93                 : /** Convert an IPv4 endpoint to an IPv4-mapped IPv6 sockaddr_in6.
      94                 : 
      95                 :     Produces a `sockaddr_in6` with the `::ffff:` prefix, suitable
      96                 :     for passing an IPv4 destination to a dual-stack IPv6 socket.
      97                 : 
      98                 :     @param ep The endpoint to convert. Must be IPv4 (is_v4() == true).
      99                 :     @return A sockaddr_in6 with the IPv4-mapped address.
     100                 : */
     101                 : inline sockaddr_in6
     102               2 : to_v4_mapped_sockaddr_in6(endpoint const& ep) noexcept
     103                 : {
     104               2 :     sockaddr_in6 sa{};
     105               2 :     sa.sin6_family = AF_INET6;
     106               2 :     sa.sin6_port   = htons(ep.port());
     107                 :     // ::ffff:0:0/96 prefix
     108               2 :     sa.sin6_addr.s6_addr[10] = 0xff;
     109               2 :     sa.sin6_addr.s6_addr[11] = 0xff;
     110               2 :     auto bytes               = ep.v4_address().to_bytes();
     111               2 :     std::memcpy(&sa.sin6_addr.s6_addr[12], bytes.data(), 4);
     112               2 :     return sa;
     113                 : }
     114                 : 
     115                 : /** Convert endpoint to sockaddr_storage.
     116                 : 
     117                 :     Dispatches to @ref to_sockaddr_in or @ref to_sockaddr_in6
     118                 :     based on the endpoint's address family.
     119                 : 
     120                 :     @param ep The endpoint to convert.
     121                 :     @param storage Output parameter filled with the sockaddr.
     122                 :     @return The length of the filled sockaddr structure.
     123                 : */
     124                 : inline socklen_t
     125            8369 : to_sockaddr(endpoint const& ep, sockaddr_storage& storage) noexcept
     126                 : {
     127            8369 :     std::memset(&storage, 0, sizeof(storage));
     128            8369 :     if (ep.is_v4())
     129                 :     {
     130            8347 :         auto sa = to_sockaddr_in(ep);
     131            8347 :         std::memcpy(&storage, &sa, sizeof(sa));
     132            8347 :         return sizeof(sa);
     133                 :     }
     134              22 :     auto sa6 = to_sockaddr_in6(ep);
     135              22 :     std::memcpy(&storage, &sa6, sizeof(sa6));
     136              22 :     return sizeof(sa6);
     137                 : }
     138                 : 
     139                 : /** Convert endpoint to sockaddr_storage for a specific socket family.
     140                 : 
     141                 :     When the socket is AF_INET6 and the endpoint is IPv4, the address
     142                 :     is converted to an IPv4-mapped IPv6 address (`::ffff:x.x.x.x`) so
     143                 :     dual-stack sockets can connect to IPv4 destinations.
     144                 : 
     145                 :     @param ep The endpoint to convert.
     146                 :     @param socket_family The address family of the socket (AF_INET or
     147                 :         AF_INET6).
     148                 :     @param storage Output parameter filled with the sockaddr.
     149                 :     @return The length of the filled sockaddr structure.
     150                 : */
     151                 : inline socklen_t
     152            8233 : to_sockaddr(
     153                 :     endpoint const& ep, int socket_family, sockaddr_storage& storage) noexcept
     154                 : {
     155                 :     // IPv4 endpoint on IPv6 socket: use IPv4-mapped address
     156            8233 :     if (ep.is_v4() && socket_family == AF_INET6)
     157                 :     {
     158               2 :         std::memset(&storage, 0, sizeof(storage));
     159               2 :         auto sa6 = to_v4_mapped_sockaddr_in6(ep);
     160               2 :         std::memcpy(&storage, &sa6, sizeof(sa6));
     161               2 :         return sizeof(sa6);
     162                 :     }
     163            8231 :     return to_sockaddr(ep, storage);
     164                 : }
     165                 : 
     166                 : /** Create endpoint from sockaddr_storage.
     167                 : 
     168                 :     Dispatches on `ss_family` to reconstruct the appropriate
     169                 :     IPv4 or IPv6 endpoint.
     170                 : 
     171                 :     @param storage The sockaddr_storage with fields in network byte order.
     172                 :     @return An endpoint with address and port extracted from storage.
     173                 : */
     174                 : inline endpoint
     175           20085 : from_sockaddr(sockaddr_storage const& storage) noexcept
     176                 : {
     177           20085 :     if (storage.ss_family == AF_INET)
     178                 :     {
     179                 :         sockaddr_in sa;
     180           20046 :         std::memcpy(&sa, &storage, sizeof(sa));
     181           20046 :         return from_sockaddr_in(sa);
     182                 :     }
     183              39 :     if (storage.ss_family == AF_INET6)
     184                 :     {
     185                 :         sockaddr_in6 sa6;
     186              39 :         std::memcpy(&sa6, &storage, sizeof(sa6));
     187              39 :         return from_sockaddr_in6(sa6);
     188                 :     }
     189 MIS           0 :     return endpoint{};
     190                 : }
     191                 : 
     192                 : /** Return the native address family for an endpoint.
     193                 : 
     194                 :     @param ep The endpoint to query.
     195                 :     @return `AF_INET` for IPv4, `AF_INET6` for IPv6.
     196                 : */
     197                 : inline int
     198                 : endpoint_family(endpoint const& ep) noexcept
     199                 : {
     200                 :     return ep.is_v6() ? AF_INET6 : AF_INET;
     201                 : }
     202                 : 
     203                 : /** Return the address family of a socket descriptor.
     204                 : 
     205                 :     @param fd The socket file descriptor.
     206                 :     @return AF_INET, AF_INET6, or AF_UNSPEC on failure.
     207                 : */
     208                 : inline int
     209 HIT        8233 : socket_family(
     210                 : #if BOOST_COROSIO_POSIX
     211                 :     int fd
     212                 : #else
     213                 :     std::uintptr_t fd
     214                 : #endif
     215                 :     ) noexcept
     216                 : {
     217            8233 :     sockaddr_storage storage{};
     218            8233 :     socklen_t len = sizeof(storage);
     219            8233 :     if (getsockname(
     220                 : #if BOOST_COROSIO_POSIX
     221                 :             fd,
     222                 : #else
     223                 :             static_cast<SOCKET>(fd),
     224                 : #endif
     225            8233 :             reinterpret_cast<sockaddr*>(&storage), &len) != 0)
     226 MIS           0 :         return AF_UNSPEC;
     227 HIT        8233 :     return storage.ss_family;
     228                 : }
     229                 : 
     230                 : } // namespace boost::corosio::detail
     231                 : 
     232                 : #endif
        

Generated by: LCOV version 2.3