mirror of
https://github.com/wownero/wownero.git
synced 2026-10-17 15:41:44 +02:00
Fix two separate data races in async levin commands
This commit is contained in:
committed by
Lee *!* Clagett
parent
20d9d3cb31
commit
6f82bacbb9
@@ -26,6 +26,8 @@
|
||||
|
||||
#pragma once
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
@@ -195,7 +197,6 @@ public:
|
||||
virtual ~invoke_response_handler_base() {}
|
||||
virtual bool handle(int res, const epee::span<const uint8_t> buff, connection_context& context)=0;
|
||||
virtual void cancel()=0;
|
||||
virtual bool cancel_timer()=0;
|
||||
virtual bool reset_timer(bool first)=0;
|
||||
};
|
||||
template <class callback_t>
|
||||
@@ -206,13 +207,15 @@ public:
|
||||
callback_t m_cb;
|
||||
const std::chrono::milliseconds m_timeout;
|
||||
const int m_command;
|
||||
bool m_cancel_timer_called;
|
||||
bool m_timer_cancelled;
|
||||
boost::mutex m_sync; // for callback
|
||||
|
||||
void failure(const int rc)
|
||||
{
|
||||
std::shared_ptr<net_utils::service_endpoint<derived_handler>> con;
|
||||
boost::unique_lock<boost::mutex> lock{m_sync};
|
||||
m_con.swap(con);
|
||||
m_timer.cancel();
|
||||
lock.unlock();
|
||||
if (!con)
|
||||
return;
|
||||
|
||||
@@ -230,8 +233,7 @@ public:
|
||||
m_cb(std::move(cb)),
|
||||
m_timeout(timeout),
|
||||
m_command(command),
|
||||
m_cancel_timer_called(false),
|
||||
m_timer_cancelled(false)
|
||||
m_sync()
|
||||
{
|
||||
if (!m_con)
|
||||
throw std::logic_error{"Unexpected nullptr connection"};
|
||||
@@ -244,44 +246,42 @@ public:
|
||||
|
||||
virtual bool handle(int res, const epee::span<const uint8_t> buff, typename async_protocol_handler::connection_context& context) override final
|
||||
{
|
||||
if(!cancel_timer())
|
||||
return false;
|
||||
|
||||
std::shared_ptr<net_utils::service_endpoint<derived_handler>> con;
|
||||
boost::unique_lock<boost::mutex> lock{m_sync};
|
||||
m_con.swap(con);
|
||||
m_timer.cancel();
|
||||
lock.unlock();
|
||||
|
||||
if (con)
|
||||
m_cb(res, buff, context);
|
||||
return true;
|
||||
return bool(con);
|
||||
}
|
||||
virtual void cancel() override final
|
||||
{
|
||||
if(cancel_timer())
|
||||
failure(LEVIN_ERROR_CONNECTION_DESTROYED);
|
||||
}
|
||||
virtual bool cancel_timer() override final
|
||||
{
|
||||
if(!m_cancel_timer_called)
|
||||
{
|
||||
m_cancel_timer_called = true;
|
||||
m_timer_cancelled = 1 == m_timer.cancel();
|
||||
}
|
||||
return m_timer_cancelled;
|
||||
failure(LEVIN_ERROR_CONNECTION_DESTROYED);
|
||||
}
|
||||
|
||||
virtual bool reset_timer(bool first) override final
|
||||
{
|
||||
if (m_command == connection_context::handshake_command() && !first)
|
||||
return true;
|
||||
std::shared_ptr<anvoke_handler> self;
|
||||
if (!m_cancel_timer_called && (self = this->weak_from_this().lock()) && (first || m_timer.cancel() > 0))
|
||||
|
||||
auto self = this->weak_from_this().lock();
|
||||
if (self)
|
||||
{
|
||||
m_timer.expires_after(m_timeout);
|
||||
m_timer.async_wait([self = std::move(self)](const boost::system::error_code& ec)
|
||||
const boost::lock_guard<boost::mutex> lock{m_sync};
|
||||
if (first || self->m_timer.cancel() > 0)
|
||||
{
|
||||
if(ec != boost::asio::error::operation_aborted)
|
||||
self->failure(LEVIN_ERROR_CONNECTION_TIMEDOUT);
|
||||
});
|
||||
return true;
|
||||
m_timer.expires_after(m_timeout);
|
||||
m_timer.async_wait([self = std::move(self)] (const boost::system::error_code& ec)
|
||||
{
|
||||
if (ec != boost::asio::error::operation_aborted)
|
||||
self->failure(LEVIN_ERROR_CONNECTION_TIMEDOUT);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -493,13 +493,10 @@ public:
|
||||
if(!m_invoke_response_handlers.empty())
|
||||
{//async call scenario
|
||||
const std::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front().lock();
|
||||
bool timer_cancelled = false;
|
||||
if (response_handler)
|
||||
timer_cancelled = response_handler->cancel_timer();
|
||||
m_invoke_response_handlers.pop_front();
|
||||
invoke_response_handlers_guard.unlock();
|
||||
|
||||
if(timer_cancelled)
|
||||
if (response_handler)
|
||||
response_handler->handle(m_current_head.m_return_code, buff_to_invoke, m_connection_context);
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user