From b8453b6fe3552cdfe32c726f87bb30d897c679b0 Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Wed, 11 Jul 2012 12:31:29 +0200 Subject: QtNetwork: Handle FD_CLOSE on Windows We need to handle FD_CLOSE separately on Windows as this will be sent only once. When we get FD_CLOSE we need to check if there is more data available for reading. It there is this might indicate that there is another FD_READ that we need to handle after the FD_CLOSE. So in this case we will manually create another close event. Task-number: QTBUG-19409 Task-number: QTBUG-25386 Change-Id: Ie19906bc3f64fb6a85a508a5ab12caac5d70ccdb Reviewed-by: Shane Kearns --- src/network/socket/qabstractsocket.cpp | 38 ++++++++++++++++++++++++++++ src/network/socket/qabstractsocket_p.h | 2 ++ src/network/socket/qabstractsocketengine.cpp | 6 +++++ src/network/socket/qabstractsocketengine_p.h | 2 ++ src/network/socket/qnativesocketengine.cpp | 3 +++ src/network/socket/qtcpserver.cpp | 1 + 6 files changed, 52 insertions(+) (limited to 'src/network') diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 6b4e48fe62..7c91022759 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -744,6 +744,44 @@ bool QAbstractSocketPrivate::canReadNotification() return true; } +/*! \internal + + Slot connected to the close socket notifier. It's called when the + socket is closed. +*/ +void QAbstractSocketPrivate::canCloseNotification() +{ + Q_Q(QAbstractSocket); + +#if defined (QABSTRACTSOCKET_DEBUG) + qDebug("QAbstractSocketPrivate::canCloseNotification()"); +#endif + + qint64 newBytes = 0; + if (isBuffered) { + // Try to read to the buffer, if the read fail we can close the socket. + newBytes = buffer.size(); + if (!readFromSocket()) { + q->disconnectFromHost(); + return; + } + newBytes = buffer.size() - newBytes; + if (newBytes) { + // If there was still some data to be read from the socket + // then we could get another FD_READ. The disconnect will + // then occur when we read from the socket again and fail + // in canReadNotification or by the manually created + // closeNotification below. + emit q->readyRead(); + + QMetaObject::invokeMethod(socketEngine, "closeNotification", Qt::QueuedConnection); + } + } else if (socketType == QAbstractSocket::TcpSocket && socketEngine) { + emit q->readyRead(); + } +} + + /*! \internal Slot connected to the write socket notifier. It's called during a diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 21d85f74fe..b19801882e 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -77,6 +77,7 @@ public: inline void readNotification() { canReadNotification(); } inline void writeNotification() { canWriteNotification(); } inline void exceptionNotification() {} + inline void closeNotification() { canCloseNotification(); } void connectionNotification(); #ifndef QT_NO_NETWORKPROXY inline void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator) { @@ -87,6 +88,7 @@ public: bool canReadNotification(); bool canWriteNotification(); + void canCloseNotification(); // slots void _q_connectToNextAddress(); diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp index e9e49d41ec..f05fa98a96 100644 --- a/src/network/socket/qabstractsocketengine.cpp +++ b/src/network/socket/qabstractsocketengine.cpp @@ -168,6 +168,12 @@ void QAbstractSocketEngine::exceptionNotification() receiver->exceptionNotification(); } +void QAbstractSocketEngine::closeNotification() +{ + if (QAbstractSocketEngineReceiver *receiver = d_func()->receiver) + receiver->closeNotification(); +} + void QAbstractSocketEngine::connectionNotification() { if (QAbstractSocketEngineReceiver *receiver = d_func()->receiver) diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h index 92d795408f..5264bc4479 100644 --- a/src/network/socket/qabstractsocketengine_p.h +++ b/src/network/socket/qabstractsocketengine_p.h @@ -71,6 +71,7 @@ public: virtual ~QAbstractSocketEngineReceiver(){} virtual void readNotification()= 0; virtual void writeNotification()= 0; + virtual void closeNotification()= 0; virtual void exceptionNotification()= 0; virtual void connectionNotification()= 0; #ifndef QT_NO_NETWORKPROXY @@ -173,6 +174,7 @@ public: public Q_SLOTS: void readNotification(); void writeNotification(); + void closeNotification(); void exceptionNotification(); void connectionNotification(); #ifndef QT_NO_NETWORKPROXY diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index f2e2f692ac..3dca7aa9ee 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -1142,6 +1142,9 @@ bool QReadNotifier::event(QEvent *e) if (e->type() == QEvent::SockAct) { engine->readNotification(); return true; + } else if (e->type() == QEvent::SockClose) { + engine->closeNotification(); + return true; } return QSocketNotifier::event(e); } diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index 4d8aad0dba..7955928727 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -134,6 +134,7 @@ public: // from QAbstractSocketEngineReceiver void readNotification(); + void closeNotification() { readNotification(); } inline void writeNotification() {} inline void exceptionNotification() {} inline void connectionNotification() {} -- cgit v1.2.3