Skip to content

Commit

Permalink
QHostInfo: Make getaddrinfo() mandatory
Browse files Browse the repository at this point in the history
All systems must implement it by now. If there's any system still
without it, that means it has no IPv6 support, so they can disable
QtNetwork entirely.

[ChangeLog][Deprecation Notice] Starting with Qt 5.10, IPv6 support is
mandatory for all platforms. Systems without proper IPv6 support, such
as the getaddrinfo() function or the proper socket address structures,
will not be able to build QtNetwork anymore.

Change-Id: I3868166e5efc45538544fffd14d8c28046f9191b
Reviewed-by: Edward Welbourne <[email protected]>
  • Loading branch information
thiagomacieira authored and ediosyncratic committed Oct 18, 2017
1 parent 3760bc7 commit 3fe74b7
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 223 deletions.
32 changes: 1 addition & 31 deletions src/network/configure.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,31 +89,6 @@
},

"tests": {
"getaddrinfo": {
"label": "getaddrinfo()",
"type": "compile",
"test": {
"head": [
"#include <stdio.h>",
"#include <stdlib.h>",
"#ifdef __MINGW32__",
"# include <winsock2.h>",
"# include <ws2tcpip.h>",
"#else",
"# include <sys/types.h>",
"# include <sys/socket.h>",
"# include <netdb.h>",
"#endif"
],
"main": [
"addrinfo *res = 0;",
"(void) getaddrinfo(\"foo\", 0, 0, &res);",
"freeaddrinfo(res);",
"gai_strerror(0);"
]
},
"use": "network"
},
"getifaddrs": {
"label": "getifaddrs()",
"type": "compile",
Expand Down Expand Up @@ -170,11 +145,6 @@
"emitIf": "config.darwin",
"output": [ "feature", "privateFeature" ]
},
"getaddrinfo": {
"label": "getaddrinfo()",
"condition": "tests.getaddrinfo",
"output": [ "feature" ]
},
"getifaddrs": {
"label": "getifaddrs()",
"condition": "tests.getifaddrs",
Expand Down Expand Up @@ -337,7 +307,7 @@ For example:
"args": "corewlan",
"condition": "config.darwin"
},
"getaddrinfo", "getifaddrs", "ipv6ifname", "libproxy",
"getifaddrs", "ipv6ifname", "libproxy",
{
"type": "feature",
"args": "securetransport",
Expand Down
50 changes: 0 additions & 50 deletions src/network/kernel/qhostinfo_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@
# include <gnu/lib-names.h>
#endif

#if defined (QT_NO_GETADDRINFO)
static QBasicMutex getHostByNameMutex;
#endif

QT_BEGIN_NAMESPACE

// Almost always the same. If not, specify in qplatformdefs.h.
Expand Down Expand Up @@ -150,7 +146,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
QHostAddress address;
if (address.setAddress(hostName)) {
// Reverse lookup
#if !defined (QT_NO_GETADDRINFO)
sockaddr_in sa4;
sockaddr_in6 sa6;
sockaddr *sa = 0;
Expand All @@ -173,12 +168,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
char hbuf[NI_MAXHOST];
if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
results.setHostName(QString::fromLatin1(hbuf));
#else
in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData());
struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET);
if (ent)
results.setHostName(QString::fromLatin1(ent->h_name));
#endif

if (results.hostName().isEmpty())
results.setHostName(address.toString());
Expand All @@ -197,7 +186,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}

#if !defined (QT_NO_GETADDRINFO)
// Call getaddrinfo, and place all IPv4 addresses at the start and
// the IPv6 addresses at the end of the address list in results.
addrinfo *res = 0;
Expand Down Expand Up @@ -264,39 +252,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
}

#else
// Fall back to gethostbyname for platforms that don't define
// getaddrinfo. gethostbyname does not support IPv6, and it's not
// reentrant on all platforms. For now this is okay since we only
// use one QHostInfoAgent, but if more agents are introduced, locking
// must be provided.
QMutexLocker locker(&getHostByNameMutex);
hostent *result = gethostbyname(aceHostname.constData());
if (result) {
if (result->h_addrtype == AF_INET) {
QList<QHostAddress> addresses;
for (char **p = result->h_addr_list; *p != 0; p++) {
QHostAddress addr;
addr.setAddress(ntohl(*((quint32 *)*p)));
if (!addresses.contains(addr))
addresses.prepend(addr);
}
results.setAddresses(addresses);
} else {
results.setError(QHostInfo::UnknownError);
results.setErrorString(tr("Unknown address type"));
}
#if !defined(Q_OS_VXWORKS)
} else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA
|| h_errno == NO_ADDRESS) {
results.setError(QHostInfo::HostNotFound);
results.setErrorString(tr("Host not found"));
#endif
} else {
results.setError(QHostInfo::UnknownError);
results.setErrorString(tr("Unknown error"));
}
#endif // !defined (QT_NO_GETADDRINFO)

#if defined(QHOSTINFO_DEBUG)
if (results.error() != QHostInfo::NoError) {
Expand Down Expand Up @@ -339,11 +294,6 @@ QString QHostInfo::localDomainName()
if (local_res_init && local_res) {
// using thread-unsafe version

#if defined(QT_NO_GETADDRINFO)
// We have to call res_init to be sure that _res was initialized
// So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too
QMutexLocker locker(&getHostByNameMutex);
#endif
local_res_init();
QString domainName = QUrl::fromAce(local_res->defdname);
if (domainName.isEmpty())
Expand Down
161 changes: 42 additions & 119 deletions src/network/kernel/qhostinfo_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,50 +50,12 @@ QT_BEGIN_NAMESPACE

//#define QHOSTINFO_DEBUG

// Older SDKs do not include the addrinfo struct declaration, so we
// include a copy of it here.
struct qt_addrinfo
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char *ai_canonname;
sockaddr *ai_addr;
qt_addrinfo *ai_next;
};

//###
#define QT_SOCKLEN_T int
#ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h?
#define NI_MAXHOST 1024
#endif

typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int);
typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **);
typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *);
static getnameinfoProto local_getnameinfo = 0;
static getaddrinfoProto local_getaddrinfo = 0;
static freeaddrinfoProto local_freeaddrinfo = 0;

static bool resolveLibraryInternal()
{
// Attempt to resolve getaddrinfo(); without it we'll have to fall
// back to gethostbyname(), which has no IPv6 support.
#if defined (Q_OS_WINRT)
local_getaddrinfo = (getaddrinfoProto) &getaddrinfo;
local_freeaddrinfo = (freeaddrinfoProto) &freeaddrinfo;
local_getnameinfo = (getnameinfoProto) getnameinfo;
#else
local_getaddrinfo = (getaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getaddrinfo");
local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "freeaddrinfo");
local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getnameinfo");
#endif
return true;
}
Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal()))

static void translateWSAError(int error, QHostInfo *results)
{
switch (error) {
Expand All @@ -114,49 +76,39 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
{
QSysInfo::machineHostName(); // this initializes ws2_32.dll

// Load res_init on demand.
resolveLibrary();

QHostInfo results;

#if defined(QHOSTINFO_DEBUG)
qDebug("QHostInfoAgent::fromName(): looking up \"%s\" (IPv6 support is %s)",
hostName.toLatin1().constData(),
(local_getaddrinfo && local_freeaddrinfo) ? "enabled" : "disabled");
(getaddrinfo && freeaddrinfo) ? "enabled" : "disabled");
#endif

QHostAddress address;
if (address.setAddress(hostName)) {
// Reverse lookup
if (local_getnameinfo) {
sockaddr_in sa4;
sockaddr_in6 sa6;
sockaddr *sa;
QT_SOCKLEN_T saSize;
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
sa = (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 = (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 (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
results.setHostName(QString::fromLatin1(hbuf));
sockaddr_in sa4;
sockaddr_in6 sa6;
sockaddr *sa;
QT_SOCKLEN_T saSize;
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
sa = (sockaddr *)&sa4;
saSize = sizeof(sa4);
memset(&sa4, 0, sizeof(sa4));
sa4.sin_family = AF_INET;
sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
} else {
unsigned long addr = inet_addr(hostName.toLatin1().constData());
struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
if (ent)
results.setHostName(QString::fromLatin1(ent->h_name));
sa = (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 (getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
results.setHostName(QString::fromLatin1(hbuf));

if (results.hostName().isEmpty())
results.setHostName(address.toString());
results.setAddresses(QList<QHostAddress>() << address);
Expand All @@ -172,64 +124,35 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}

if (local_getaddrinfo && local_freeaddrinfo) {
// Call getaddrinfo, and place all IPv4 addresses at the start
// and the IPv6 addresses at the end of the address list in
// results.
qt_addrinfo *res;
int err = local_getaddrinfo(aceHostname.constData(), 0, 0, &res);
if (err == 0) {
QList<QHostAddress> addresses;
for (qt_addrinfo *p = res; p != 0; p = p->ai_next) {
switch (p->ai_family) {
case AF_INET: {
QHostAddress addr;
addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr));
if (!addresses.contains(addr))
addresses.append(addr);
}
break;
case AF_INET6: {
QHostAddress addr;
addr.setAddress(((sockaddr_in6 *) p->ai_addr)->sin6_addr.s6_addr);
if (!addresses.contains(addr))
addresses.append(addr);
}
break;
default:
results.setError(QHostInfo::UnknownError);
results.setErrorString(tr("Unknown address type"));
}
addrinfo *res;
int err = getaddrinfo(aceHostname.constData(), 0, 0, &res);
if (err == 0) {
QList<QHostAddress> addresses;
for (addrinfo *p = res; p != 0; p = p->ai_next) {
switch (p->ai_family) {
case AF_INET: {
QHostAddress addr;
addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr));
if (!addresses.contains(addr))
addresses.append(addr);
}
break;
case AF_INET6: {
QHostAddress addr;
addr.setAddress(((sockaddr_in6 *) p->ai_addr)->sin6_addr.s6_addr);
if (!addresses.contains(addr))
addresses.append(addr);
}
results.setAddresses(addresses);
local_freeaddrinfo(res);
} else {
translateWSAError(WSAGetLastError(), &results);
}
} else {
// Fall back to gethostbyname, which only supports IPv4.
hostent *ent = gethostbyname(aceHostname.constData());
if (ent) {
char **p;
QList<QHostAddress> addresses;
switch (ent->h_addrtype) {
case AF_INET:
for (p = ent->h_addr_list; *p != 0; p++) {
long *ip4Addr = (long *) *p;
QHostAddress temp;
temp.setAddress(ntohl(*ip4Addr));
addresses << temp;
}
break;
default:
results.setError(QHostInfo::UnknownError);
results.setErrorString(tr("Unknown address type"));
break;
}
results.setAddresses(addresses);
} else {
translateWSAError(WSAGetLastError(), &results);
}
results.setAddresses(addresses);
freeaddrinfo(res);
} else {
translateWSAError(WSAGetLastError(), &results);
}

#if defined(QHOSTINFO_DEBUG)
Expand Down
10 changes: 0 additions & 10 deletions src/network/socket/qnet_unix_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,6 @@ static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
#endif
}

// VxWorks' headers do not specify any const modifiers
static inline in_addr_t qt_safe_inet_addr(const char *cp)
{
#ifdef Q_OS_VXWORKS
return ::inet_addr((char *) cp);
#else
return ::inet_addr(cp);
#endif
}

static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
#ifdef MSG_NOSIGNAL
Expand Down
6 changes: 6 additions & 0 deletions tests/auto/network/kernel/qhostinfo/BLACKLIST
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# These tests fail due to a DNS server issue
# (this is not a Qt bug)
[lookupIPv6:a-plus-aaaa]
windows ci
[blockingLookup:a-plus-aaaa]
windows ci
Loading

0 comments on commit 3fe74b7

Please sign in to comment.