Fix non inheritable socket creation on old windows versions
authorShane Kearns <ext-shane.2.kearns@nokia.com>
Tue, 19 Jun 2012 16:38:40 +0000 (17:38 +0100)
committerQt by Nokia <qt-info@nokia.com>
Fri, 22 Jun 2012 11:43:28 +0000 (13:43 +0200)
The documentation is misleading, as using the new API actually
causes WSASocket to fail.
New behaviour:
On windows vista or earlier: skip the new API, use old one
On windows 7: try the new API first, if it fails try the old one
On windows 8: try the new API only

The windows 7 behaviour is because we don't know if the service
pack has been installed or not. (And IT departments may have
specifically installed/blocked the hotfix)

Task-number: QTBUG-26224
Change-Id: I6da47959919caee0cd2697f1ae1fca46aa33c1ff
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Mikhail Vorozhtsov
src/network/socket/qnativesocketengine_win.cpp

index 60c4c73..8b354a8 100644 (file)
@@ -307,10 +307,11 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
         return -1;
     }
     */
+    QSysInfo::WinVersion osver = QSysInfo::windowsVersion();
 
     //Windows XP and 2003 support IPv6 but not dual stack sockets
     int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol
-        || (socketProtocol == QAbstractSocket::AnyIPProtocol && QSysInfo::windowsVersion() >= QSysInfo::WV_6_0)) ? AF_INET6 : AF_INET;
+        || (socketProtocol == QAbstractSocket::AnyIPProtocol && osver >= QSysInfo::WV_6_0)) ? AF_INET6 : AF_INET;
     int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
 
     // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking
@@ -318,12 +319,29 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
 
     // WSA_FLAG_NO_HANDLE_INHERIT is atomic (like linux O_CLOEXEC), but requires windows 7 SP 1 or later
     // SetHandleInformation is supported since W2K but isn't atomic
-    // According to the MS docs, we can use the new flag and call GetHandleInformation to see if it was successful
 #ifndef WSA_FLAG_NO_HANDLE_INHERIT
 #define WSA_FLAG_NO_HANDLE_INHERIT 0x80
 #endif
 
-    SOCKET socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
+    SOCKET socket = INVALID_SOCKET;
+    // Windows 7 or later, try the new API
+    if (osver >= QSysInfo::WV_6_1)
+        socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
+    // previous call fails if the windows 7 service pack 1 or hot fix isn't installed.
+
+    // Try the old API if the new one failed on Windows 7, or always on earlier versions
+    if (socket == INVALID_SOCKET && osver <= QSysInfo::WV_6_1) {
+        socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
+#ifdef HANDLE_FLAG_INHERIT
+        if (socket != INVALID_SOCKET) {
+            // make non inheritable the old way
+            BOOL handleFlags = SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+            qDebug() << "QNativeSocketEnginePrivate::createNewSocket - set inheritable" << handleFlags;
+#endif
+        }
+#endif
+    }
 
     if (socket == INVALID_SOCKET) {
         int err = WSAGetLastError();
@@ -349,19 +367,6 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
         return false;
     }
 
-#ifdef HANDLE_FLAG_INHERIT
-    // check if the WSASocket was successful or not at creating a non inheritable socket
-    DWORD handleFlags = 0xFF;
-    if (GetHandleInformation((HANDLE)socket, &handleFlags) && (handleFlags & HANDLE_FLAG_INHERIT)) {
-        // make non inheritable the old way
-        if (SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0))
-            handleFlags = 0;
-    }
-#ifdef QNATIVESOCKETENGINE_DEBUG
-    qDebug() << "QNativeSocketEnginePrivate::createNewSocket - set inheritable" << handleFlags;
-#endif
-#endif
-
 #if !defined(Q_OS_WINCE)
     if (socketType == QAbstractSocket::UdpSocket) {
         // enable new behavior using