QUdpSocket::hasPendingDatagrams() broken in Qt 5.5 on Windows Desktop
-
It seems that c86ca601edfde6e7b6a0769903d86bd48e26d70d has broken Qt 5.5 for our application. We are getting QIODevice::readReady() signals when we send datagrams on the socket and then calls to hasPendingDatagrams() return true and pendingDatagramSize() is returning zero. The problem is that we cannot ignore these "false" pending datagrams since that goes into a loop but if we try and read them then the readDatagram() triggers an error() signal due to the same WSAECONNRESET error.
I believe this is because the writeDatagram is getting ICMP port unreachable because we are sending to the local host and no application is bound to the port (a valid scenario and not an error). WSARecvFrom documents that it will fail with WSAECONNRESET in these circumstances but that should not be interpreted as a pending datagram. Qt 5.4 worked as expected by consuming the "false" message in hasPendingDatagrams() and returning false.
I believe that an empty datagram is valid so somehow QUdpSocket must differentiate between this error and a valid empty datagram.
TIA
Bill. -
Here is a test program that demonstrates the issue:
#include <QCoreApplication> #include <QTimer> #include <QUdpSocket> #include <QHostAddress> #include <QByteArray> #include <QDebug> // // trivial UDP socket class that sends datagrams to a server and // processes any replies that may turn up // class MyUdpSocket final : public QUdpSocket { Q_OBJECT public: MyUdpSocket (QObject* parent = nullptr) : QUdpSocket {parent} { // report socket errors connect (this, static_cast<void (MyUdpSocket::*) (MyUdpSocket::SocketError)> (&MyUdpSocket::error) , [this] (MyUdpSocket::SocketError const& err) { qDebug () << "socket error:" << err << ":" << errorString (); }); connect (this, &MyUdpSocket::readyRead, this, &MyUdpSocket::get_reply); // bind to ephemeral port for any replies from server if (!bind ()) qDebug () << "bind failed"; // send periodic datagrams to any server listening localhost:2237 auto timer = new QTimer {this}; connect (timer, &QTimer::timeout, [this]() { static const QByteArray ba {10, 'a'}; auto bytes_sent = writeDatagram(ba, QHostAddress::LocalHost, 2237); qDebug () << "wrote" << bytes_sent << "byte datagram"; }); timer->start (2000); } private: // process replies from server Q_SLOT void get_reply () { int i {0}; while (hasPendingDatagrams ()) { buffer_.resize (pendingDatagramSize ()); QHostAddress sender; quint16 sender_port; auto size = readDatagram (buffer_.data (), buffer_.size (), &sender, &sender_port); qDebug() << ++i << "read" << size << "of" << buffer_.size () << "bytesAvailable()" << bytesAvailable (); } } QByteArray buffer_; }; int main (int argc, char * argv[]) { QCoreApplication a {argc, argv}; MyUdpSocket socket; return a.exec (); } #include "main.moc"
and here is the output on Windows:
main wrote 10 byte datagram socket error: QAbstractSocket::NetworkError : "Unable to receive a message" 1 read -1 of 0 bytesAvailable() 0 wrote 10 byte datagram socket error: QAbstractSocket::NetworkError : "Unable to receive a message" 1 read -1 of 0 bytesAvailable() 0 wrote 10 byte datagram socket error: QAbstractSocket::NetworkError : "Unable to receive a message" 1 read -1 of 0 bytesAvailable() 0 wrote 10 byte datagram socket error: QAbstractSocket::NetworkError : "Unable to receive a message" 1 read -1 of 0 bytesAvailable() 0 wrote 10 byte datagram socket error: QAbstractSocket::NetworkError : "Unable to receive a message" 1 read -1 of 0 bytesAvailable() 0
TIA
Bill. -
Raised issue https://bugreports.qt.io/browse/QTBUG-49301