diff -r 56cd8111b7f7 -r 41300fa6a67c src/network/socket/qabstractsocket.cpp --- 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)