Merge the multiple implementations of getting the local hostname

This commit moves the functionality from QtNetwork's QHostInfo to
QtCore. Note that due to Windows ws2_32.dll's quirky behavior of
requiring WSAStartup before calling gethostname, this change required
moving the initialization to QtCore too.

On Linux systems, gethostname() gets the name from uname(), so we bypass
the middle man and save one memcpy.

Change-Id: I27eaacb532114dd188c4ffff13d32655a6301346
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Thiago Macieira 2015-04-08 14:14:16 -07:00
parent 2366ca059e
commit 01d0b1d6e3
10 changed files with 145 additions and 99 deletions

View File

@ -65,6 +65,20 @@
# endif
#endif
#ifdef Q_OS_WINRT
#include <wrl.h>
#include <windows.networking.h>
#include <windows.networking.sockets.h>
#include <windows.networking.connectivity.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::Networking;
using namespace ABI::Windows::Networking::Connectivity;
using namespace ABI::Windows::Networking::Sockets;
#endif
#if defined(Q_OS_VXWORKS) && defined(_WRS_KERNEL)
# include <envLib.h>
#endif
@ -90,6 +104,10 @@
#include <private/qcore_unix_p.h>
#endif
#ifdef Q_OS_BSD4
#include <sys/sysctl.h>
#endif
#include "archdetect.cpp"
QT_BEGIN_NAMESPACE
@ -1887,6 +1905,36 @@ QT_END_INCLUDE_NAMESPACE
#ifndef Q_OS_WINRT
# ifndef QT_BOOTSTRAPPED
class QWindowsSockInit
{
public:
QWindowsSockInit();
~QWindowsSockInit();
int version;
};
QWindowsSockInit::QWindowsSockInit()
: version(0)
{
//### should we try for 2.2 on all platforms ??
WSAData wsadata;
// IPv6 requires Winsock v2.0 or better.
if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
} else {
version = 0x20;
}
}
QWindowsSockInit::~QWindowsSockInit()
{
WSACleanup();
}
Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
# endif // QT_BOOTSTRAPPED
# ifndef Q_OS_WINCE
// Determine Windows versions >= 8 by querying the version of kernel32.dll.
@ -2775,6 +2823,82 @@ QString QSysInfo::prettyProductName()
return unknownText();
}
#ifndef QT_BOOTSTRAPPED
/*!
\since 5.6
Returns this machine's host name, if one is configured. Note that hostnames
are not guaranteed to be globally unique, especially if they were
configured automatically.
This function does not guarantee the returned host name is a Fully
Qualified Domain Name (FQDN). For that, use QHostInfo to resolve the
returned name to an FQDN.
This function returns the same as QHostInfo::localHostName().
\sa QHostInfo::localDomainName
*/
QString QSysInfo::machineHostName()
{
#if defined(Q_OS_LINUX)
// gethostname(3) on Linux just calls uname(2), so do it ourselves
// and avoid a memcpy
struct utsname u;
if (uname(&u) == 0)
return QString::fromLocal8Bit(u.nodename);
#elif defined(Q_OS_WINRT)
ComPtr<INetworkInformationStatics> statics;
GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &statics);
ComPtr<IVectorView<HostName *>> hostNames;
statics->GetHostNames(&hostNames);
if (!hostNames)
return QString();
unsigned int size;
hostNames->get_Size(&size);
if (size == 0)
return QString();
for (unsigned int i = 0; i < size; ++i) {
ComPtr<IHostName> hostName;
hostNames->GetAt(i, &hostName);
HostNameType type;
hostName->get_Type(&type);
if (type != HostNameType_DomainName)
continue;
HString name;
hostName->get_CanonicalName(name.GetAddressOf());
UINT32 length;
PCWSTR rawString = name.GetRawBuffer(&length);
return QString::fromWCharArray(rawString, length);
}
ComPtr<IHostName> firstHost;
hostNames->GetAt(0, &firstHost);
HString name;
firstHost->get_CanonicalName(name.GetAddressOf());
UINT32 length;
PCWSTR rawString = name.GetRawBuffer(&length);
return QString::fromWCharArray(rawString, length);
#else
# ifdef Q_OS_WIN
// Important: QtNetwork depends on machineHostName() initializing ws2_32.dll
winsockInit();
# endif
char hostName[512];
if (gethostname(hostName, sizeof(hostName)) == -1)
return QString();
hostName[sizeof(hostName) - 1] = '\0';
return QString::fromLocal8Bit(hostName);
#endif
return QString();
}
#endif // QT_BOOTSTRAPPED
/*!
\macro void Q_ASSERT(bool test)
\relates <QtGlobal>

View File

@ -186,6 +186,8 @@ public:
static QString productType();
static QString productVersion();
static QString prettyProductName();
static QString machineHostName();
};
QT_END_NAMESPACE

View File

@ -415,10 +415,22 @@ void QHostInfo::setErrorString(const QString &str)
/*!
\fn QString QHostInfo::localHostName()
Returns the host name of this machine.
Returns this machine's host name, if one is configured. Note that hostnames
are not guaranteed to be globally unique, especially if they were
configured automatically.
\sa hostName()
This function does not guarantee the returned host name is a Fully
Qualified Domain Name (FQDN). For that, use fromName() to resolve the
returned name to an FQDN.
This function returns the same as QSysInfo::machineHostName().
\sa hostName(), localDomainName()
*/
QString QHostInfo::localHostName()
{
return QSysInfo::machineHostName();
}
/*!
\fn QString QHostInfo::localDomainName()

View File

@ -315,15 +315,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}
QString QHostInfo::localHostName()
{
char hostName[512];
if (gethostname(hostName, sizeof(hostName)) == -1)
return QString();
hostName[sizeof(hostName) - 1] = '\0';
return QString::fromLocal8Bit(hostName);
}
QString QHostInfo::localDomainName()
{
#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)

View File

@ -111,7 +111,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
QMutexLocker locker(&qPrivCEMutex);
#endif
QWindowsSockInit winSock;
QSysInfo::machineHostName(); // this initializes ws2_32.dll
// Load res_init on demand.
static QBasicAtomicInt triedResolve = Q_BASIC_ATOMIC_INITIALIZER(false);
@ -256,17 +256,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}
QString QHostInfo::localHostName()
{
QWindowsSockInit winSock;
char hostName[512];
if (gethostname(hostName, sizeof(hostName)) == -1)
return QString();
hostName[sizeof(hostName) - 1] = '\0';
return QString::fromLocal8Bit(hostName);
}
// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
QT_END_NAMESPACE

View File

@ -130,45 +130,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}
QString QHostInfo::localHostName()
{
ComPtr<INetworkInformationStatics> statics;
GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &statics);
ComPtr<IVectorView<HostName *>> hostNames;
statics->GetHostNames(&hostNames);
if (!hostNames)
return QString();
unsigned int size;
hostNames->get_Size(&size);
if (size == 0)
return QString();
for (unsigned int i = 0; i < size; ++i) {
ComPtr<IHostName> hostName;
hostNames->GetAt(i, &hostName);
HostNameType type;
hostName->get_Type(&type);
if (type != HostNameType_DomainName)
continue;
HString name;
hostName->get_CanonicalName(name.GetAddressOf());
UINT32 length;
PCWSTR rawString = name.GetRawBuffer(&length);
return QString::fromWCharArray(rawString, length);
}
ComPtr<IHostName> firstHost;
hostNames->GetAt(0, &firstHost);
HString name;
firstHost->get_CanonicalName(name.GetAddressOf());
UINT32 length;
PCWSTR rawString = name.GetRawBuffer(&length);
return QString::fromWCharArray(rawString, length);
}
// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
QT_END_NAMESPACE

View File

@ -152,10 +152,6 @@ QT_BEGIN_NAMESPACE
/*! \internal
Constructs the private class and initializes all data members.
On Windows, WSAStartup is called "recursively" for every
concurrent QNativeSocketEngine. This is safe, because WSAStartup and
WSACleanup are reference counted.
*/
QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() :
socketDescriptor(-1),
@ -163,6 +159,9 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() :
writeNotifier(0),
exceptNotifier(0)
{
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
QSysInfo::machineHostName(); // this initializes ws2_32.dll
#endif
}
/*! \internal

View File

@ -173,16 +173,6 @@ private:
Q_DISABLE_COPY(QNativeSocketEngine)
};
#ifdef Q_OS_WIN
class QWindowsSockInit
{
public:
QWindowsSockInit();
~QWindowsSockInit();
int version;
};
#endif
class QSocketNotifier;
class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate
@ -196,10 +186,6 @@ public:
QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier;
#ifdef Q_OS_WIN
QWindowsSockInit winSock;
#endif
enum ErrorString {
NonBlockingInitFailedErrorString,
BroadcastingInitFailedErrorString,

View File

@ -320,25 +320,6 @@ static inline int qt_socket_getMaxMsgSize(qintptr socketDescriptor)
return value;
}
QWindowsSockInit::QWindowsSockInit()
: version(0)
{
//### should we try for 2.2 on all platforms ??
WSAData wsadata;
// IPv6 requires Winsock v2.0 or better.
if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
} else {
version = 0x20;
}
}
QWindowsSockInit::~QWindowsSockInit()
{
WSACleanup();
}
// MS Transport Provider IOCTL to control
// reporting PORT_UNREACHABLE messages
// on UDP sockets via recv/WSARecv/etc.

View File

@ -134,6 +134,7 @@ int main(int argc, char *argv[])
printf("QSysInfo::productType() = %s\n", qPrintable(QSysInfo::productType()));
printf("QSysInfo::productVersion() = %s\n", qPrintable(QSysInfo::productVersion()));
printf("QSysInfo::prettyProductName() = %s\n", qPrintable(QSysInfo::prettyProductName()));
printf("QSysInfo::machineHostName() = %s\n", qPrintable(QSysInfo::machineHostName()));
return 0;
}