Merge the multiple implementations of getting the local hostname
authorThiago Macieira <thiago.macieira@intel.com>
Wed, 8 Apr 2015 21:14:16 +0000 (14:14 -0700)
committerThiago Macieira <thiago.macieira@intel.com>
Thu, 13 Aug 2015 16:34:51 +0000 (16:34 +0000)
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>
src/corelib/global/qglobal.cpp
src/corelib/global/qsysinfo.h
src/network/kernel/qhostinfo.cpp
src/network/kernel/qhostinfo_unix.cpp
src/network/kernel/qhostinfo_win.cpp
src/network/kernel/qhostinfo_winrt.cpp
src/network/socket/qnativesocketengine.cpp
src/network/socket/qnativesocketengine_p.h
src/network/socket/qnativesocketengine_win.cpp
tests/manual/qsysinfo/main.cpp

index 37a765b40a3af1f56f120bad45a93b1791f10856..77ac53f7e918de6dde86f4430a8c8d06a6d311e6 100644 (file)
 #  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
 #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>
index d40e6659c7aac1bb1ab138c695e06a958ebb70e8..27a285fd36aacb6c9e2c4e75d5bbd6301d3ee767 100644 (file)
@@ -186,6 +186,8 @@ public:
     static QString productType();
     static QString productVersion();
     static QString prettyProductName();
+
+    static QString machineHostName();
 };
 
 QT_END_NAMESPACE
index a2ac9065fd0ed8718429a4e35f745dac5ef2ff35..c6c09542e74ea60ef8713502dd7e9cf92f349530 100644 (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()
index 90a6f763f7a611bd2720262b17ba6e1e21b431d6..266a67771c937d8da8ebe599b29c1eb24a6f24b5 100644 (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)
index e0447281984d6fc99008118ae99f7d6166dfc017..fc65ce9fa2580959b99c22c355cf94102ddf0c8b 100644 (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
index 1a97fe0e404aeda814e6a2b431e609821e7031df..3d2344726b4a0ab537090ce620f1d84f93b73644 100644 (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
index 33bf3af0b59af41fcabc65f42f1b387116cc7c0b..22151b8e56743364a37d3c89f26233d8a517b1e8 100644 (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
index 24909bf310f0778e888323c584ef48a6075a1dc6..653309302c9fc20c3fd0b161df86655ba32ad7f8 100644 (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,
index 7856db0487a1a4569de56d747082ef73be24f161..8c3f68f04f050212c3b9bd1b770863d25e33d1aa 100644 (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.
index a3f21140cb3788378bed8a672eb9173d4812a1aa..9456bd9b031b5036e1516475e37a06dfd0d5f71b 100644 (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;
 }