network_serialization.hpp
1 // SPDX-FileCopyrightText: Copyright (C) 2025 Marek Küthe <m.k@mk16.de> 2 // 3 // SPDX-License-Identifier: GPL-3.0-or-later 4 5 #ifndef NETWORK_SERIALIZATION 6 #define NETWORK_SERIALIZATION 7 8 #include <algorithm> 9 #include <array> 10 #include <bit> 11 #include <concepts> 12 #include <cstdint> 13 #include <boost/asio.hpp> 14 15 namespace NetworkSerialization 16 { 17 template<std::integral T> 18 [[gnu::const]] constexpr T to_bigendian(const T host) 19 requires(std::endian::native == std::endian::big || 20 std::endian::native == std::endian::little) 21 { 22 if constexpr (std::endian::native == std::endian::little) 23 { 24 return std::byteswap(host); 25 } 26 else 27 { 28 return host; 29 } 30 } 31 32 template<std::integral T> 33 [[gnu::const]] constexpr T to_littleendian(const T host) 34 requires(std::endian::native == std::endian::big || 35 std::endian::native == std::endian::little) 36 { 37 if constexpr (std::endian::native == std::endian::big) 38 { 39 return std::byteswap(host); 40 } 41 else 42 { 43 return host; 44 } 45 } 46 47 template<typename T> 48 [[gnu::const]] constexpr std::array<unsigned char, sizeof(T)> 49 to_byte_array(const T i) 50 requires(std::is_trivially_copyable_v<T>) 51 { 52 return std::bit_cast<std::array<unsigned char, sizeof(T)>>(i); 53 } 54 55 [[gnu::pure]] inline std::array<unsigned char, 128> 56 ipv6_to_sockaddr_storage(const boost::asio::ip::address_v6& address, 57 const uint16_t port) 58 { 59 std::array<unsigned char, 128> result = {}; 60 result.fill('\0'); 61 62 auto * it = result.begin(); 63 64 /* 10 */ 65 constexpr uint16_t ipv6_type_int = 10; 66 constexpr std::array<unsigned char, 2> ipv6_type = 67 to_byte_array(to_littleendian(ipv6_type_int)); 68 it = std::ranges::copy(ipv6_type, it).out; 69 70 /* P */ 71 const std::array<unsigned char, 2> port_bytes = 72 to_byte_array(to_bigendian(port)); 73 it = std::ranges::copy(port_bytes, it).out; 74 75 std::advance(it, 4); 76 77 /* IPv6 */ 78 const std::array<unsigned char, 16> ipv6_bytes = address.to_bytes(); 79 std::ranges::copy(ipv6_bytes, it); 80 81 return result; 82 } 83 84 [[gnu::pure]] inline std::array<unsigned char, 128> 85 ipv4_to_sockaddr_storage(const boost::asio::ip::address_v4& address, 86 const uint16_t port) 87 { 88 std::array<unsigned char, 128> result = {}; 89 result.fill('\0'); 90 91 auto * it = result.begin(); 92 93 /* 2 */ 94 constexpr uint16_t ipv4_type_int = 2; 95 constexpr std::array<unsigned char, 2> ipv4_type = 96 to_byte_array(to_littleendian(ipv4_type_int)); 97 it = std::ranges::copy(ipv4_type, it).out; 98 99 /* P */ 100 const std::array<unsigned char, 2> port_bytes = 101 to_byte_array(to_bigendian(port)); 102 it = std::ranges::copy(port_bytes, it).out; 103 104 std::advance(it, 4); 105 106 /* IPv4 */ 107 const std::array<unsigned char, 4> ipv4_bytes = address.to_bytes(); 108 std::ranges::copy(ipv4_bytes, it); 109 110 return result; 111 } 112 } // namespace NetworkSerialization 113 114 #endif