diff options
Diffstat (limited to 'src/network/kernel/qhostinfo.cpp')
-rw-r--r-- | src/network/kernel/qhostinfo.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index d3fe85f5d5..9374728244 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -37,8 +37,11 @@ ** ****************************************************************************/ +//#define QHOSTINFO_DEBUG + #include "qhostinfo.h" #include "qhostinfo_p.h" +#include <qplatformdefs.h> #include "QtCore/qscopedpointer.h" #include <qabstracteventdispatcher.h> @@ -53,6 +56,15 @@ #ifdef Q_OS_UNIX # include <unistd.h> +# include <netdb.h> +# include <netinet/in.h> +# if defined(AI_ADDRCONFIG) +# define Q_ADDRCONFIG AI_ADDRCONFIG +# endif +#elif defined Q_OS_WIN +# include <ws2tcpip.h> + +# define QT_SOCKLEN_T int #endif QT_BEGIN_NAMESPACE @@ -412,6 +424,162 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetw } #endif +QHostInfo QHostInfoAgent::reverseLookup(const QHostAddress &address) +{ + QHostInfo results; + // Reverse lookup + sockaddr_in sa4; + sockaddr_in6 sa6; + sockaddr *sa = 0; + QT_SOCKLEN_T saSize; + if (address.protocol() == QAbstractSocket::IPv4Protocol) { + sa = reinterpret_cast<sockaddr *>(&sa4); + saSize = sizeof(sa4); + memset(&sa4, 0, sizeof(sa4)); + sa4.sin_family = AF_INET; + sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); + } else { + sa = reinterpret_cast<sockaddr *>(&sa6); + saSize = sizeof(sa6); + memset(&sa6, 0, sizeof(sa6)); + sa6.sin6_family = AF_INET6; + memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr)); + } + + char hbuf[NI_MAXHOST]; + if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), nullptr, 0, 0) == 0) + results.setHostName(QString::fromLatin1(hbuf)); + + if (results.hostName().isEmpty()) + results.setHostName(address.toString()); + results.setAddresses(QList<QHostAddress>() << address); + + return results; +} + +/* + Call getaddrinfo, and returns the results as QHostInfo::addresses +*/ +QHostInfo QHostInfoAgent::lookup(const QString &hostName) +{ + QHostInfo results; + + // IDN support + QByteArray aceHostname = QUrl::toAce(hostName); + results.setHostName(hostName); + if (aceHostname.isEmpty()) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(hostName.isEmpty() ? + QCoreApplication::translate("QHostInfoAgent", "No host name given") : + QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); + return results; + } + + addrinfo *res = 0; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; +#ifdef Q_ADDRCONFIG + hints.ai_flags = Q_ADDRCONFIG; +#endif + + int result = getaddrinfo(aceHostname.constData(), nullptr, &hints, &res); +# ifdef Q_ADDRCONFIG + if (result == EAI_BADFLAGS) { + // if the lookup failed with AI_ADDRCONFIG set, try again without it + hints.ai_flags = 0; + result = getaddrinfo(aceHostname.constData(), nullptr, &hints, &res); + } +# endif + + if (result == 0) { + addrinfo *node = res; + QList<QHostAddress> addresses; + while (node) { +#ifdef QHOSTINFO_DEBUG + qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family + << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol + << "ai_addrlen:" << node->ai_addrlen; +#endif + switch (node->ai_family) { + case AF_INET: { + QHostAddress addr; + addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); + if (!addresses.contains(addr)) + addresses.append(addr); + break; + } + case AF_INET6: { + QHostAddress addr; + sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; + addr.setAddress(sa6->sin6_addr.s6_addr); + if (sa6->sin6_scope_id) + addr.setScopeId(QString::number(sa6->sin6_scope_id)); + if (!addresses.contains(addr)) + addresses.append(addr); + break; + } + default: + results.setError(QHostInfo::UnknownError); + results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Unknown address type")); + } + node = node->ai_next; + } + if (addresses.isEmpty()) { + // Reached the end of the list, but no addresses were found; this + // means the list contains one or more unknown address types. + results.setError(QHostInfo::UnknownError); + results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Unknown address type")); + } + + results.setAddresses(addresses); + freeaddrinfo(res); + } else { + switch (result) { +#ifdef Q_OS_WIN + case WSAHOST_NOT_FOUND: //authoritative not found + case WSATRY_AGAIN: //non authoritative not found + case WSANO_DATA: //valid name, no associated address +#else + case EAI_NONAME: + case EAI_FAIL: +# ifdef EAI_NODATA // EAI_NODATA is deprecated in RFC 3493 + case EAI_NODATA: +# endif +#endif + results.setError(QHostInfo::HostNotFound); + results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Host not found")); + break; + default: + results.setError(QHostInfo::UnknownError); +#ifdef Q_OS_WIN + results.setErrorString(QString::fromWCharArray(gai_strerror(result))); +#else + results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); +#endif + break; + } + } + +#if defined(QHOSTINFO_DEBUG) + if (results.error() != QHostInfo::NoError) { + qDebug("QHostInfoAgent::fromName(): error #%d %s", + h_errno, results.errorString().toLatin1().constData()); + } else { + QString tmp; + QList<QHostAddress> addresses = results.addresses(); + for (int i = 0; i < addresses.count(); ++i) { + if (i != 0) tmp += QLatin1String(", "); + tmp += addresses.at(i).toString(); + } + qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", + addresses.count(), aceHostname.constData(), + tmp.toLatin1().constData()); + } +#endif + + return results; +} /*! \enum QHostInfo::HostInfoError |