/* -*- C++ -*- * Copyright (C) 2003 Thiago Macieira * * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "klocale.h" #include "ksocketaddress.h" #include "netsupp.h" using namespace KNetwork; #if 0 class KIpAddress_localhostV4 : public KIpAddress { public: KIpAddress_localhostV4() { *m_data = htonl(0x7f000001); m_version = 4; } }; class KIpAddress_localhostV6 : public KIpAddress { public: KIpAddress_localhostV6() : KIpAddress(0L, 6) { m_data[3] = htonl(1); } }; #endif static const char localhostV4_data[] = { 127, 0, 0, 1 }; static const char localhostV6_data[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1 }; const KIpAddress KIpAddress::localhostV4(&localhostV4_data, 4); const KIpAddress KIpAddress::localhostV6(&localhostV6_data, 6); const KIpAddress KIpAddress::anyhostV4(0L, 4); const KIpAddress KIpAddress::anyhostV6(0L, 6); // helper function to test if an IPv6 v4-mapped address is equal to its IPv4 counterpart static bool check_v4mapped(const TQ_UINT32* v6addr, TQ_UINT32 v4addr) { // check that the v6 is a v4-mapped address if (!(v6addr[0] == 0 && v6addr[1] == 0 && v6addr[2] == htonl(0x0000ffff))) return false; // not a v4-mapped address return v6addr[3] == v4addr; } // copy operator KIpAddress& KIpAddress::operator =(const KIpAddress& other) { m_version = other.m_version; if (m_version == 4 || m_version == 6) memcpy(m_data, other.m_data, sizeof(m_data)); return *this; } // comparison bool KIpAddress::compare(const KIpAddress& other, bool checkMapped) const { if (m_version == other.m_version) switch (m_version) { case 0: // both objects are empty return true; case 4: // IPv4 address return *m_data == *other.m_data; case 6: // IPv6 address // they are 128-bit long, that is, 16 bytes return memcmp(m_data, other.m_data, 16) == 0; } if (checkMapped) { // check the possibility of a v4-mapped address being compared to an IPv4 one if (m_version == 6 && other.m_version == 4 && check_v4mapped(m_data, *other.m_data)) return true; if (other.m_version == 6 && m_version == 4 && check_v4mapped(other.m_data, *m_data)) return true; } return false; } // sets the address to the given address bool KIpAddress::setAddress(const TQString& address) { m_version = 0; // try to guess the address version if (address.find(':') != -1) { #ifdef AF_INET6 // guessing IPv6 TQ_UINT32 buf[4]; if (inet_pton(AF_INET6, address.latin1(), buf)) { memcpy(m_data, buf, sizeof(m_data)); m_version = 6; return true; } #endif return false; } else { TQ_UINT32 buf; if (inet_pton(AF_INET, address.latin1(), &buf)) { *m_data = buf; m_version = 4; return true; } return false; } return false; // can never happen! } bool KIpAddress::setAddress(const char* address) { return setAddress(TQString::fromLatin1(address)); } // set from binary data bool KIpAddress::setAddress(const void* raw, int version) { // this always succeeds // except if version is invalid if (version != 4 && version != 6) return false; m_version = version; if (raw != 0L) memcpy(m_data, raw, version == 4 ? 4 : 16); else memset(m_data, 0, 16); return true; } // presentation form TQString KIpAddress::toString() const { char buf[sizeof "1111:2222:3333:4444:5555:6666:255.255.255.255" + 2]; buf[0] = '\0'; switch (m_version) { case 4: inet_ntop(AF_INET, m_data, buf, sizeof(buf) - 1); return TQString::fromLatin1(buf); case 6: #ifdef AF_INET6 inet_ntop(AF_INET6, m_data, buf, sizeof(buf) - 1); #endif return TQString::fromLatin1(buf); } return TQString::null; } TQ_UINT32 KIpAddress::hostIPv4Addr(bool convertMapped) const { TQ_UINT32 addr = IPv4Addr(convertMapped); return ntohl(addr); } /* * An IPv6 socket address * This is taken from RFC 2553. */ struct our_sockaddr_in6 { # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN TQ_UINT8 sin6_len; TQ_UINT8 sin6_family; # else //!HAVE_STRUCT_SOCKADDR_SA_LEN TQ_UINT16 sin6_family; # endif TQ_UINT16 sin6_port; /* RFC says in_port_t */ TQ_UINT32 sin6_flowinfo; TQ_UINT8 sin6_addr[16]; // 24 bytes up to here TQ_UINT32 sin6_scope_id; // 28 bytes total }; // useful definitions #define MIN_SOCKADDR_LEN sizeof(TQ_UINT16) #define SOCKADDR_IN_LEN sizeof(sockaddr_in) #define MIN_SOCKADDR_IN6_LEN ((unsigned long) &(((our_sockaddr_in6*)0)->sin6_scope_id)) #define SOCKADDR_IN6_LEN sizeof(our_sockaddr_in6) #define MIN_SOCKADDR_UN_LEN (sizeof(TQ_UINT16) + sizeof(char)) class KNetwork::KSocketAddressData { public: /* * Note: maybe this should be virtual * But since the data is shared via the d pointer, it doesn't really matter * what one class sees, so will the other */ class QMixSocketAddressRef : public KInetSocketAddress, public KUnixSocketAddress { public: QMixSocketAddressRef(KSocketAddressData* d) : KInetSocketAddress(d), KUnixSocketAddress(d) { } }; QMixSocketAddressRef ref; union { struct sockaddr *generic; struct sockaddr_in *in; struct our_sockaddr_in6 *in6; struct sockaddr_un *un; } addr; TQ_UINT16 curlen, reallen; KSocketAddressData() : ref(this) { addr.generic = 0L; curlen = 0; tqinvalidate(); } ~KSocketAddressData() { if (addr.generic != 0L) free(addr.generic); } inline bool invalid() const { return reallen == 0; } inline void tqinvalidate() { reallen = 0; } void dup(const sockaddr* sa, TQ_UINT16 len, bool clear = true); void makeipv4() { short oldport = 0; if (!invalid()) switch (addr.generic->sa_family) { case AF_INET: return; // nothing to do here #ifdef AF_INET6 case AF_INET6: oldport = addr.in6->sin6_port; break; #endif } // create new space dup(0L, SOCKADDR_IN_LEN); addr.in->sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN addr.in->sin_len = SOCKADDR_IN_LEN; #endif addr.in->sin_port = oldport; } void makeipv6() { short oldport = 0; if (!invalid()) switch (addr.generic->sa_family) { case AF_INET: oldport = addr.in->sin_port; break; #ifdef AF_INET6 case AF_INET6: return; // nothing to do here #endif } // make room dup(0L, SOCKADDR_IN6_LEN); #ifdef AF_INET6 addr.in6->sin6_family = AF_INET6; #endif #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN addr.in6->sin6_len = SOCKADDR_IN6_LEN; #endif addr.in6->sin6_port = oldport; // sin6_scope_id and sin6_flowid are zero } }; // create duplicates of void KSocketAddressData::dup(const sockaddr* sa, TQ_UINT16 len, bool clear) { if (len < MIN_SOCKADDR_LEN) { // certainly invalid tqinvalidate(); return; } if (sa && ((sa->sa_family == AF_INET && len < SOCKADDR_IN_LEN) || #ifdef AF_INET6 (sa->sa_family == AF_INET6 && len < MIN_SOCKADDR_IN6_LEN) || #endif (sa->sa_family == AF_UNIX && len < MIN_SOCKADDR_UN_LEN))) { // also invalid tqinvalidate(); return; } // good reallen = len; if (len > curlen) { if (len < 32) curlen = 32; // big enough for sockaddr_in and sockaddr_in6 else curlen = len; addr.generic = (sockaddr*)realloc(addr.generic, curlen); } if (sa != 0L) { memcpy(addr.generic, sa, len); // copy // now, normalise the data if (addr.generic->sa_family == AF_INET) reallen = SOCKADDR_IN_LEN; // no need to be larger #ifdef AF_INET6 else if (addr.generic->sa_family == AF_INET6) { // set the extra field (sin6_scope_id) // the buffer is never smaller than 32 bytes, so this is always // allowed if (reallen < SOCKADDR_IN6_LEN) addr.in6->sin6_scope_id = 0; reallen = SOCKADDR_IN6_LEN; } #endif else if (addr.generic->sa_family == AF_UNIX) reallen = MIN_SOCKADDR_UN_LEN + strlen(addr.un->sun_path); } else if (clear) { memset(addr.generic, 0, len); addr.generic->sa_family = AF_UNSPEC; } } // default constructor KSocketAddress::KSocketAddress() : d(new KSocketAddressData) { } // constructor from binary data KSocketAddress::KSocketAddress(const sockaddr *sa, TQ_UINT16 len) : d(new KSocketAddressData) { setAddress(sa, len); } KSocketAddress::KSocketAddress(const KSocketAddress& other) : d(new(KSocketAddressData)) { *this = other; } KSocketAddress::KSocketAddress(KSocketAddressData *d2) : d(d2) { } KSocketAddress::~KSocketAddress() { // prevent double-deletion, since we're already being deleted if (d) { d->ref.KInetSocketAddress::d = 0L; d->ref.KUnixSocketAddress::d = 0L; delete d; } } KSocketAddress& KSocketAddress::operator =(const KSocketAddress& other) { if (other.d && !other.d->invalid()) d->dup(other.d->addr.generic, other.d->reallen); else d->tqinvalidate(); return *this; } const sockaddr* KSocketAddress::address() const { if (d->invalid()) return 0L; return d->addr.generic; } sockaddr* KSocketAddress::address() { if (d->invalid()) return 0L; return d->addr.generic; } KSocketAddress& KSocketAddress::setAddress(const sockaddr* sa, TQ_UINT16 len) { if (sa != 0L && len >= MIN_SOCKADDR_LEN) d->dup(sa, len); else d->tqinvalidate(); return *this; } TQ_UINT16 KSocketAddress::length() const { if (d->invalid()) return 0; return d->reallen; } KSocketAddress& KSocketAddress::setLength(TQ_UINT16 len) { d->dup((sockaddr*)0L, len, false); return *this; } int KSocketAddress::family() const { if (d->invalid()) return AF_UNSPEC; return d->addr.generic->sa_family; } KSocketAddress& KSocketAddress::setFamily(int family) { if (d->invalid()) d->dup((sockaddr*)0L, MIN_SOCKADDR_LEN); d->addr.generic->sa_family = family; return *this; } bool KSocketAddress::operator ==(const KSocketAddress& other) const { // if this is invalid, it's only equal if the other one is invalid as well if (d->invalid()) return other.d->invalid(); // check the family to make sure we don't do unnecessary comparison if (d->addr.generic->sa_family != other.d->addr.generic->sa_family) return false; // not the same family, not equal // same family then // check the ones we know already switch (d->addr.generic->sa_family) { case AF_INET: Q_ASSERT(d->reallen == SOCKADDR_IN_LEN); Q_ASSERT(other.d->reallen == SOCKADDR_IN_LEN); return memcmp(d->addr.in, other.d->addr.in, SOCKADDR_IN_LEN) == 0; #ifdef AF_INET6 case AF_INET6: Q_ASSERT(d->reallen >= MIN_SOCKADDR_IN6_LEN); Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_IN6_LEN); # if !defined(HAVE_STRUCT_SOCKADDR_IN6) || defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID) // check for the case where sin6_scope_id isn't present if (d->reallen != other.d->reallen) { if (memcmp(d->addr.in6, other.d->addr.in6, MIN_SOCKADDR_IN6_LEN) != 0) return false; // not equal if (d->reallen > other.d->reallen) return d->addr.in6->sin6_scope_id == 0; else return other.d->addr.in6->sin6_scope_id == 0; } # endif return memcmp(d->addr.in6, other.d->addr.in6, d->reallen) == 0; #endif case AF_UNIX: Q_ASSERT(d->reallen >= MIN_SOCKADDR_UN_LEN); Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_UN_LEN); // do a string comparison here return strcmp(d->addr.un->sun_path, other.d->addr.un->sun_path) == 0; default: // something else we don't know about // they are equal if and only if they are exactly equal if (d->reallen == other.d->reallen) return memcmp(d->addr.generic, other.d->addr.generic, d->reallen) == 0; } return false; // not equal in any other case } TQString KSocketAddress::nodeName() const { if (d->invalid()) return TQString::null; switch (d->addr.generic->sa_family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: TQString scopeid("%"); if (d->addr.generic->sa_family == AF_INET6 && d->addr.in6->sin6_scope_id) scopeid += TQString::number(d->addr.in6->sin6_scope_id); else scopeid.truncate(0); return d->ref.ipAddress().toString() + scopeid; #else return d->ref.ipAddress().toString(); #endif } // any other case, including AF_UNIX return TQString::null; } TQString KSocketAddress::serviceName() const { if (d->invalid()) return TQString::null; switch (d->addr.generic->sa_family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: #endif return TQString::number(d->ref.port()); case AF_UNIX: return d->ref.pathname(); } return TQString::null; } TQString KSocketAddress::toString() const { if (d->invalid()) return TQString::null; TQString fmt; if (d->addr.generic->sa_family == AF_INET) fmt = "%1:%2"; #ifdef AF_INET6 else if (d->addr.generic->sa_family == AF_INET6) fmt = "[%1]:%2"; #endif else if (d->addr.generic->sa_family == AF_UNIX) return TQString::fromLatin1("unix:%1").arg(serviceName()); else return i18n("1: the unknown socket address family number", "Unknown family %1").arg(d->addr.generic->sa_family); return fmt.arg(nodeName()).arg(serviceName()); } KInetSocketAddress& KSocketAddress::asInet() { return d->ref; } KInetSocketAddress KSocketAddress::asInet() const { return d->ref; } KUnixSocketAddress& KSocketAddress::asUnix() { return d->ref; } KUnixSocketAddress KSocketAddress::asUnix() const { return d->ref; } int KSocketAddress::ianaFamily(int af) { switch (af) { case AF_INET: return 1; #ifdef AF_INET6 case AF_INET6: return 2; #endif default: return 0; } } int KSocketAddress::fromIanaFamily(int iana) { switch (iana) { case 1: return AF_INET; #ifdef AF_INET6 case 2: return AF_INET6; #endif default: return AF_UNSPEC; } } // default constructor KInetSocketAddress::KInetSocketAddress() { } // binary data constructor KInetSocketAddress::KInetSocketAddress(const sockaddr* sa, TQ_UINT16 len) : KSocketAddress(sa, len) { if (!d->invalid()) update(); } // create from IP and port KInetSocketAddress::KInetSocketAddress(const KIpAddress& host, TQ_UINT16 port) { setHost(host); setPort(port); } // copy constructor KInetSocketAddress::KInetSocketAddress(const KInetSocketAddress& other) : KSocketAddress(other) { } // special copy constructor KInetSocketAddress::KInetSocketAddress(const KSocketAddress& other) : KSocketAddress(other) { if (!d->invalid()) update(); } // special constructor KInetSocketAddress::KInetSocketAddress(KSocketAddressData *d) : KSocketAddress(d) { } // destructor KInetSocketAddress::~KInetSocketAddress() { /* nothing to do */ } // copy operator KInetSocketAddress& KInetSocketAddress::operator =(const KInetSocketAddress& other) { KSocketAddress::operator =(other); return *this; } // IP version int KInetSocketAddress::ipVersion() const { if (d->invalid()) return 0; switch (d->addr.generic->sa_family) { case AF_INET: return 4; #ifdef AF_INET6 case AF_INET6: return 6; #endif } return 0; // for all other cases } KIpAddress KInetSocketAddress::ipAddress() const { if (d->invalid()) return KIpAddress(); // return an empty address as well switch (d->addr.generic->sa_family) { case AF_INET: return KIpAddress(&d->addr.in->sin_addr, 4); #ifdef AF_INET6 case AF_INET6: return KIpAddress(&d->addr.in6->sin6_addr, 6); #endif } return KIpAddress(); // empty in all other cases } KInetSocketAddress& KInetSocketAddress::setHost(const KIpAddress& ip) { switch (ip.version()) { case 4: makeIPv4(); memcpy(&d->addr.in->sin_addr, ip.addr(), sizeof(d->addr.in->sin_addr)); break; case 6: makeIPv6(); memcpy(&d->addr.in6->sin6_addr, ip.addr(), sizeof(d->addr.in6->sin6_addr)); break; default: // empty d->tqinvalidate(); } return *this; } // returns the port TQ_UINT16 KInetSocketAddress::port() const { if (d->invalid()) return 0; switch (d->addr.generic->sa_family) { case AF_INET: return ntohs(d->addr.in->sin_port); #ifdef AF_INET6 case AF_INET6: return ntohs(d->addr.in6->sin6_port); #endif } return 0; } KInetSocketAddress& KInetSocketAddress::setPort(TQ_UINT16 port) { if (d->invalid()) makeIPv4(); switch (d->addr.generic->sa_family) { case AF_INET: d->addr.in->sin_port = htons(port); break; #ifdef AF_INET6 case AF_INET6: d->addr.in6->sin6_port = htons(port); break; #endif default: d->tqinvalidate(); // setting the port on something else } return *this; } KInetSocketAddress& KInetSocketAddress::makeIPv4() { d->makeipv4(); return *this; } KInetSocketAddress& KInetSocketAddress::makeIPv6() { d->makeipv6(); return *this; } TQ_UINT32 KInetSocketAddress::flowinfo() const { #ifndef AF_INET6 return 0; #else if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6) return d->addr.in6->sin6_flowinfo; return 0; #endif } KInetSocketAddress& KInetSocketAddress::setFlowinfo(TQ_UINT32 flowinfo) { makeIPv6(); // must set here d->addr.in6->sin6_flowinfo = flowinfo; return *this; } int KInetSocketAddress::scopeId() const { #ifndef AF_INET6 return 0; #else if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6) return d->addr.in6->sin6_scope_id; return 0; #endif } KInetSocketAddress& KInetSocketAddress::setScopeId(int scopeid) { makeIPv6(); // must set here d->addr.in6->sin6_scope_id = scopeid; return *this; } void KInetSocketAddress::update() { if (d->addr.generic->sa_family == AF_INET) return; #ifdef AF_INET6 else if (d->addr.generic->sa_family == AF_INET6) return; #endif else d->tqinvalidate(); } KUnixSocketAddress::KUnixSocketAddress() { } KUnixSocketAddress::KUnixSocketAddress(const sockaddr* sa, TQ_UINT16 len) : KSocketAddress(sa, len) { if (!d->invalid() && d->addr.un->sun_family != AF_UNIX) d->tqinvalidate(); } KUnixSocketAddress::KUnixSocketAddress(const KUnixSocketAddress& other) : KSocketAddress(other) { } KUnixSocketAddress::KUnixSocketAddress(const TQString& pathname) { setPathname(pathname); } KUnixSocketAddress::KUnixSocketAddress(KSocketAddressData* d) : KSocketAddress(d) { } KUnixSocketAddress::~KUnixSocketAddress() { } KUnixSocketAddress& KUnixSocketAddress::operator =(const KUnixSocketAddress& other) { KSocketAddress::operator =(other); return *this; } TQString KUnixSocketAddress::pathname() const { if (!d->invalid() && d->addr.un->sun_family == AF_UNIX) return TQFile::decodeName(d->addr.un->sun_path); return TQString::null; } KUnixSocketAddress& KUnixSocketAddress::setPathname(const TQString& path) { d->dup(0L, MIN_SOCKADDR_UN_LEN + path.length()); d->addr.un->sun_family = AF_UNIX; strcpy(d->addr.un->sun_path, TQFile::encodeName(path)); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN d->addr.un->sun_len = d->reallen; #endif return *this; }