summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qabstractsocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket/qabstractsocket.cpp')
-rw-r--r--src/network/socket/qabstractsocket.cpp142
1 files changed, 110 insertions, 32 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 086292f..3218662 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -627,8 +627,9 @@ bool QAbstractSocketPrivate::canReadNotification()
// only emit readyRead() when not recursing, and only if there is data available
bool hasData = newBytes > 0
#ifndef QT_NO_UDPSOCKET
- || (!isBuffered && socketEngine && socketEngine->hasPendingDatagrams())
+ || (!isBuffered && socketType != QAbstractSocket::TcpSocket && socketEngine && socketEngine->hasPendingDatagrams())
#endif
+ || (!isBuffered && socketType == QAbstractSocket::TcpSocket && socketEngine)
;
if (!emittedReadyRead && hasData) {
@@ -1350,8 +1351,11 @@ void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint
}
#endif
- if (!d_func()->isBuffered)
- openMode |= QAbstractSocket::Unbuffered;
+ if (openMode & QIODevice::Unbuffered)
+ d->isBuffered = false; // Unbuffered QTcpSocket
+ else if (!d_func()->isBuffered)
+ openMode |= QAbstractSocket::Unbuffered; // QUdpSocket
+
QIODevice::open(openMode);
d->state = HostLookupState;
emit stateChanged(d->state);
@@ -1431,10 +1435,12 @@ qint64 QAbstractSocket::bytesAvailable() const
{
Q_D(const QAbstractSocket);
qint64 available = QIODevice::bytesAvailable();
- if (d->isBuffered)
- available += (qint64) d->readBuffer.size();
- else if (d->socketEngine && d->socketEngine->isValid())
+
+ available += (qint64) d->readBuffer.size();
+
+ if (!d->isBuffered && d->socketEngine && d->socketEngine->isValid())
available += d->socketEngine->bytesAvailable();
+
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::bytesAvailable() == %llu", available);
#endif
@@ -2067,42 +2073,50 @@ bool QAbstractSocket::flush()
qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
{
Q_D(QAbstractSocket);
- if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
- d->socketEngine->setReadNotificationEnabled(true);
-
- if (!d->isBuffered) {
- if (!d->socketEngine)
- return -1; // no socket engine is probably EOF
- qint64 readBytes = d->socketEngine->read(data, maxSize);
- if (readBytes < 0) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
- }
- if (!d->socketEngine->isReadNotificationEnabled())
- d->socketEngine->setReadNotificationEnabled(true);
-#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
- data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
- readBytes);
-#endif
- return readBytes;
- }
- if (d->readBuffer.isEmpty())
+ // This is for a buffered QTcpSocket
+ if (d->isBuffered && d->readBuffer.isEmpty())
// if we're still connected, return 0 indicating there may be more data in the future
// if we're not connected, return -1 indicating EOF
return d->state == QAbstractSocket::ConnectedState ? qint64(0) : qint64(-1);
- // If readFromSocket() read data, copy it to its destination.
- if (maxSize == 1) {
+ // short cut for a char read if we have something in the buffer
+ if (maxSize == 1 && !d->readBuffer.isEmpty()) {
*data = d->readBuffer.getChar();
#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1",
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1 [char buffer]",
data, isprint(int(uchar(*data))) ? *data : '?', *data);
#endif
+ if (d->readBuffer.isEmpty() && d->socketEngine)
+ d->socketEngine->setReadNotificationEnabled(true);
return 1;
}
+ // Special case for an Unbuffered QTcpSocket
+ // Re-filling the buffer.
+ if (d->socketType == TcpSocket
+ && !d->isBuffered
+ && d->readBuffer.size() < maxSize
+ && d->readBufferMaxSize > 0
+ && maxSize < d->readBufferMaxSize
+ && d->socketEngine) {
+ // Our buffer is empty and a read() was requested for a byte amount that is smaller
+ // than the readBufferMaxSize. This means that we should fill our buffer since we want
+ // such small reads come from the buffer and not always go to the costly socket engine read()
+ qint64 bytesToRead = d->socketEngine->bytesAvailable();
+ if (bytesToRead > 0) {
+ char *ptr = d->readBuffer.reserve(bytesToRead);
+ qint64 readBytes = d->socketEngine->read(ptr, bytesToRead);
+ if (readBytes == -2) {
+ // No bytes currently available for reading.
+ d->readBuffer.chop(bytesToRead);
+ } else {
+ d->readBuffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)));
+ }
+ }
+ }
+
+ // First try to satisfy the read from the buffer
qint64 bytesToRead = qMin(qint64(d->readBuffer.size()), maxSize);
qint64 readSoFar = 0;
while (readSoFar < bytesToRead) {
@@ -2114,8 +2128,50 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
d->readBuffer.free(bytesToReadFromThisBlock);
}
+ if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ if (readSoFar > 0) {
+ // we read some data from buffer.
+ // Just return, readyRead will be emitted again
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', %lli) == %lli [buffer]",
+ data, isprint(int(uchar(*data))) ? *data : '?', *data, maxSize, readSoFar);
+#endif
+
+ if (d->readBuffer.isEmpty() && d->socketEngine)
+ d->socketEngine->setReadNotificationEnabled(true);
+ return readSoFar;
+ }
+
+ // This code path is for Unbuffered QTcpSocket or for connected UDP
+
+ if (!d->isBuffered) {
+ if (!d->socketEngine)
+ return -1; // no socket engine is probably EOF
+ qint64 readBytes = d->socketEngine->read(data, maxSize);
+ if (readBytes == -2) {
+ // -2 from the engine means no bytes available (EAGAIN) so read more later
+ return 0;
+ } else if (readBytes < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ } else if (!d->socketEngine->isReadNotificationEnabled()) {
+ // Only do this when there was no error
+ d->socketEngine->setReadNotificationEnabled(true);
+ }
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [engine]",
+ data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
+ readBytes);
+#endif
+ return readBytes;
+ }
+
+
#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [unreachable]",
data, qt_prettyDebug(data, qMin<qint64>(32, readSoFar), readSoFar).data(),
maxSize, readSoFar);
#endif
@@ -2140,7 +2196,23 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
return -1;
}
- if (!d->isBuffered) {
+ if (!d->isBuffered && d->socketType == TcpSocket && d->writeBuffer.isEmpty()) {
+ // This code is for the new Unbuffered QTcpSocket use case
+ qint64 written = d->socketEngine->write(data, size);
+ if (written < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ return written;
+ } else if (written < size) {
+ // Buffer what was not written yet
+ char *ptr = d->writeBuffer.reserve(size - written);
+ memcpy(ptr, data + written, size - written);
+ if (d->socketEngine)
+ d->socketEngine->setWriteNotificationEnabled(true);
+ }
+ return size; // size=actually written + what has been buffered
+ } else if (!d->isBuffered && d->socketType != TcpSocket) {
+ // This is for a QUdpSocket that was connect()ed
qint64 written = d->socketEngine->write(data, size);
if (written < 0) {
d->socketError = d->socketEngine->error();
@@ -2159,6 +2231,12 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
return written;
}
+ // This is the code path for normal buffered QTcpSocket or
+ // unbuffered QTcpSocket when there was already something in the
+ // write buffer and therefore we could not do a direct engine write.
+ // We just write to our write buffer and enable the write notifier
+ // The write notifier then flush()es the buffer.
+
char *ptr = d->writeBuffer.reserve(size);
if (size == 1)
*ptr = *data;