QNetworkAccessManager post method freezes the calling thread when internet access is down
-
Hi!
Please consider the following scenario on WIndows 10 x64 and Qt 5.12.4:
Use a computer with an ethernet connection with internet access with this setup:
PC - ethernet cable 1- ethernet switch - ethernet cable 2 - internet gateway
Now Windows will not immediately detect that the ethernet interface is down when we unplug ethernet cable 2.Now make sure you have internet access, unplug ethernet cable 2, make a post request with QNetworkAccessManager from the gui thread. the gui thread freezes for 10-20 seconds until post returns.
I have compiled this in debug mode and interrupted the process, here is the call stack:
Note that nplugging ethernet cable 1 instead of ethernet cable 2 won't freeze the thread (as the ethernet interface will be down I guess.)
1 NtWaitForSingleObject ntdll 0x7ffd67fcaa24 2 WaitForSingleObjectEx KERNELBASE 0x7ffd64339252 3 QMutexPrivate::wait qmutex_win.cpp 64 0x7ffd1335bf5c 4 QBasicMutex::lockInternal qmutex.cpp 573 0x7ffd1335b8c4 5 QBasicMutex::lockInternal qmutex.cpp 490 0x7ffd1335b658 6 QBasicMutex::lock qmutex.h 80 0x7ffd13320184 7 QRecursiveMutexPrivate::lock qmutex.cpp 707 0x7ffd1335d69f 8 QMutex::lock qmutex.cpp 226 0x7ffd1335bd51 9 QMutexLocker::QMutexLocker qmutex.h 207 0x7ffd1331a48d 10 QSslSocketPrivate::ensureLibraryLoaded qsslsocket_openssl11.cpp 90 0x7ffd168cdbf1 11 QSslSocketPrivate::supportsSsl qsslsocket_openssl.cpp 497 0x7ffd168b7f79 12 QSslSocketPrivate::ensureInitialized qsslsocket_openssl.cpp 509 0x7ffd168b7fe9 13 QSslConfigurationPrivate::defaultConfiguration qsslsocket.cpp 2280 0x7ffd168980fe 14 QSslConfiguration::defaultConfiguration qsslconfiguration.cpp 1023 0x7ffd16887233 15 QNetworkRequest::sslConfiguration qnetworkrequest.cpp 675 0x7ffd1671eccb 16 QNetworkReplyHttpImpl::QNetworkReplyHttpImpl qnetworkreplyhttpimpl.cpp 193 0x7ffd167d04ae 17 QNetworkAccessManager::createRequest qnetworkaccessmanager.cpp 1480 0x7ffd166f5f72 18 QNetworkAccessManager::post qnetworkaccessmanager.cpp 882 0x7ffd166f3f02 19 QNetworkAccessManager::post qnetworkaccessmanager.cpp 897 0x7ffd166f3fe9 20 ApiConnectorMgr::postPingData ApiConnectorMgr.cpp 572 0x7ff7815613ab 21 ApiConnectorMgr::updateCloudServerStatus ApiConnectorMgr.cpp 1078 0x7ff7815614ce 22 ApiConnectorMgr::ApiConnectorMgr ApiConnectorMgr.cpp 58 0x7ff781556f18 23 MainWindow::MainWindow mainwindow.cpp 121 0x7ff78143bbf8 24 main main.cpp 122 0x7ff781438636 25 invoke_main exe_common.inl 65 0x7ff781598274 26 __scrt_common_main_seh exe_common.inl 253 0x7ff781598137 27 __scrt_common_main exe_common.inl 296 0x7ff781597ffe 28 mainCRTStartup exe_main.cpp 17 0x7ff781598299 29 BaseThreadInitThunk KERNEL32 0x7ffd67e54034 30 RtlUserThreadStart ntdll 0x7ffd67fa3691
The lock seems to come from a QMutexLocker in qsslsocket_openssl11.cpp
qsslsocket_openssl11.cpp line 83 bool QSslSocketPrivate::ensureLibraryLoaded() { if (!q_resolveOpenSslSymbols()) return false; const QMutexLocker locker(qt_opensslInitMutex); [interrupted here] -> if (!s_libraryLoaded) { // Initialize OpenSSL. if (q_OPENSSL_init_ssl(0, nullptr) != 1) return false; q_SSL_load_error_strings(); q_OpenSSL_add_all_algorithms(); QSslSocketBackendPrivate::s_indexForSSLExtraData = q_CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, 0L, nullptr, nullptr, nullptr, nullptr); // Initialize OpenSSL's random seed. if (!q_RAND_status()) { qWarning("Random number generator not seeded, disabling SSL support"); return false; } s_libraryLoaded = true; } return true; }
Thanks for your help!
-
This post is deleted!
-
have you isolated this behaviour to prove that it only happens in an ssl post connection? what about non-ssl web services with other providers? Does it occur in linux or just windows?
IIRC the network sockets API must run in the GUI thread so moving it to a different event loop probably isn't a valid work-around. Can someone verify my assertion about the GUI thread and networking???
Since it seems to occur when initializing the ssl layer what happens if you do an ssl connection that you know will work first, as a way to initialize, then attempt the one that is non-reachable?
-
@kent-dorfman No, sockets can be used in other threads but you have to be careful to create them in the thread that will use them.
-
Hi @jojopirato,
there are several reports of similar behavior, e.g. https://bugreports.qt.io/browse/QTBUG-60916 and all were closed as invalid.
Timur stated there, that QNAM already operates in an own thread. So if you encounter freezes, that is either a bug or a mis-use of the API.
Can you show a minimal example that illustrates that blocking behavior?
Regards
-
Hi, I have submitted a QT bug with an example and an updated procedure here: