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]
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);
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.