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
parent
e178b49522
commit
b8453b6fe3
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ public:
|
|||
|
||||
// from QAbstractSocketEngineReceiver
|
||||
void readNotification();
|
||||
void closeNotification() { readNotification(); }
|
||||
inline void writeNotification() {}
|
||||
inline void exceptionNotification() {}
|
||||
inline void connectionNotification() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ protected slots:
|
|||
private:
|
||||
void readNotification() { }
|
||||
void writeNotification() { }
|
||||
void closeNotification() { }
|
||||
void exceptionNotification() { }
|
||||
void connectionNotification() { }
|
||||
QTcpSocket *tcpSocketNonBlocking_socket;
|
||||
|
|
|
|||
Loading…
Reference in New Issue