Details
-
Bug
-
Resolution: Done
-
P2: Important
-
4.7.2
-
None
-
windows 7
-
b8453b6fe3552cdfe32c726f87bb30d897c679b0
Description
FTP data transfer hangs sometimes during a GET command, typically the data has been transferred but the commandFinished() signal is not emitted.
Reason of this behaviour:
1. In the Qt event loop (qt_internal_proc() in qeventdispatcher_win.cpp) FD_ACCEPT, FD_READ, and FD_CLOSE messages are sent as QEvent::SockAct to the QSocketNotifier instance which has been registered for reading. In the case of QFtp this is QReadNotifier (implemented in qnativesocketengine.cpp). This means the QSocket* implementation cannot distiguish between FD_READ and FD_CLOSE messages.
2. The message is sent via QReadNotifier::event(), QAbstractSocketEngine::readNotification(), and QAbstractSocketPrivate::canReadNotification(). Finally, QNativeSocketEngine::read() closes the socket if 0 bytes were read and if it's a tcp socket. This works as long as a) the socket is not emtpy while FD_READ messages are processed, and b) the socket is empty when the final FD_CLOSE message is processed.
3. The documentation of WSAAsyncSelect(), see http://msdn.microsoft.com/en-us/library/ms741540(v=vs.85).aspx is particularly unclear about this point but it states: "FD_CLOSE should only be posted after all data is read from a socket, but an application should check for remaining data upon receipt of FD_CLOSE to avoid any possibility of losing data." Some discussion about this behaviour can also be found in the internet.
4. The same documentation states: an FD_READ message is sent "... After recv or recvfrom is called, with or without MSG_PEEK), if data is still available to receive", i.e. when data is left on the socket after any read operation.
5. This is the case we ran into: FD_CLOSE is processed (sometimes) way BEFORE the last FD_READ messages, and while the socket still has bytes available.
Example: 16400 bytes are available on the socket, one FD_READ and one FD_CLOSE message are pending:
a) Good case:
- FD_READ triggers QNativeSocketEngine::read() to read 8192 bytes, 8208 bytes left, a new FD_READ is sent
- It doesn't matter whether the 2nd FD_READ or the FD_CLOSE is processed first because Qt doesn't distiguish them: again 8192 bytes are read, 16 bytes are left, a new FD_READ is triggered.
- 3rd FD_READ or the FD_CLOSE is processed: 8 bytes read, 0 left, no further FD_READ is sent.
- the final message is processed: 0 bytes read, Qt closes the socket
b) Bad case:
- FD_CLOSE is processed before FD_READ. In that case QNativeSocketEngine::read() will read 8192 bytes for the FD_CLOSE message, 8208 bytes left, a new FD_READ is sent.
- 1st FD_READ is processed: 8192 bytes read, 16 bytes left, a new FD_READ is sent.
- 2nd FD_READ is processed: 16 bytes read, 0 bytes left, no further FD_READ is sent.
- the socket will never be closed (and QFtp hangs) because no message will ever arrive for this socket
Attachments
Issue Links
- relates to
-
QTBUG-19465 Network Authentication on Windows
- Closed
For Gerrit Dashboard: QTBUG-19409 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
30628,7 | QtNetwork: Handle FD_CLOSE on Windows | master | qt/qtbase | Status: MERGED | +2 | 0 |