c++boost-asioboost-thread

program crash using boost::asio


I am trying to download file using asio .
the program is multithreaded and system is ubuntu with gcc 7.5
in the following function:

    void HTTPRequest::ReadStatusLine(boost::asio::yield_context yield_r)
{
    boost::unique_lock<boost::mutex> ReadStatusLine_lock(mBOOST_LOGMutex, boost::defer_lock);

    boost::system::error_code ec;
    std::size_t bytes_transferred_read_status_line = boost::asio::async_read_until(mSock, mResponsePtr->get_response_buf(), "\r\n", yield_r[ec]);

    if (ec.value() != boost::system::errc::errc_t::success)
    {
        OnFinish(ec);
        this->mReadStatusLine += 1;
        this->mContinue_for = (!mContinue_for);
        //??5-17-2020 isolate multithreaded error
        ReadStatusLine_lock.lock();
        BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "\t" << "Request #" << this->GetId() << " for " << mUrl << " failed after trying " << mIrange << " times" << " to async_read_until inside HTTPRequest::ReadStatusLine with certain resolver iterator " << mSock.remote_endpoint().address().to_string() << std::endl;
        ReadStatusLine_lock.unlock();

        return;//4-2-2020 now i return to SendRequest to return to Execute to continue for loop
    }
    if (ec.value() == boost::system::errc::errc_t::success)
    {
        this->mReadStatusLine = 0;
        //??5-17-2020 isolate multithreaded error

        boost::unique_lock<boost::mutex> cancel_lock(mCancelMutex);
        if (mWasCancelled)
        {
            cancel_lock.unlock();
            OnFinish(boost::system::error_code(boost::asio::error::operation_aborted));
            BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "\t" << "Request #" << this->GetId() << " for " << mUrl << " has been cancelled by the user after returning from async_read_until inside HTTPRequest::ReadStatusLine using" << mSock.remote_endpoint().address().to_string() << std::endl;
            return;
        }
        cancel_lock.unlock();

        //here we get information to do several things
        //first we make logging system based on received status_code
        //second we make some tests to determine continuing the connection or restarting it 
        //so we should determine if to do the previous jobs here or after returning to Execute>>>>>>>>>i think i should make http1/1 test here because its result will determine if to continue to next function ReadResponseHeaders() or not ....and i think i will like to make log file for http1/1 failure 

        std::istream response_stream(&(mResponsePtr->get_response_buf()));
        response_stream >> mHTTP_Version;

        ////allam2020 i should not set response variables till request is completely finished>>>>>>no this is wrong because the design depends on HTTPResponse to record response then validate response ....so i ll use HTTPResponse instance and if request fails i ll clear it but i ll transfer the following line after mHTTP_Version test succeds
        if (mHTTP_Version != "HTTP/1.1")
        {
            // Response is incorrect.
            OnFinish(http_errors::invalid_response);
            this->mHttp_1_1 += 1;
            this->mContinue_for = (!mContinue_for);
            //??5-17-2020 isolate multithreaded error
            ReadStatusLine_lock.lock();

            BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "\t" << "Request #" << this->GetId() << " for " << mUrl << " failed after trying " << mIrange << " times" << " to async_read_until inside HTTPRequest::ReadStatusLine because of bad not http/1.1 version:" << mHTTP_Version << " response recieved with certain resolver iterator " << mSock.remote_endpoint().address().to_string() << std::endl;
            ReadStatusLine_lock.unlock();

            return;
        }
        if (mHTTP_Version == "HTTP/1.1")
        {
            this->mHttp_1_1 = 0;
        }
        mResponsePtr->set_http_version(mHTTP_Version);

        ////allam 2020 response_stream >> str_status_code;
        response_stream >> mStatusCode;

        //first we make logging files based on received status_code by async_read_until
        //4-2-2020 i think i should make these files after the end of the 5 ATTEMPTS and only do boost_log now >>>>>i make log files inside mStatusCode==200 and for mStatusCode!=200 i shall make them at the end of 5 attempts    

        std::getline(response_stream, mStatusMessage, '\r');
        // Remove symbol '\n' from the buffer.
        response_stream.get();////allam2020 4-3-2020 this function read till next new line so that the next getline after it will read the next line"here it helps to skip the empty line \n"

        if (mStatusCode != std::to_string((HttpStatus::toInt(HttpStatus::Code::OK))))

        {
            //4-3-2020 i think i should make these files after the end of the 5 ATTEMPTS and only do boost_log now
            // Response is incorrect.
            OnFinish(http_errors::invalid_response);
            this->mStatusCodeNot200 += 1;
            this->mContinue_for = (!mContinue_for);
            //??5-17-2020 isolate multithreaded error
            ReadStatusLine_lock.unlock();
            BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "\t" << "Request #" << this->GetId() << " for " << mUrl << " failed after trying " << mIrange << " times" << " to async_read_until inside HTTPRequest::ReadStatusLine because of status_code not 200:" << http_errors::invalid_response << "the error code is :" << mStatusCode << "\n" << "and the error reasonPhrase is :" << HttpStatus::reasonPhrase(static_cast<int>(std::stoul(mStatusCode))) << "with certain resolver iterator " << mSock.remote_endpoint().address().to_string() << std::endl;
            ReadStatusLine_lock.unlock();

            return;
        }

        //4-3-2020 if (std::stoul(mStatusCode) == 200)
        else if (mStatusCode == std::to_string((HttpStatus::toInt(HttpStatus::Code::OK))))
        {
            this->mStatusCodeNot200 = 0;

            ////allam2020 4-3-2020 i think that cancel is made with this synchronization to account for cancel operation which happens during async operation So i put the cancel part after ec.value() ==success directly and there is no reason to put cancel code here 

            // At this point the status line is successfully
            // received and parsed.
            //??5-17-2020 isolate multithreaded error

            ////allam2020 4-3-2020 i now make log files for mStatusCode=200
            m_formatting_ostream << boost::this_thread::get_id() << "\t" << "Request for " << mUrl << " after trying " << mIrange << " times" << " has returned " << mStatusCode << " after returning from async_read_until inside  HTTPRequest::ReadStatusLine for file:" << this->GetUrl() << " with certain resolver iterator " << mSock.remote_endpoint().address().to_string() << std::endl;
            m_formatting_ostream.flush();
            ////allam 2020 i might need to pass iterator resolve which has failed
            //4-26-2020
            //boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "status_code_async_read_until_inside_HTTPRequest_ReadStatusLine", "request_status_code_200:this_is_status_code" + mStatusCode + "with_Iterator_" + mSock.remote_endpoint().address().to_string(), m_formatting_ostream_string);
            //std::string string_replace = { mSock.remote_endpoint().address().to_string() };
            //replace(string_replace, ".", "");
            //boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "st_aru_RSL", "_" + mStatusCode + "_"+ string_replace,m_formatting_ostream_string, mBOOST_LOGMutex);
            //5-22-2020 st_aru is too long for BRENTCMDUS
            boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, mHTTPRequest_Symbol_str, "st_aru_RSL", "_" + mStatusCode  , m_formatting_ostream_string, mBOOST_LOGMutex);
            //boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, mHTTPRequest_Symbol_str, "s_RSL", "_" + mStatusCode, m_formatting_ostream_string, mBOOST_LOGMutex);
            //5-16-2020m_formatting_ostream.clear();
            m_formatting_ostream_string.clear();

            // Now read the response headers.
            mResponsePtr->set_status_code(std::stoul(mStatusCode));
            mResponsePtr->set_status_message(mStatusMessage);

            BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "ReadResponseHeaders is to be called" <<  std::endl;
            ReadResponseHeaders(yield_r);
            BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "ReadResponseHeaders returned" << std::endl;
        }
    }

}

when the server fails,and send End of file ,the thread running the function terminates.
the thread should not terminate because I will reconnect and redo all work again in infinite loop depending on variable:

this->mContinue_for = (!mContinue_for);

this is the error message:

7ffff564c700    Request #0 failed! Error code = 2. Error message = End of file
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
  what():  remote_endpoint: Transport endpoint is not connected

what should i do to prevent termination of thread??

UPDATE:take care that io_service is ran from different thread NOTE:in this question Boost.Asio read_some: End of file error the answer suggests putting the read_some function in try catch block. he without explicitly saying changes read_some whick take 2nd parameter for error to the version without error.
if i need error parameter to continue my procedure ,what can i do?

this is the output of debugger console:

Thread 2 "final_duka_5-22" hit Breakpoint 13, HTTPRequest::ReadStatusLine (this=0x7fffe8007370, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:721
721                     std::size_t bytes_transferred_read_status_line = boost::asio::async_read_until(mSock, mResponsePtr->get_response_buf(), "\r\n", yield_r[ec]);
#0  malloc (n=23) at dl-minimal.c:50
50      dl-minimal.c: No such file or directory.
#0  HTTPRequest::ReadStatusLine (this=0x7fffe8007370, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:721
721                     std::size_t bytes_transferred_read_status_line = boost::asio::async_read_until(mSock, mResponsePtr->get_response_buf(), "\r\n", yield_r[ec]);
#0  0x0000555555610877 in HTTPClient::CreateTasks (this=0x7ffff0001b60) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HttpClient_11_trying_boost_future_3_single_thread.cpp:188
188             mWork.reset(NULL);
[Switching to thread 2 (Thread 0x7ffff664e700 (LWP 6129))]
#0  HTTPRequest::ReadStatusLine (this=0x7fffe8007370, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:721
721                     std::size_t bytes_transferred_read_status_line = boost::asio::async_read_until(mSock, mResponsePtr->get_response_buf(), "\r\n", yield_r[ec]);
#0  HTTPRequest::OnFinish (this=0x7fffe80023b0, ec=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:1028
1028                            OnFinish_lock.lock();
#2  HTTPRequest::ReadStatusLine (this=0x7ffff00023b0, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:729
729                     OnFinish(ec);
#0  HTTPRequest::ReadStatusLine (this=0x7fffe8007370, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:721
721                     std::size_t bytes_transferred_read_status_line = boost::asio::async_read_until(mSock, mResponsePtr->get_response_buf(), "\r\n", yield_r[ec]);
#1  <function called from gdb>
#2  HTTPRequest::ReadStatusLine (this=0x7ffff00023b0, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:729
729                     OnFinish(ec);
#0  malloc (n=23) at dl-minimal.c:50
50      dl-minimal.c: No such file or directory.
[Switching to Thread 0x7ffff664e700 (LWP 6129)]

Thread 2 "final_duka_5-22" hit Breakpoint 15, HTTPRequest::ReadStatusLine (this=0x7fffe8007370, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:727
727             if (ec.value() != boost::system::errc::errc_t::success)
[Switching to thread 5 (Thread 0x7ffff4e4b700 (LWP 6228))](running)
[Switching to Thread 0x7ffff564c700 (LWP 6217)]
Thread 4 "final_duka_5-22" hit Breakpoint 2, HTTPRequest::ReadStatusLine (this=0x7fffe80023b0, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:734
734                     BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "\t" << "Request #" << this->GetId() << " for " << mUrl << " failed after trying " << mIrange << " times" << " to async_read_until inside HTTPRequest::ReadStatusLine with certain resolver iterator " << mSock.remote_endpoint().address().to_string() << std::endl;
#0  HTTPRequest::ReadStatusLine (this=0x7fffe80023b0, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:734
734                     BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << boost::this_thread::get_id() << "\t" << "Request #" << this->GetId() << " for " << mUrl << " failed after trying " << mIrange << " times" << " to async_read_until inside HTTPRequest::ReadStatusLine with certain resolver iterator " << mSock.remote_endpoint().address().to_string() << std::endl;
[Switching to thread 5 (Thread 0x7ffff4e4b700 (LWP 6228))](running)
[Switching to Thread 0x7ffff4e4b700 (LWP 6228)]
#0  HTTPRequest::ReadStatusLine (this=0x7ffff00023b0, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:729
729                     OnFinish(ec);
[Switching to thread 3 (Thread 0x7ffff5e4d700 (LWP 6130))](running)
[Switching to Thread 0x7ffff5e4d700 (LWP 6130)]

Thread 3 "final_duka_5-22" hit Breakpoint 13, HTTPRequest::ReadStatusLine (this=0x7ffff0007270, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:721
721                     std::size_t bytes_transferred_read_status_line = boost::asio::async_read_until(mSock, mResponsePtr->get_response_buf(), "\r\n", yield_r[ec]);
#0  HTTPRequest::ReadStatusLine (this=0x7ffff0007270, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:721
721                     std::size_t bytes_transferred_read_status_line = boost::asio::async_read_until(mSock, mResponsePtr->get_response_buf(), "\r\n", yield_r[ec]);
[Switching to thread 4 (Thread 0x7ffff564c700 (LWP 6217))](running)
[Switching to Thread 0x7ffff664e700 (LWP 6129)]

Thread 2 "final_duka_5-22" hit Breakpoint 10, HTTPRequest::ReadStatusLine (this=0x7fffe8007370, yield_r=...) at ../final_duka_5-22-2020_multi_currency_sln/final_duka_5-22-2020_multi_currency/HTTPRequest_12_multi_1.cpp:739
739             if (ec.value() == boost::system::errc::errc_t::success)
[Switching to thread 5 (Thread 0x7ffff4e4b700 (LWP 6228))](running)

Thread 4 "final_duka_5-22" received signal SIGABRT, Aborted.
[Switching to Thread 0x7ffff564c700 (LWP 6217)]
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51      in ../sysdeps/unix/sysv/linux/raise.c
[Switching to thread 5 (Thread 0x7ffff4e4b700 (LWP 6228))](running)
[Thread 0x7ffff7fc3740 (LWP 6116) exited]

Solution

  • what should i do to prevent termination of thread??

    Handle the exception (try/catch).

    UPDATE:take care that io_service is ran from different thread NOTE:in this question Boost.Asio read_some: End of file error the answer suggests putting the read_some function in try catch block. he without explicitly saying changes read_some whick take 2nd parameter for error to the version without error. if i need error parameter to continue my procedure ,what can i do?

    You don't need the "error paramater" to continue the procedure - just handle the exception again.

    In principle there is no difference between the versions that throw and the versions that set an error_code:

    errpr_code ec;
    try {
       foo();
    } catch(boost::system::system_error& se) {
       ec = se.code();
    }
    

    Is functionally equivalent to

    errpr_code ec;
    foo(ec);
    

    Bonus

    Note also you can just write if (ec) (or even if (!ec.failed9))) instead of if (ec.value() != boost::system::errc::errc_t::success). And you should.