#include "netaddr.h" #include #include namespace NBus { const char* ToCString(EIpVersion ipVersion) { switch (ipVersion) { case EIP_VERSION_ANY: return "EIP_VERSION_ANY"; case EIP_VERSION_4: return "EIP_VERSION_4"; case EIP_VERSION_6: return "EIP_VERSION_6"; } Y_ABORT(); } int ToAddrFamily(EIpVersion ipVersion) { switch (ipVersion) { case EIP_VERSION_ANY: return AF_UNSPEC; case EIP_VERSION_4: return AF_INET; case EIP_VERSION_6: return AF_INET6; } Y_ABORT(); } class TNetworkAddressRef: private TNetworkAddress, public TAddrInfo { public: TNetworkAddressRef(const TNetworkAddress& na, const TAddrInfo& ai) : TNetworkAddress(na) , TAddrInfo(ai) { } }; static bool Compare(const IRemoteAddr& l, const IRemoteAddr& r) noexcept { if (l.Addr()->sa_family != r.Addr()->sa_family) { return false; } switch (l.Addr()->sa_family) { case AF_INET: { return memcmp(&(((const sockaddr_in*)l.Addr())->sin_addr), &(((const sockaddr_in*)r.Addr())->sin_addr), sizeof(in_addr)) == 0 && ((const sockaddr_in*)l.Addr())->sin_port == ((const sockaddr_in*)r.Addr())->sin_port; } case AF_INET6: { return memcmp(&(((const sockaddr_in6*)l.Addr())->sin6_addr), &(((const sockaddr_in6*)r.Addr())->sin6_addr), sizeof(in6_addr)) == 0 && ((const sockaddr_in6*)l.Addr())->sin6_port == ((const sockaddr_in6*)r.Addr())->sin6_port; } } return memcmp(l.Addr(), r.Addr(), Min(l.Len(), r.Len())) == 0; } TNetAddr::TNetAddr() : Ptr(new TOpaqueAddr) { } TNetAddr::TNetAddr(TAutoPtr addr) : Ptr(addr) { Y_ABORT_UNLESS(!!Ptr); } namespace { using namespace NAddr; const char* Describe(EIpVersion version) { switch (version) { case EIP_VERSION_4: return "ipv4 address"; case EIP_VERSION_6: return "ipv6 address"; case EIP_VERSION_ANY: return "any address"; default: Y_ABORT("unreachable"); } } TAutoPtr MakeAddress(const TNetworkAddress& na, EIpVersion requireVersion, EIpVersion preferVersion) { TAutoPtr addr; for (TNetworkAddress::TIterator it = na.Begin(); it != na.End(); ++it) { if (IsFamilyAllowed(it->ai_family, requireVersion)) { if (IsFamilyAllowed(it->ai_family, preferVersion)) { return new TNetworkAddressRef(na, &*it); } else if (!addr) { addr.Reset(new TNetworkAddressRef(na, &*it)); } } } return addr; } TAutoPtr MakeAddress(TStringBuf host, int port, EIpVersion requireVersion, EIpVersion preferVersion) { TString hostString(host); TNetworkAddress na(hostString, port); return MakeAddress(na, requireVersion, preferVersion); } TAutoPtr MakeAddress(const char* hostPort, EIpVersion requireVersion, EIpVersion preferVersion) { const char* portStr = strchr(hostPort, ':'); if (!portStr) { ythrow TNetAddr::TError() << "port not specified in " << hostPort; } int port = atoi(portStr + 1); TNetworkAddress na(TString(hostPort, portStr), port); return MakeAddress(na, requireVersion, preferVersion); } } TNetAddr::TNetAddr(const char* hostPort, EIpVersion requireVersion /*= EIP_VERSION_ANY*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/) : Ptr(MakeAddress(hostPort, requireVersion, preferVersion)) { if (!Ptr) { ythrow TNetAddr::TError() << "cannot resolve " << hostPort << " into " << Describe(requireVersion); } } TNetAddr::TNetAddr(TStringBuf host, int port, EIpVersion requireVersion /*= EIP_VERSION_ANY*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/) : Ptr(MakeAddress(host, port, requireVersion, preferVersion)) { if (!Ptr) { ythrow TNetAddr::TError() << "cannot resolve " << host << ":" << port << " into " << Describe(requireVersion); } } TNetAddr::TNetAddr(const TNetworkAddress& na, EIpVersion requireVersion /*= EIP_VERSION_ANY*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/) : Ptr(MakeAddress(na, requireVersion, preferVersion)) { if (!Ptr) { ythrow TNetAddr::TError() << "cannot resolve into " << Describe(requireVersion); } } TNetAddr::TNetAddr(const TNetworkAddress& na, const TAddrInfo& ai) : Ptr(new TNetworkAddressRef(na, ai)) { } const sockaddr* TNetAddr::Addr() const { return Ptr->Addr(); } socklen_t TNetAddr::Len() const { return Ptr->Len(); } int TNetAddr::GetPort() const { switch (Ptr->Addr()->sa_family) { case AF_INET: return InetToHost(((sockaddr_in*)Ptr->Addr())->sin_port); case AF_INET6: return InetToHost(((sockaddr_in6*)Ptr->Addr())->sin6_port); default: Y_ABORT("unknown AF: %d", (int)Ptr->Addr()->sa_family); throw 1; } } bool TNetAddr::IsIpv4() const { return Ptr->Addr()->sa_family == AF_INET; } bool TNetAddr::IsIpv6() const { return Ptr->Addr()->sa_family == AF_INET6; } bool TNetAddr::operator==(const TNetAddr& rhs) const { return Ptr == rhs.Ptr || Compare(*Ptr, *rhs.Ptr); } } template <> void Out(IOutputStream& out, const NBus::TNetAddr& addr) { Out(out, addr); }