#pragma once #include <util/digest/murmur.h> #include <util/network/ip.h> #include <util/str_stl.h> #include <util/generic/maybe.h> #include <util/generic/variant.h> #ifdef _unix_ #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #endif // _unix_ #include <string.h> #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 #endif // Network (big-endian) byte order using TIp4 = TIpHost; // Network (big-endian) byte order struct TIp6 { char Data[16]; bool operator==(const TIp6& rhs) const { return memcmp(Data, rhs.Data, sizeof(Data)) == 0; } bool operator<(const TIp6& rhs) const { return memcmp(Data, rhs.Data, sizeof(Data)) < 0; } }; template <> struct THash<TIp6> { inline size_t operator()(const TIp6& ip) const { return MurmurHash<size_t>((const void*)ip.Data, 16); } }; static inline TIp6 Ip6FromIp4(TIp4 addr) { TIp6 res; memset(res.Data, 0, sizeof(res.Data)); res.Data[10] = '\xFF'; res.Data[11] = '\xFF'; memcpy(res.Data + 12, &addr, 4); return res; } static inline TIp6 Ip6FromString(const char* ipStr) { TIp6 res; if (inet_pton(AF_INET6, ipStr, &res.Data) == 0) { ythrow TSystemError() << "Failed to convert (" << ipStr << ") to ipv6 address"; } return res; } static inline TMaybe<TIp6> TryParseIp6FromString(const char* ipStr) { TIp6 res; if (inet_pton(AF_INET6, ipStr, &res.Data) == 0) { return Nothing(); } return res; } static inline char* Ip6ToString(const TIp6& ip, char* buf, size_t len) { if (!inet_ntop(AF_INET6, (void*)&ip.Data, buf, (socklen_t)len)) { ythrow TSystemError() << "Failed to get ipv6 address string"; } return buf; } static inline TString Ip6ToString(const TIp6& ip) { char buf[INET6_ADDRSTRLEN]; return TString(Ip6ToString(ip, buf, sizeof(buf))); } template <> inline void Out<TIp6>(IOutputStream& os, const TIp6& a) { os << Ip6ToString(a); } using TIp4Or6 = std::variant<TIp4, TIp6>; static inline TIp4Or6 Ip4Or6FromString(const char* ipStr) { const char* c = ipStr; for (; *c; ++c) { if (*c == '.') { return IpFromString(ipStr); } if (*c == ':') { return Ip6FromString(ipStr); } } ythrow TSystemError() << "Failed to convert (" << ipStr << ") to ipv4 or ipv6 address"; } static inline TString Ip4Or6ToString(const TIp4Or6& ip) { if (std::holds_alternative<TIp6>(ip)) { return Ip6ToString(std::get<TIp6>(ip)); } else { return IpToString(std::get<TIp4>(ip)); } } // for TIp4 or TIp6, not TIp4Or6 template <class TIp> struct TIpCompare { bool Less(const TIp& l, const TIp& r) const { return memcmp(&l, &r, sizeof(TIp)) < 0; } bool LessEqual(const TIp& l, const TIp& r) const { return memcmp(&l, &r, sizeof(TIp)) <= 0; } bool operator()(const TIp& l, const TIp& r) const { return Less(l, r); } };