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 <shane.kearns@accenture.com>
bb10
Martin Petersson 2012-07-11 12:31:29 +02:00 committed by Qt by Nokia
parent e178b49522
commit b8453b6fe3
11 changed files with 69 additions and 16 deletions

View File

@ -275,6 +275,8 @@ public:
ThemeChange = 210,
SockClose = 211, // socket closed
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event

View File

@ -377,7 +377,6 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
int type = -1;
switch (WSAGETSELECTEVENT(lp)) {
case FD_READ:
case FD_CLOSE:
case FD_ACCEPT:
type = 0;
break;
@ -388,16 +387,24 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
case FD_OOB:
type = 2;
break;
case FD_CLOSE:
type = 3;
break;
}
if (type >= 0) {
Q_ASSERT(d != 0);
QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read };
QSNDict *dict = sn_vec[type];
QSockNot *sn = dict ? dict->value(wp) : 0;
if (sn) {
QEvent event(QEvent::SockAct);
QCoreApplication::sendEvent(sn->obj, &event);
if (type < 3) {
QEvent event(QEvent::SockAct);
QCoreApplication::sendEvent(sn->obj, &event);
} else {
QEvent event(QEvent::SockClose);
QCoreApplication::sendEvent(sn->obj, &event);
}
}
}
return 0;

View File

@ -287,7 +287,7 @@ void QSocketNotifier::setEnabled(bool enable)
bool QSocketNotifier::event(QEvent *e)
{
Q_D(QSocketNotifier);
// Emits the activated() signal when a QEvent::SockAct is
// Emits the activated() signal when a QEvent::SockAct or QEvent::SockClose is
// received.
if (e->type() == QEvent::ThreadChange) {
if (d->snenabled) {
@ -297,7 +297,7 @@ bool QSocketNotifier::event(QEvent *e)
}
}
QObject::event(e); // will activate filters
if (e->type() == QEvent::SockAct) {
if ((e->type() == QEvent::SockAct) || (e->type() == QEvent::SockClose)) {
emit activated(d->sockfd);
return true;
}

View File

@ -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

View File

@ -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();

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -134,6 +134,7 @@ public:
// from QAbstractSocketEngineReceiver
void readNotification();
void closeNotification() { readNotification(); }
inline void writeNotification() {}
inline void exceptionNotification() {}
inline void connectionNotification() {}

View File

@ -3820,11 +3820,6 @@ void tst_QNetworkReply::ioPutToFileFromSocket()
SocketPair socketpair;
QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
#ifdef Q_OS_WIN
//128k and 2M tests regularly fail. Assumed same characteristics as ioPostToHttpFromSocket
if (data.size() > 1000)
QSKIP("unstable on windows - QTBUG-25386");
#endif
socketpair.endPoints[0]->write(data);
QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), socketpair.endPoints[1]));
socketpair.endPoints[0]->close();
@ -4110,11 +4105,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocket()
QFETCH(QByteArray, data);
QFETCH(QUrl, url);
QFETCH(QNetworkProxy, proxy);
#ifdef Q_OS_WIN
//QTBUG-25386 hits one of the 128k tests 50% of the time, one of the 4k tests rarely (but at least 1%)
if (data.size() > 1000)
QSKIP("unstable on windows - QTBUG-25386");
#endif
SocketPair socketpair;
QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451

View File

@ -108,6 +108,7 @@ protected slots:
private:
void readNotification() { }
void writeNotification() { }
void closeNotification() { }
void exceptionNotification() { }
void connectionNotification() { }
QTcpSocket *tcpSocketNonBlocking_socket;