QtNetwork: Better detection of connection failures on Windows
authorMartin Petersson <Martin.Petersson@nokia.com>
Thu, 12 Jul 2012 10:52:17 +0000 (12:52 +0200)
committerQt by Nokia <qt-info@nokia.com>
Mon, 30 Jul 2012 08:43:50 +0000 (10:43 +0200)
If the error code from WSAConnect is WSAEWOULDBLOCK, then the
operation proceeds but the outcome is not known at that time. We then
check SO_ERROR's value to detect errors. But if that call returns 0
this could indicate that the value is still not know. In this case
we try one more time to increase the chance of getting the correct
value.

This fixed the tst_QNetworkReply::getFromUnreachableIp auto test
on Windows.

Change-Id: I25008aca062b2f823e3d93ebb0ae456d7e4a6ecc
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
src/network/socket/qnativesocketengine_win.cpp

index 59e8517..aebb9dc 100644 (file)
@@ -683,28 +683,48 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
                 // unfinished operation.
                 int value = 0;
                 QT_SOCKLEN_T valueSize = sizeof(value);
-                if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
-                    if (value == WSAECONNREFUSED) {
-                        setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
-                        socketState = QAbstractSocket::UnconnectedState;
-                        break;
+                bool tryAgain = false;
+                bool errorDetected = false;
+                int tries = 0;
+                do {
+                    if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
+                        if (value == WSAECONNREFUSED) {
+                            setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+                            socketState = QAbstractSocket::UnconnectedState;
+                            errorDetected = true;
+                            break;
+                        }
+                        if (value == WSAETIMEDOUT) {
+                            setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+                            socketState = QAbstractSocket::UnconnectedState;
+                            errorDetected = true;
+                            break;
+                        }
+                        if (value == WSAEHOSTUNREACH) {
+                            setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
+                            socketState = QAbstractSocket::UnconnectedState;
+                            errorDetected = true;
+                            break;
+                        }
+                        if (value == WSAEADDRNOTAVAIL) {
+                            setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
+                            socketState = QAbstractSocket::UnconnectedState;
+                            errorDetected = true;
+                            break;
+                        }
+                        if (value == NOERROR) {
+                            // When we get WSAEWOULDBLOCK the outcome was not known, so a
+                            // NOERROR might indicate that the result of the operation
+                            // is still unknown. We try again to increase the chance that we did
+                            // get the correct result.
+                            tryAgain = !tryAgain;
+                        }
                     }
-                    if (value == WSAETIMEDOUT) {
-                        setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
-                        socketState = QAbstractSocket::UnconnectedState;
-                        break;
-                    }
-                    if (value == WSAEHOSTUNREACH) {
-                        setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
-                        socketState = QAbstractSocket::UnconnectedState;
-                        break;
-                    }
-                    if (value == WSAEADDRNOTAVAIL) {
-                        setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
-                        socketState = QAbstractSocket::UnconnectedState;
-                        break;
-                    }
-                }
+                    tries++;
+                } while (tryAgain && (tries < 2));
+
+                if (errorDetected)
+                    break;
                 // fall through
             }
             case WSAEINPROGRESS: