QAbstractSocket: do not fail writing on read buffer overflow

canReadNotification() could return 'false' if either the socket has
been closed, or the read buffer has reached the maximum size. Because of
this duality, waitForBytesWritten() should not fail as a result of a
canReadNotification() call.

Change-Id: I9a15fa174a3b982a7ce404913caa38fc19f64622
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
This commit is contained in:
Alex Trotsenko 2016-02-17 17:55:41 +02:00
parent d930c8b5fc
commit bec47545dc
2 changed files with 40 additions and 4 deletions

View File

@ -2253,8 +2253,10 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
forever {
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite,
!d->readBufferMaxSize || d->buffer.size() < d->readBufferMaxSize,
!d->writeBuffer.isEmpty(),
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)",
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
@ -2269,8 +2271,7 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForBytesWritten calls canReadNotification");
#endif
if(!d->canReadNotification())
return false;
d->canReadNotification();
}

View File

@ -197,6 +197,7 @@ private slots:
void clientSendDataOnDelayedDisconnect();
void serverDisconnectWithBuffered();
void socketDiscardDataInWriteMode();
void writeOnReadBufferOverflow();
void readNotificationsAfterBind();
protected slots:
@ -3067,6 +3068,40 @@ void tst_QTcpSocket::socketDiscardDataInWriteMode()
delete socket;
}
// Test waitForBytesWritten() does not fail on read buffer overflow
void tst_QTcpSocket::writeOnReadBufferOverflow()
{
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
QTcpServer tcpServer;
QTcpSocket *socket = newSocket();
QVERIFY(tcpServer.listen(QHostAddress::LocalHost));
socket->setReadBufferSize(1);
socket->connectToHost(tcpServer.serverAddress(), tcpServer.serverPort());
QVERIFY(socket->waitForConnected(5000));
QCOMPARE(socket->state(), QAbstractSocket::ConnectedState);
// Accept connection on server side
QVERIFY2(tcpServer.waitForNewConnection(5000), "Network timeout");
QTcpSocket *newConnection = tcpServer.nextPendingConnection();
QVERIFY(newConnection != nullptr);
QCOMPARE(newConnection->write("1", 2), Q_INT64_C(2));
QVERIFY(newConnection->flush());
// Wait for buffer overflow
QVERIFY(socket->waitForReadyRead(5000));
QCOMPARE(socket->bytesAvailable(), Q_INT64_C(1));
// Write data and wait for successful send
QVERIFY(socket->putChar(0));
QVERIFY(socket->waitForBytesWritten(5000));
delete newConnection;
delete socket;
}
// Test that the socket does not enable the read notifications in bind()
void tst_QTcpSocket::readNotificationsAfterBind()
{