Windows socket engine: do not discard datagram on critical failure
On some network conditions, WSARecvFrom() may return WSAECONNRESET or WSAENETRESET error code to indicate that the connection has been broken and should be reset. According to MSDN documentation, WSAECONNRESET mean that the virtual circuit was reset by the remote side executing a hard or abortive close. Also, it would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message. For a datagram socket, WSAENETRESET indicates that the time to live has expired. Previously, hasPendingDatagram() discarded datagrams with these errors and reported no data available. This behavior is incorrect and can lead to infinite "freezing" of the socket. This patch allows to handle these notifications as a result of the readDatagram() call. Task-number: QTBUG-46552 Change-Id: I7d84babe22d36736b928b4dd4841e30be53d16bd Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com> Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>bb10
parent
a6ec869211
commit
c86ca601ed
|
|
@ -1090,8 +1090,11 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
|
|||
buf.buf = &c;
|
||||
buf.len = sizeof(c);
|
||||
DWORD flags = MSG_PEEK;
|
||||
if (::WSARecvFrom(socketDescriptor, &buf, 1, 0, &flags, 0,0,0,0) == SOCKET_ERROR)
|
||||
return 0;
|
||||
if (::WSARecvFrom(socketDescriptor, &buf, 1, 0, &flags, 0,0,0,0) == SOCKET_ERROR) {
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAECONNRESET && err != WSAENETRESET)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
|
@ -1119,14 +1122,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
|
|||
int err = WSAGetLastError();
|
||||
if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) {
|
||||
WS_ERROR_DEBUG(err);
|
||||
if (err == WSAECONNRESET || err == WSAENETRESET) {
|
||||
// Discard error message to prevent QAbstractSocket from
|
||||
// getting this message repeatedly after reenabling the
|
||||
// notifiers.
|
||||
flags = 0;
|
||||
::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags,
|
||||
&storage.a, &storageSize, 0, 0);
|
||||
}
|
||||
result = (err == WSAECONNRESET || err == WSAENETRESET);
|
||||
} else {
|
||||
// If there's no error, or if our buffer was too small, there must be
|
||||
// a pending datagram.
|
||||
|
|
@ -1179,12 +1175,21 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
|
|||
if (recvResult != SOCKET_ERROR) {
|
||||
ret = qint64(bytesRead);
|
||||
break;
|
||||
} else if (recvResult == SOCKET_ERROR && err == WSAEMSGSIZE) {
|
||||
bufferCount += 5;
|
||||
delete[] buf;
|
||||
} else if (recvResult == SOCKET_ERROR) {
|
||||
WS_ERROR_DEBUG(err);
|
||||
ret = -1;
|
||||
} else {
|
||||
switch (err) {
|
||||
case WSAEMSGSIZE:
|
||||
bufferCount += 5;
|
||||
delete[] buf;
|
||||
continue;
|
||||
case WSAECONNRESET:
|
||||
case WSAENETRESET:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
WS_ERROR_DEBUG(err);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue