src/network/socket/qabstractsocket.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
--- a/src/network/socket/qabstractsocket.cpp	Tue Jan 26 12:42:25 2010 +0200
+++ b/src/network/socket/qabstractsocket.cpp	Tue Feb 02 00:43:10 2010 +0200
@@ -462,6 +462,7 @@
       isBuffered(false),
       blockingTimeout(30000),
       connectTimer(0),
+      disconnectTimer(0),
       connectTimeElapsed(0),
       hostLookupId(-1),
       socketType(QAbstractSocket::UnknownSocketType),
@@ -497,9 +498,10 @@
         socketEngine = 0;
         cachedSocketDescriptor = -1;
     }
-    if (connectTimer) {
+    if (connectTimer)
         connectTimer->stop();
-    }
+    if (disconnectTimer)
+        disconnectTimer->stop();
 }
 
 /*! \internal
@@ -669,11 +671,11 @@
 
     if (socketEngine) {
 #if defined (Q_OS_WIN)
-	if (!writeBuffer.isEmpty())
-	    socketEngine->setWriteNotificationEnabled(true);
+        if (!writeBuffer.isEmpty())
+            socketEngine->setWriteNotificationEnabled(true);
 #else
-	if (writeBuffer.isEmpty())
-	    socketEngine->setWriteNotificationEnabled(false);
+        if (writeBuffer.isEmpty() && socketEngine->bytesToWrite() == 0)
+            socketEngine->setWriteNotificationEnabled(false);
 #endif
     }
 
@@ -710,11 +712,17 @@
 bool QAbstractSocketPrivate::flush()
 {
     Q_Q(QAbstractSocket);
-    if (!socketEngine || !socketEngine->isValid() || writeBuffer.isEmpty()) {
+    if (!socketEngine || !socketEngine->isValid() || (writeBuffer.isEmpty()
+        && socketEngine->bytesToWrite() == 0)) {
 #if defined (QABSTRACTSOCKET_DEBUG)
     qDebug("QAbstractSocketPrivate::flush() nothing to do: valid ? %s, writeBuffer.isEmpty() ? %s",
            socketEngine->isValid() ? "yes" : "no", writeBuffer.isEmpty() ? "yes" : "no");
 #endif
+
+        // this covers the case when the buffer was empty, but we had to wait for the socket engine to finish
+        if (state == QAbstractSocket::ClosingState)
+            q->disconnectFromHost();
+
         return false;
     }
 
@@ -751,7 +759,8 @@
         }
     }
 
-    if (writeBuffer.isEmpty() && socketEngine && socketEngine->isWriteNotificationEnabled())
+    if (writeBuffer.isEmpty() && socketEngine && socketEngine->isWriteNotificationEnabled()
+        && !socketEngine->bytesToWrite())
         socketEngine->setWriteNotificationEnabled(false);
     if (state == QAbstractSocket::ClosingState)
         q->disconnectFromHost();
@@ -1087,6 +1096,15 @@
     }
 }
 
+void QAbstractSocketPrivate::_q_forceDisconnect()
+{
+    Q_Q(QAbstractSocket);
+    if (socketEngine && socketEngine->isValid() && state == QAbstractSocket::ClosingState) {
+        socketEngine->close();
+        q->disconnectFromHost();
+    }
+}
+
 /*! \internal
 
     Reads data from the socket layer into the read buffer. Returns
@@ -1571,10 +1589,10 @@
 }
 
 /*!
-    Sets the option \a option to the value described by \a value.
+    \since 4.6
+    Sets the given \a option to the value described by \a value.
 
     \sa socketOption()
-    \since 4.6
 */
 void QAbstractSocket::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
 {
@@ -1600,10 +1618,10 @@
 }
 
 /*!
+    \since 4.6
     Returns the value of the \a option option.
 
     \sa setSocketOption()
-    \since 4.6
 */
 QVariant QAbstractSocket::socketOption(QAbstractSocket::SocketOption option)
 {
@@ -2347,7 +2365,22 @@
         }
 
         // Wait for pending data to be written.
-        if (d->socketEngine && d->socketEngine->isValid() && d->writeBuffer.size() > 0) {
+        if (d->socketEngine && d->socketEngine->isValid() && (d->writeBuffer.size() > 0
+            || d->socketEngine->bytesToWrite() > 0)) {
+            // hack: when we are waiting for the socket engine to write bytes (only
+            // possible when using Socks5 or HTTP socket engine), then close
+            // anyway after 2 seconds. This is to prevent a timeout on Mac, where we
+            // sometimes just did not get the write notifier from the underlying
+            // CFSocket and no progress was made.
+            if (d->writeBuffer.size() == 0 && d->socketEngine->bytesToWrite() > 0) {
+                if (!d->disconnectTimer) {
+                    d->disconnectTimer = new QTimer(this);
+                    connect(d->disconnectTimer, SIGNAL(timeout()), this,
+                            SLOT(_q_forceDisconnect()), Qt::DirectConnection);
+                }
+                if (!d->disconnectTimer->isActive())
+                    d->disconnectTimer->start(2000);
+            }
             d->socketEngine->setWriteNotificationEnabled(true);
 
 #if defined(QABSTRACTSOCKET_DEBUG)