LCOV - code coverage report
Current view: top level - corosio/detail - endpoint_convert.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 96.7 % 60 58 2
Test Date: 2026-02-25 01:27:20 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_DETAIL_ENDPOINT_CONVERT_HPP
      11                 : #define BOOST_COROSIO_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        7814 : to_sockaddr_in(endpoint const& ep) noexcept
      42                 : {
      43            7814 :     sockaddr_in sa{};
      44            7814 :     sa.sin_family = AF_INET;
      45            7814 :     sa.sin_port   = htons(ep.port());
      46            7814 :     auto bytes    = ep.v4_address().to_bytes();
      47            7814 :     std::memcpy(&sa.sin_addr, bytes.data(), 4);
      48            7814 :     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           18551 : from_sockaddr_in(sockaddr_in const& sa) noexcept
      74                 : {
      75                 :     ipv4_address::bytes_type bytes;
      76           18551 :     std::memcpy(bytes.data(), &sa.sin_addr, 4);
      77           18551 :     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            7828 : to_sockaddr( endpoint const& ep, sockaddr_storage& storage ) noexcept
     126                 : {
     127            7828 :     std::memset( &storage, 0, sizeof( storage ) );
     128            7828 :     if( ep.is_v4() )
     129                 :     {
     130            7806 :         auto sa = to_sockaddr_in( ep );
     131            7806 :         std::memcpy( &storage, &sa, sizeof( sa ) );
     132            7806 :         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            7692 : to_sockaddr(
     153                 :     endpoint const& ep,
     154                 :     int socket_family,
     155                 :     sockaddr_storage& storage) noexcept
     156                 : {
     157                 :     // IPv4 endpoint on IPv6 socket: use IPv4-mapped address
     158            7692 :     if (ep.is_v4() && socket_family == AF_INET6)
     159                 :     {
     160               2 :         std::memset(&storage, 0, sizeof(storage));
     161               2 :         auto sa6 = to_v4_mapped_sockaddr_in6(ep);
     162               2 :         std::memcpy(&storage, &sa6, sizeof(sa6));
     163               2 :         return sizeof(sa6);
     164                 :     }
     165            7690 :     return to_sockaddr(ep, storage);
     166                 : }
     167                 : 
     168                 : /** Create endpoint from sockaddr_storage.
     169                 : 
     170                 :     Dispatches on `ss_family` to reconstruct the appropriate
     171                 :     IPv4 or IPv6 endpoint.
     172                 : 
     173                 :     @param storage The sockaddr_storage with fields in network byte order.
     174                 :     @return An endpoint with address and port extracted from storage.
     175                 : */
     176                 : inline endpoint
     177           18579 : from_sockaddr( sockaddr_storage const& storage ) noexcept
     178                 : {
     179           18579 :     if( storage.ss_family == AF_INET )
     180                 :     {
     181                 :         sockaddr_in sa;
     182           18540 :         std::memcpy( &sa, &storage, sizeof( sa ) );
     183           18540 :         return from_sockaddr_in( sa );
     184                 :     }
     185              39 :     if( storage.ss_family == AF_INET6 )
     186                 :     {
     187                 :         sockaddr_in6 sa6;
     188              39 :         std::memcpy( &sa6, &storage, sizeof( sa6 ) );
     189              39 :         return from_sockaddr_in6( sa6 );
     190                 :     }
     191 MIS           0 :     return endpoint{};
     192                 : }
     193                 : 
     194                 : /** Return the native address family for an endpoint.
     195                 : 
     196                 :     @param ep The endpoint to query.
     197                 :     @return `AF_INET` for IPv4, `AF_INET6` for IPv6.
     198                 : */
     199                 : inline int
     200                 : endpoint_family( endpoint const& ep ) noexcept
     201                 : {
     202                 :     return ep.is_v6() ? AF_INET6 : AF_INET;
     203                 : }
     204                 : 
     205                 : /** Return the address family of a socket descriptor.
     206                 : 
     207                 :     @param fd The socket file descriptor.
     208                 :     @return AF_INET, AF_INET6, or AF_UNSPEC on failure.
     209                 : */
     210                 : inline int
     211 HIT        7692 : socket_family(
     212                 : #if BOOST_COROSIO_POSIX
     213                 :     int fd
     214                 : #else
     215                 :     std::uintptr_t fd
     216                 : #endif
     217                 :     ) noexcept
     218                 : {
     219            7692 :     sockaddr_storage storage{};
     220            7692 :     socklen_t len = sizeof(storage);
     221            7692 :     if (getsockname(
     222                 : #if BOOST_COROSIO_POSIX
     223                 :             fd,
     224                 : #else
     225                 :             static_cast<SOCKET>(fd),
     226                 : #endif
     227            7692 :             reinterpret_cast<sockaddr*>(&storage), &len) != 0)
     228 MIS           0 :         return AF_UNSPEC;
     229 HIT        7692 :     return storage.ss_family;
     230                 : }
     231                 : 
     232                 : } // namespace boost::corosio::detail
     233                 : 
     234                 : #endif
        

Generated by: LCOV version 2.3