diff options
Diffstat (limited to 'src/network/socket/qabstractsocket.cpp')
-rw-r--r-- | src/network/socket/qabstractsocket.cpp | 152 |
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); } } |