diff options
author | Alex Trotsenko <alex1973tr@gmail.com> | 2015-08-11 13:23:32 +0300 |
---|---|---|
committer | Alex Trotsenko <alex1973tr@gmail.com> | 2015-09-10 12:51:02 +0000 |
commit | a6ec869211d67fed94e3513dc453a96717155121 (patch) | |
tree | abdf5a1a449c9b8474e6c7db17a617fd7766afb2 /tests | |
parent | 378e26dd14df808a55471330400984841ef414d4 (diff) |
Fix the spurious socket notifications under Windows
To handle network events, QEventDispatcherWin32 uses I/O model
based on notifications through the window message queue. Having
successfully posted notification of a particular event to an
application window, no further messages for that network event
will be posted to the application window until the application
makes the function call that implicitly re-enables notification
of that network event. With these semantics, an application need
not read all available data in response to an FD_READ message:
a single recv in response to each FD_READ message is appropriate.
If an application issues multiple recv calls in response to a
single FD_READ, it can receive multiple FD_READ messages
(including spurious).
To solve this issue, this patch always disables the notifier
after getting a notification, and re-enables it only when the
message queue is empty.
Task-number: QTBUG-46552
Change-Id: I05df67032911cd1f5927fa7912f7864bfbf8711e
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp b/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp index 930a17c3a9..f49da1f5a8 100644 --- a/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp +++ b/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp @@ -40,6 +40,7 @@ #include <QtCore/QSocketNotifier> #include <QtNetwork/QTcpServer> #include <QtNetwork/QTcpSocket> +#include <QtNetwork/QUdpSocket> #ifndef Q_OS_WINRT #include <private/qnativesocketengine_p.h> #else @@ -66,8 +67,29 @@ private slots: #ifdef Q_OS_UNIX void posixSockets(); #endif + void asyncMultipleDatagram(); + +protected slots: + void async_readDatagramSlot(); + void async_writeDatagramSlot(); + +private: + QUdpSocket *m_asyncSender; + QUdpSocket *m_asyncReceiver; }; +static QHostAddress makeNonAny(const QHostAddress &address, + QHostAddress::SpecialAddress preferForAny = QHostAddress::LocalHost) +{ + if (address == QHostAddress::Any) + return preferForAny; + if (address == QHostAddress::AnyIPv4) + return QHostAddress::LocalHost; + if (address == QHostAddress::AnyIPv6) + return QHostAddress::LocalHostIPv6; + return address; +} + class UnexpectedDisconnectTester : public QObject { Q_OBJECT @@ -299,5 +321,56 @@ void tst_QSocketNotifier::posixSockets() } #endif +void tst_QSocketNotifier::async_readDatagramSlot() +{ + char buf[1]; + QVERIFY(m_asyncReceiver->hasPendingDatagrams()); + do { + QCOMPARE(m_asyncReceiver->pendingDatagramSize(), qint64(1)); + QCOMPARE(m_asyncReceiver->readDatagram(buf, sizeof(buf)), qint64(1)); + if (buf[0] == '1') { + // wait for the second datagram message. + QTest::qSleep(100); + } + } while (m_asyncReceiver->hasPendingDatagrams()); + + if (buf[0] == '3') + QTestEventLoop::instance().exitLoop(); +} + +void tst_QSocketNotifier::async_writeDatagramSlot() +{ + m_asyncSender->writeDatagram("3", makeNonAny(m_asyncReceiver->localAddress()), + m_asyncReceiver->localPort()); +} + +void tst_QSocketNotifier::asyncMultipleDatagram() +{ + m_asyncSender = new QUdpSocket; + m_asyncReceiver = new QUdpSocket; + + QVERIFY(m_asyncReceiver->bind(QHostAddress(QHostAddress::AnyIPv4), 0)); + quint16 port = m_asyncReceiver->localPort(); + QVERIFY(port != 0); + + QSignalSpy spy(m_asyncReceiver, &QIODevice::readyRead); + connect(m_asyncReceiver, &QIODevice::readyRead, this, + &tst_QSocketNotifier::async_readDatagramSlot); + m_asyncSender->writeDatagram("1", makeNonAny(m_asyncReceiver->localAddress()), port); + m_asyncSender->writeDatagram("2", makeNonAny(m_asyncReceiver->localAddress()), port); + // wait a little to ensure that the datagrams we've just sent + // will be delivered on receiver side. + QTest::qSleep(100); + + QTimer::singleShot(500, this, &tst_QSocketNotifier::async_writeDatagramSlot); + + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(spy.count(), 2); + + delete m_asyncSender; + delete m_asyncReceiver; +} + QTEST_MAIN(tst_QSocketNotifier) #include <tst_qsocketnotifier.moc> |