-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Timeouts in operations with sockets #417
base: master
Are you sure you want to change the base?
Changes from all commits
9a9a3c2
e5f60a7
3435248
a6ba4f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
#include <logger.hpp> | ||
|
||
#include <boost/asio.hpp> | ||
#include <boost/asio/experimental/awaitable_operators.hpp> | ||
#include <boost/beast.hpp> | ||
#include <boost/system/error_code.hpp> | ||
|
||
|
@@ -23,31 +24,122 @@ namespace http_client | |
} | ||
|
||
/// @brief Connects the socket to the given endpoints | ||
/// @param io_context The io_context associated to the socket | ||
/// @param endpoints The endpoints to connect to | ||
/// @param ec The error code, if any occurred | ||
void Connect(const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec) override | ||
/// @param timeOut The timeout for the connection | ||
void Connect(boost::asio::io_context& io_context, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec, | ||
const std::chrono::seconds timeOut = std::chrono::seconds(TIMEOUT_DEFAULT)) override | ||
{ | ||
try | ||
{ | ||
boost::asio::connect(m_socket, endpoints, ec); | ||
bool connectionSuccess = false; | ||
|
||
boost::asio::async_connect(m_socket, | ||
endpoints, | ||
[&](const boost::system::error_code& errorCode, const auto&) | ||
{ | ||
if (!errorCode) | ||
{ | ||
connectionSuccess = true; | ||
ec = errorCode; | ||
LogDebug("Connected successfully"); | ||
} | ||
}); | ||
|
||
io_context.run_for(timeOut); // Run for 2 seconds(); | ||
if (!connectionSuccess) | ||
{ | ||
ec = boost::asio::error::timed_out; | ||
LogDebug("Connection timed out"); | ||
} | ||
} | ||
catch (const std::exception& e) | ||
{ | ||
LogDebug("Exception thrown: {}", e.what()); | ||
} | ||
} | ||
|
||
/// @brief Starts a timer and updates the error code and task completion status accordingly | ||
/// @param timer The timer to start | ||
/// @param result The error code to update | ||
/// @param taskCompleted In/Out Indicates whether the socket task is completed and, if not, serves as a flag | ||
/// that indicates TimeOut | ||
|
||
boost::asio::awaitable<void> TimerTask(std::shared_ptr<boost::asio::steady_timer> timer, | ||
std::shared_ptr<boost::system::error_code> result, | ||
std::shared_ptr<bool> taskCompleted) | ||
{ | ||
try | ||
{ | ||
co_await timer->async_wait(boost::asio::use_awaitable); | ||
|
||
if (!(*taskCompleted)) | ||
{ | ||
LogDebug("Connection timed out"); | ||
*result = boost::asio::error::timed_out; | ||
*taskCompleted = true; | ||
} | ||
} | ||
catch (const boost::system::system_error& e) | ||
{ | ||
if (!(*taskCompleted) && e.code() != boost::asio::error::operation_aborted) | ||
{ | ||
*result = boost::asio::error::fault; | ||
} | ||
} | ||
} | ||
|
||
/// @brief Performs the socket connection | ||
/// @param endpoints The endpoints to connect to | ||
/// @param result The error code, if any occurred | ||
/// @param taskCompleted In/Out Indicates whether the timer task is completed and, if not, serves as a flag that | ||
/// indicates the socket is connected | ||
boost::asio::awaitable<void> SocketTask(const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
std::shared_ptr<boost::system::error_code> result, | ||
std::shared_ptr<bool> taskCompleted) | ||
{ | ||
boost::system::error_code socketErrorCode; | ||
co_await boost::asio::async_connect( | ||
m_socket, endpoints, boost::asio::redirect_error(boost::asio::use_awaitable, socketErrorCode)); | ||
if (!(*taskCompleted) && !socketErrorCode) | ||
{ | ||
LogDebug("Connected successfully"); | ||
result->clear(); | ||
*taskCompleted = true; | ||
} | ||
else | ||
{ | ||
*result = socketErrorCode; | ||
} | ||
} | ||
|
||
/// @brief Asynchronous version of Connect | ||
/// @param endpoints The endpoints to connect to | ||
/// @param ec The error code, if any occurred | ||
boost::asio::awaitable<void> AsyncConnect(const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec) override | ||
/// @param timeOut The timeout for the connection | ||
boost::asio::awaitable<void> | ||
AsyncConnect(const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec, | ||
const std::chrono::seconds timeOut = std::chrono::seconds(TIMEOUT_DEFAULT)) override | ||
{ | ||
using namespace boost::asio::experimental::awaitable_operators; | ||
|
||
auto timer = std::make_shared<boost::asio::steady_timer>(co_await boost::asio::this_coro::executor); | ||
timer->expires_after(timeOut); | ||
|
||
auto result = std::make_shared<boost::system::error_code>(); | ||
auto taskCompleted = std::make_shared<bool>(false); | ||
|
||
try | ||
{ | ||
co_await boost::asio::async_connect( | ||
m_socket, endpoints, boost::asio::redirect_error(boost::asio::use_awaitable, ec)); | ||
co_await (TimerTask(timer, result, taskCompleted) || SocketTask(endpoints, result, taskCompleted)); | ||
if (!result) | ||
{ | ||
LogDebug("Connection error: {}", result->value()); | ||
} | ||
} | ||
catch (const std::exception& e) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,24 +27,30 @@ namespace http_client | |
/// @brief Connects the socket to the given endpoints | ||
/// @param endpoints The endpoints to connect to | ||
/// @param ec The error code, if any occurred | ||
void Connect(const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec) override | ||
/// @param timeOut The timeout for the connection | ||
void Connect(boost::asio::io_context& io_context, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec, | ||
const std::chrono::seconds timeOut = std::chrono::seconds(TIMEOUT_DEFAULT)) override | ||
{ | ||
try | ||
{ | ||
boost::asio::connect(m_ssl_socket.next_layer(), endpoints.begin(), endpoints.end(), ec); | ||
if (ec) | ||
{ | ||
LogDebug("Connect failed: {}", ec.message()); | ||
return; | ||
} | ||
bool connectionSuccess = false; | ||
|
||
m_ssl_socket.handshake(boost::asio::ssl::stream_base::client, ec); | ||
if (ec) | ||
{ | ||
LogDebug("Handshake failed: {}", ec.message()); | ||
return; | ||
} | ||
// Start the asynchronous connect operation | ||
boost::asio::async_connect(m_ssl_socket.lowest_layer(), | ||
endpoints, | ||
[&](const boost::system::error_code& errorCode, const auto&) | ||
{ | ||
if (!errorCode) | ||
{ | ||
connectionSuccess = true; | ||
ec = errorCode; | ||
LogDebug("Connected successfully"); | ||
} | ||
}); | ||
|
||
io_context.run_for(timeOut); // Run for 2 seconds(); | ||
} | ||
catch (const std::exception& e) | ||
{ | ||
|
@@ -56,8 +62,11 @@ namespace http_client | |
/// @brief Asynchronous version of Connect | ||
/// @param endpoints The endpoints to connect to | ||
/// @param ec The error code, if any occurred | ||
boost::asio::awaitable<void> AsyncConnect(const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec) override | ||
/// @param timeOut The timeout for the connection | ||
boost::asio::awaitable<void> AsyncConnect( | ||
const boost::asio::ip::tcp::resolver::results_type& endpoints, | ||
boost::system::error_code& ec, | ||
[[maybe_unused]] const std::chrono::seconds timeOut = std::chrono::seconds(TIMEOUT_DEFAULT)) override | ||
{ | ||
try | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add missing parameters to function description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done