10#include <system_error>
13#include <sys/socket.h>
15#include <fmt/format.h>
17#include <userver/utils/zstring_view.hpp>
19USERVER_NAMESPACE_BEGIN
27template <std::size_t N>
28class AddressBase
final {
29 static_assert(N == 4 || N == 16,
"Address can only be 4 or 16 bytes size");
32 static constexpr std::size_t kAddressSize = N;
33 using BytesType = std::array<
unsigned char, N>;
35 AddressBase()
noexcept : address_({0}) {}
36 explicit AddressBase(
const BytesType& address)
41 const BytesType&
GetBytes()
const noexcept {
return address_; }
43 friend bool operator==(
const AddressBase<N>& a1,
const AddressBase<N>& a2)
noexcept {
44 return a1.address_ == a2.address_;
47 friend bool operator!=(
const AddressBase<N>& a1,
const AddressBase<N>& a2)
noexcept {
48 return a1.address_ != a2.address_;
58using AddressV4 = AddressBase<4>;
63using AddressV6 = AddressBase<16>;
66inline constexpr bool kIsAddressType = std::is_same_v<T, AddressV4> || std::is_same_v<T, AddressV6>;
84template <
typename Address,
typename = std::enable_if_t<kIsAddressType<Address>>>
85class NetworkBase
final {
87 using AddressType = Address;
88 static constexpr unsigned char kMaximumPrefixLength = std::is_same_v<Address, AddressV4> ? 32 : 128;
90 NetworkBase()
noexcept =
default;
92 NetworkBase(
const AddressType& address,
unsigned short prefix_length)
94 prefix_length_(prefix_length)
96 if (prefix_length > kMaximumPrefixLength) {
97 throw std::out_of_range(fmt::format(
98 "{} prefix length is too large",
99 std::is_same_v<Address, AddressV4> ?
"NetworkV4" :
"NetworkV6"
112 const auto network_bytes = address_.GetBytes();
113 const auto address_bytes = address.GetBytes();
115 std::uint8_t diff = 0;
116 for (std::size_t byte_index = 0; byte_index < kMaximumPrefixLength / 8; ++byte_index) {
117 std::uint8_t mask_byte = 0;
118 if (byte_index == prefix_length_ / 8) {
119 mask_byte = ~((1 << (8 - prefix_length_ % 8)) - 1);
121 if (byte_index < prefix_length_ / 8) {
125 diff |= (network_bytes[byte_index] ^ address_bytes[byte_index]) & mask_byte;
130 friend bool operator==(
const NetworkBase<Address>& a,
const NetworkBase<Address>& b)
noexcept {
131 return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;
134 friend bool operator!=(
const NetworkBase<Address>& a,
const NetworkBase<Address>& b)
noexcept {
return !(a == b); }
137 AddressType address_;
138 unsigned char prefix_length_ = 0;
144using NetworkV4 = NetworkBase<AddressV4>;
149using NetworkV6 = NetworkBase<AddressV6>;
178class InetNetwork
final {
180 enum class AddressFamily :
unsigned char { kIPv4 = AF_INET, kIPv6 = AF_INET6 };
184 InetNetwork(std::vector<
unsigned char>&& bytes,
unsigned char prefix_length, AddressFamily address_family);
187 const std::vector<
unsigned char>&
GetBytes()
const noexcept {
return bytes_; }
195 friend bool operator==(
const InetNetwork& lhs,
const InetNetwork& rhs) {
196 return lhs.address_family_ == rhs.address_family_ && lhs.prefix_length_ == rhs.prefix_length_ &&
197 lhs.bytes_ == rhs.bytes_;
200 friend bool operator!=(
const InetNetwork& lhs,
const InetNetwork& rhs) {
return !operator==(lhs, rhs); }
203 std::vector<
unsigned char> bytes_;
204 unsigned char prefix_length_;
205 AddressFamily address_family_;
221class AddressSystemError
final :
public std::exception {
223 AddressSystemError(std::error_code code, std::string_view msg)
229 const std::error_code&
Code()
const {
return code_; }
231 const char* what()
const noexcept final {
return msg_.c_str(); }
235 std::error_code code_;