diff --git a/qse/include/qse/cmn/ipad.h b/qse/include/qse/cmn/ipad.h index fd94c314..eba15718 100644 --- a/qse/include/qse/cmn/ipad.h +++ b/qse/include/qse/cmn/ipad.h @@ -45,8 +45,14 @@ struct qse_ip6ad_t qse_uint8_t value[16]; }; -#define QSE_IP4AD_IS_LOOPBACK(addr) ((((addr)->value) & QSE_CONST_HTON32(0xFF000000)) == QSE_CONST_HTON32(0x7F000000)) +/* 127.0.0.0/8 */ +#define QSE_IP4AD_IS_LOOPBACK(addr) ((((addr)->value) & QSE_CONST_HTON32(0xFF000000u)) == QSE_CONST_HTON32(0x7F000000u)) +/* 169.254.0.0/16 */ +#define QSE_IP4AD_IS_LINK_LOCAL(addr) ((((addr)->value) & QSE_CONST_HTON32(0xFFFF0000u)) == QSE_CONST_HTON32(0xA9FE0000u)) +/* 224.0.0.0/4 */ +#define QSE_IP4AD_IS_MULTICAST(addr) ((((addr)->value) & QSE_CONST_HTON32(0xF0000000u)) == QSE_CONST_HTON32(0xE0000000u)) +/* ::1 */ #define QSE_IP6AD_IS_LOOPBACK(addr) \ ((addr)->value[0] == 0 && (addr)->value[1] == 0 && \ (addr)->value[2] == 0 && (addr)->value[3] == 0 && \ @@ -57,11 +63,13 @@ struct qse_ip6ad_t (addr)->value[12] == 0 && (addr)->value[13] == 0 && \ (addr)->value[14] == 0 && (addr)->value[15] == 1) -// FE80::/10 + +/* FE80::/10 */ #define QSE_IP6AD_IS_LINK_LOCAL(addr) (this->value[0] == 0xFE && (this->value[1] & 0xC0) == 0x80) -// FEC0::/10 +/* FEC0::/10 */ #define QSE_IP6AD_IS_SITE_LOCAL(addr) (this->value[0] == 0xFE && (this->value[1] & 0xC0) == 0xC0) +/* FF00::/8 */ #define QSE_IP6AD_IS_MULTICAST(addr) ((addr)->value[0] == 0xFF) #define QSE_IP6AD_IS_MULTICAST_LINK_LOCAL(addr) ((addr)->value[0] == 0xFF && ((addr)->value[1] & 0x0F) == 0x02) #define QSE_IP6AD_IS_MULTICAST_SITE_LOCAL(addr) ((addr)->value[0] == 0xFF && ((addr)->value[1] & 0x0F) == 0x05) diff --git a/qse/include/qse/si/SocketAddress.hpp b/qse/include/qse/si/SocketAddress.hpp index 5ee16e30..0b7c4680 100644 --- a/qse/include/qse/si/SocketAddress.hpp +++ b/qse/include/qse/si/SocketAddress.hpp @@ -38,6 +38,14 @@ QSE_BEGIN_NAMESPACE(QSE) class SocketAddress { public: + enum + { + MAX_IP4AD_STR_LEN = 15, // nnn.nnn.nnn.nnn + MAX_IP6AD_STR_LEN = 45, // XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX, XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:nnn.nnn.nnn.nnn + MAX_IP4AD_PORT_STR_LEN = 21, // nnn.nnn.nnn.nnn:AAAAA + MAX_IP6AD_PORT_STR_LEN = 53 // [....]:AAAAA + }; + SocketAddress () QSE_CPP_NOEXCEPT; SocketAddress (int family) QSE_CPP_NOEXCEPT; SocketAddress (const qse_skad_t* skad) QSE_CPP_NOEXCEPT; @@ -93,10 +101,11 @@ public: int resolve (const qse_wchar_t* service, const qse_wchar_t* host, int type) QSE_CPP_NOEXCEPT { return this->resolve(service, host, this->getFamily(), type); } bool isLoopBack () const QSE_CPP_NOEXCEPT; - // TODO: isLinkLocal() const QSE_CPP_NOEXCEPT - // TODO: isSiteLocal() const QSE_CPP_NOEXCEPT - // TODO: isV4Mapped() const QSE_CPP_NOEXCEPT - // + bool isLinkLocal() const QSE_CPP_NOEXCEPT; + bool isSiteLocal() const QSE_CPP_NOEXCEPT; + bool isMulticast() const QSE_CPP_NOEXCEPT; + bool isV4Mapped() const QSE_CPP_NOEXCEPT; + //TODO: bool isInIpSubnet (const qse_ip4ad_t* addr, int prefix) const QSE_CPP_NOEXCEPT; //TODO: bool isInIpSubnet (const qse_ip6ad_t* addr, int prefix) const QSE_CPP_NOEXCEPT; bool isInIpSubnet (const qse_nwad_t* addr, int prefix) const QSE_CPP_NOEXCEPT; diff --git a/qse/lib/si/SocketAddress.cpp b/qse/lib/si/SocketAddress.cpp index 7fcb743b..6219cfde 100644 --- a/qse/lib/si/SocketAddress.cpp +++ b/qse/lib/si/SocketAddress.cpp @@ -378,21 +378,90 @@ bool SocketAddress::isLoopBack () const QSE_CPP_NOEXCEPT { case AF_INET: { + // 127.0.0.0/8 struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad; - return v4->sin_addr.s_addr == QSE_CONST_HTON32(0x7F000001); + return (v4->sin_addr.s_addr & QSE_CONST_HTON32(0xFF000000u)) == QSE_CONST_HTON32(0x7F000000u); } case AF_INET6: { struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad; qse_uint32_t* x = (qse_uint32_t*)v6->sin6_addr.s6_addr; // TODO: is this alignment safe? - return x[0] == 0 && x[1] == 0 && x[2] == 0 && x[3] == 1; + return (x[0] == 0 && x[1] == 0 && x[2] == 0 && x[3] == QSE_CONST_HTON32(1)) || + (this->isV4Mapped() && (x[3] & QSE_CONST_HTON32(0xFF000000u)) == QSE_CONST_HTON32(0x7F000000u)); } } return false; } +bool SocketAddress::isLinkLocal() const QSE_CPP_NOEXCEPT +{ + switch (FAMILY(&this->skad)) + { + case AF_INET: + { + // 169.254.0.0/16 + struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad; + return (v4->sin_addr.s_addr & QSE_CONST_HTON32(0xFFFF0000u)) == QSE_CONST_HTON32(0xA9FE0000u); + } + + case AF_INET6: + { + // FE80::/10 + struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad; + return v6->sin6_addr.s6_addr[0] == 0xFE && (v6->sin6_addr.s6_addr[1] & 0xC0) == 0x80; + } + } + + return false; +} + +bool SocketAddress::isSiteLocal() const QSE_CPP_NOEXCEPT +{ + if (FAMILY(&this->skad) != AF_INET6) return false; + + // FEC0::/10 + struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad; + return v6->sin6_addr.s6_addr[0] == 0xFE && (v6->sin6_addr.s6_addr[1] & 0xC0) == 0xC0; +} + +bool SocketAddress::isMulticast() const QSE_CPP_NOEXCEPT +{ + switch (FAMILY(&this->skad)) + { + case AF_INET: + { + // 224.0.0.0/4 + struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad; + return (v4->sin_addr.s_addr & QSE_CONST_HTON32(0xF0000000u)) == QSE_CONST_HTON32(0xE0000000u); + } + + case AF_INET6: + { + // FF00::/8 + struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad; + return v6->sin6_addr.s6_addr[0] == 0xFF; + } + } + + return false; +} + +bool SocketAddress::isV4Mapped() const QSE_CPP_NOEXCEPT +{ + if (FAMILY(&this->skad) != AF_INET6) return false; + + struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad; + return v6->sin6_addr.s6_addr[0] == 0x00 && v6->sin6_addr.s6_addr[1] == 0x00 && + v6->sin6_addr.s6_addr[2] == 0x00 && v6->sin6_addr.s6_addr[3] == 0x00 && + v6->sin6_addr.s6_addr[4] == 0x00 && v6->sin6_addr.s6_addr[5] == 0x00 && + v6->sin6_addr.s6_addr[6] == 0x00 && v6->sin6_addr.s6_addr[7] == 0x00 && + v6->sin6_addr.s6_addr[8] == 0x00 && v6->sin6_addr.s6_addr[9] == 0x00 && + v6->sin6_addr.s6_addr[10] == 0xFF && v6->sin6_addr.s6_addr[11] == 0xFF; +} + + bool SocketAddress::isInIpSubnet (const qse_nwad_t* addr, int prefix) const QSE_CPP_NOEXCEPT { switch (addr->type)