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.cpp152
1 files changed, 79 insertions, 73 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 88237dc416..fbc7088a02 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -267,7 +267,8 @@
\value TcpSocket TCP
\value UdpSocket UDP
- \value UnknownSocketType Other than TCP and UDP
+ \value SctpSocket SCTP
+ \value UnknownSocketType Other than TCP, UDP and SCTP
\sa QAbstractSocket::socketType()
*/
@@ -563,6 +564,7 @@ QAbstractSocketPrivate::QAbstractSocketPrivate()
cachedSocketDescriptor(-1),
readBufferMaxSize(0),
isBuffered(false),
+ hasPendingData(false),
connectTimer(0),
disconnectTimer(0),
hostLookupId(-1),
@@ -593,6 +595,7 @@ void QAbstractSocketPrivate::resetSocketLayer()
qDebug("QAbstractSocketPrivate::resetSocketLayer()");
#endif
+ hasPendingData = false;
if (socketEngine) {
socketEngine->close();
socketEngine->disconnect();
@@ -624,6 +627,7 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
QString typeStr;
if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
+ else if (q->socketType() == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket");
else typeStr = QLatin1String("UnknownSocketType");
QString protocolStr;
if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
@@ -668,6 +672,12 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
*/
void QAbstractSocketPrivate::configureCreatedSocket()
{
+#ifndef QT_NO_SCTP
+ Q_Q(QAbstractSocket);
+ // Set single stream mode for unbuffered SCTP socket
+ if (socketEngine && q->socketType() == QAbstractSocket::SctpSocket)
+ socketEngine->setOption(QAbstractSocketEngine::MaxStreamsSocketOption, 1);
+#endif
}
/*! \internal
@@ -683,14 +693,20 @@ bool QAbstractSocketPrivate::canReadNotification()
qDebug("QAbstractSocketPrivate::canReadNotification()");
#endif
- if (!isBuffered)
- socketEngine->setReadNotificationEnabled(false);
+ if (!isBuffered) {
+ if (hasPendingData) {
+ socketEngine->setReadNotificationEnabled(false);
+ return true;
+ }
+ hasPendingData = true;
+ }
// If buffered, read data from the socket into the read buffer
qint64 newBytes = 0;
if (isBuffered) {
// Return if there is no space in the buffer
if (readBufferMaxSize && buffer.size() >= readBufferMaxSize) {
+ socketEngine->setReadNotificationEnabled(false);
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canReadNotification() buffer is full");
#endif
@@ -708,11 +724,6 @@ bool QAbstractSocketPrivate::canReadNotification()
return false;
}
newBytes = buffer.size() - newBytes;
-
- // If read buffer is full, disable the read socket notifier.
- if (readBufferMaxSize && buffer.size() == readBufferMaxSize) {
- socketEngine->setReadNotificationEnabled(false);
- }
}
// Only emit readyRead() if there is data available.
@@ -728,10 +739,6 @@ bool QAbstractSocketPrivate::canReadNotification()
return true;
}
- // turn the socket engine off if we've reached the buffer size limit
- if (socketEngine && isBuffered)
- socketEngine->setReadNotificationEnabled(readBufferMaxSize == 0 || readBufferMaxSize > q->bytesAvailable());
-
return true;
}
@@ -772,7 +779,8 @@ void QAbstractSocketPrivate::canCloseNotification()
QMetaObject::invokeMethod(socketEngine, "closeNotification", Qt::QueuedConnection);
}
- } else if (socketType == QAbstractSocket::TcpSocket && socketEngine) {
+ } else if ((socketType == QAbstractSocket::TcpSocket ||
+ socketType == QAbstractSocket::SctpSocket) && socketEngine) {
emitReadyRead();
}
}
@@ -788,12 +796,8 @@ bool QAbstractSocketPrivate::canWriteNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canWriteNotification() flushing");
#endif
- bool dataWasWritten = writeToSocket();
- if (socketEngine && writeBuffer.isEmpty() && socketEngine->bytesToWrite() == 0)
- socketEngine->setWriteNotificationEnabled(false);
-
- return dataWasWritten;
+ return writeToSocket();
}
/*! \internal
@@ -833,8 +837,12 @@ bool QAbstractSocketPrivate::writeToSocket()
#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)
+ if (state == QAbstractSocket::ClosingState) {
q->disconnectFromHost();
+ } else {
+ if (socketEngine)
+ socketEngine->setWriteNotificationEnabled(false);
+ }
return false;
}
@@ -863,17 +871,12 @@ bool QAbstractSocketPrivate::writeToSocket()
if (written > 0) {
// Remove what we wrote so far.
writeBuffer.free(written);
- // Don't emit bytesWritten() recursively.
- if (!emittedBytesWritten) {
- QScopedValueRollback<bool> r(emittedBytesWritten);
- emittedBytesWritten = true;
- emit q->bytesWritten(written);
- }
- emit q->channelBytesWritten(0, written);
+
+ // Emit notifications.
+ emitBytesWritten(written);
}
- if (writeBuffer.isEmpty() && socketEngine && socketEngine->isWriteNotificationEnabled()
- && !socketEngine->bytesToWrite())
+ if (writeBuffer.isEmpty() && socketEngine && !socketEngine->bytesToWrite())
socketEngine->setWriteNotificationEnabled(false);
if (state == QAbstractSocket::ClosingState)
q->disconnectFromHost();
@@ -891,7 +894,7 @@ bool QAbstractSocketPrivate::flush()
{
bool dataWasWritten = false;
- while (!writeBuffer.isEmpty() && writeToSocket())
+ while (!allWriteBuffersEmpty() && writeToSocket())
dataWasWritten = true;
return dataWasWritten;
@@ -914,6 +917,8 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
QNetworkProxyQuery query(hostname, port, QString(),
socketType == QAbstractSocket::TcpSocket ?
QNetworkProxyQuery::TcpSocket :
+ socketType == QAbstractSocket::SctpSocket ?
+ QNetworkProxyQuery::SctpSocket :
QNetworkProxyQuery::UdpSocket);
proxies = QNetworkProxyFactory::proxyForQuery(query);
}
@@ -928,6 +933,10 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
(p.capabilities() & QNetworkProxy::TunnelingCapability) == 0)
continue;
+ if (socketType == QAbstractSocket::SctpSocket &&
+ (p.capabilities() & QNetworkProxy::SctpTunnelingCapability) == 0)
+ continue;
+
proxyInUse = p;
return;
}
@@ -1146,12 +1155,10 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
*/
void QAbstractSocketPrivate::_q_testConnection()
{
- if (socketEngine) {
- if (threadData->hasEventDispatcher()) {
- if (connectTimer)
- connectTimer->stop();
- }
+ if (connectTimer)
+ connectTimer->stop();
+ if (socketEngine) {
if (socketEngine->state() == QAbstractSocket::ConnectedState) {
// Fetch the parameters if our connection is completed;
// otherwise, fall out and try the next address.
@@ -1168,11 +1175,6 @@ void QAbstractSocketPrivate::_q_testConnection()
addresses.clear();
}
- if (threadData->hasEventDispatcher()) {
- if (connectTimer)
- connectTimer->stop();
- }
-
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::_q_testConnection() connection failed,"
" checking for alternative addresses");
@@ -1289,16 +1291,34 @@ bool QAbstractSocketPrivate::readFromSocket()
Prevents from the recursive readyRead() emission.
*/
-void QAbstractSocketPrivate::emitReadyRead()
+void QAbstractSocketPrivate::emitReadyRead(int channel)
{
Q_Q(QAbstractSocket);
// Only emit readyRead() when not recursing.
- if (!emittedReadyRead) {
+ if (!emittedReadyRead && channel == currentReadChannel) {
QScopedValueRollback<bool> r(emittedReadyRead);
emittedReadyRead = true;
emit q->readyRead();
}
- emit q->channelReadyRead(0);
+ // channelReadyRead() can be emitted recursively - even for the same channel.
+ emit q->channelReadyRead(channel);
+}
+
+/*! \internal
+
+ Prevents from the recursive bytesWritten() emission.
+*/
+void QAbstractSocketPrivate::emitBytesWritten(qint64 bytes, int channel)
+{
+ Q_Q(QAbstractSocket);
+ // Only emit bytesWritten() when not recursing.
+ if (!emittedBytesWritten && channel == currentWriteChannel) {
+ QScopedValueRollback<bool> r(emittedBytesWritten);
+ emittedBytesWritten = true;
+ emit q->bytesWritten(bytes);
+ }
+ // channelBytesWritten() can be emitted recursively - even for the same channel.
+ emit q->channelBytesWritten(channel, bytes);
}
/*! \internal
@@ -1409,8 +1429,8 @@ QAbstractSocket::QAbstractSocket(SocketType socketType,
Q_D(QAbstractSocket);
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::QAbstractSocket(%sSocket, QAbstractSocketPrivate == %p, parent == %p)",
- socketType == TcpSocket ? "Tcp" : socketType == UdpSocket
- ? "Udp" : "Unknown", &dd, parent);
+ socketType == TcpSocket ? "Tcp" : socketType == UdpSocket ? "Udp"
+ : socketType == SctpSocket ? "Sctp" : "Unknown", &dd, parent);
#endif
d->socketType = socketType;
}
@@ -1674,9 +1694,9 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
#endif
if (openMode & QIODevice::Unbuffered)
- d->isBuffered = false; // Unbuffered QTcpSocket
+ d->isBuffered = false;
else if (!d_func()->isBuffered)
- openMode |= QAbstractSocket::Unbuffered; // QUdpSocket
+ openMode |= QAbstractSocket::Unbuffered;
QIODevice::open(openMode);
d->readChannelCount = d->writeChannelCount = 0;
@@ -2381,11 +2401,6 @@ void QAbstractSocket::abort()
return;
}
#endif
- if (d->connectTimer) {
- d->connectTimer->stop();
- delete d->connectTimer;
- d->connectTimer = 0;
- }
d->abortCalled = true;
close();
@@ -2432,15 +2447,7 @@ bool QAbstractSocket::atEnd() const
// Note! docs copied to QSslSocket::flush()
bool QAbstractSocket::flush()
{
- Q_D(QAbstractSocket);
-#ifndef QT_NO_SSL
- // Manual polymorphism; flush() isn't virtual, but QSslSocket overloads
- // it.
- if (QSslSocket *socket = qobject_cast<QSslSocket *>(this))
- return socket->flush();
-#endif
- Q_CHECK_SOCKETENGINE(false);
- return d->flush();
+ return d_func()->flush();
}
/*! \reimp
@@ -2463,8 +2470,9 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
d->setError(d->socketEngine->error(), d->socketEngine->errorString());
d->resetSocketLayer();
d->state = QAbstractSocket::UnconnectedState;
- } else if (!d->socketEngine->isReadNotificationEnabled()) {
+ } else {
// Only do this when there was no error
+ d->hasPendingData = false;
d->socketEngine->setReadNotificationEnabled(true);
}
@@ -2524,10 +2532,8 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
qt_prettyDebug(data, qMin((int)size, 32), size).data(),
size, written);
#endif
- if (written >= 0) {
- emit bytesWritten(written);
- emit channelBytesWritten(0, written);
- }
+ if (written >= 0)
+ d->emitBytesWritten(written);
return written;
}
@@ -2727,14 +2733,14 @@ void QAbstractSocket::disconnectFromHost()
}
// Wait for pending data to be written.
- if (d->socketEngine && d->socketEngine->isValid() && (d->writeBuffer.size() > 0
+ if (d->socketEngine && d->socketEngine->isValid() && (!d->allWriteBuffersEmpty()
|| 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->allWriteBuffersEmpty() && d->socketEngine->bytesToWrite() > 0) {
if (!d->disconnectTimer) {
d->disconnectTimer = new QTimer(this);
connect(d->disconnectTimer, SIGNAL(timeout()), this,
@@ -2823,12 +2829,12 @@ void QAbstractSocket::setReadBufferSize(qint64 size)
if (d->readBufferMaxSize == size)
return;
d->readBufferMaxSize = size;
- if (!d->emittedReadyRead && d->socketEngine) {
- // ensure that the read notification is enabled if we've now got
- // room in the read buffer
- // but only if we're not inside canReadNotification -- that will take care on its own
- if ((size == 0 || d->buffer.size() < size) && d->state == QAbstractSocket::ConnectedState) // Do not change the notifier unless we are connected.
- d->socketEngine->setReadNotificationEnabled(true);
+
+ // Do not change the notifier unless we are connected.
+ if (d->socketEngine && d->state == QAbstractSocket::ConnectedState) {
+ // Ensure that the read notification is enabled if we've now got
+ // room in the read buffer.
+ d->socketEngine->setReadNotificationEnabled(size == 0 || d->buffer.size() < size);
}
}