Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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?


  • Lifetime Qt Champion

    @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.


  • Lifetime Qt Champion

    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:

    https://bugreports.qt.io/browse/QTBUG-77370


Log in to reply