What changed, and why it matters
This commit updates Monero's networking code to use modern C++14 move semantics for asynchronous callbacks. The changes make callback passing more efficient and avoid unnecessary copies, but they do not appear to fix any active security vulnerability. It is primarily a code modernization and robustness improvement.
Treat as routine maintenance. Review for C++ correctness if integrating into a release branch, but no security-specific action is required.
Security signals we found
Use of perfect forwarding for callbacks reduces risk of copy-related lifetime issues
Lambda capture modernization with explicit move of callbacks into closures
No changes to parsing, authentication, encryption, or resource limits
Evidence from the diff
The patch converts callback parameters from const lvalue references (const callback_t &cb) to forwarding references (callback_t &&cb) and uses std::forward/std::move to transfer ownership into lambda captures and handler objects. This eliminates redundant copies of callable objects, particularly important for move-only functors and capturing lambdas. The changes touch levin protocol async handlers, TCP server connect_async, and P2P ping/support-flags callbacks. No bounds checks, input validation, cryptographic operations, or network protocol logic were modified.
Changed components
contrib/epee/include/net/abstract_tcp_server2.hcontrib/epee/include/net/abstract_tcp_server2.inlcontrib/epee/include/net/levin_protocol_handler_async.hcontrib/epee/include/storages/levin_abstract_invoke2.hsrc/p2p/net_node.hsrc/p2p/net_node.inlInspect captured patch +23 / −29
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index a410699..d5df90e 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -420,7 +420,7 @@ namespace net_utils
try_connect_result_t try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support);
bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
template<class t_callback>
- bool connect_async(const std::string& adr, const std::string& port, std::chrono::milliseconds conn_timeout, const t_callback &cb, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, t_connection_context&& initial = t_connection_context{});
+ bool connect_async(const std::string& adr, const std::string& port, std::chrono::milliseconds conn_timeout, t_callback &&cb, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, t_connection_context&& initial = t_connection_context{});
boost::asio::ssl::context& get_ssl_context() noexcept
{
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 4bd1f6e..695a1a2 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -1963,7 +1963,7 @@ namespace net_utils
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler> template<class t_callback>
- bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, const std::chrono::milliseconds conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support, t_connection_context&& initial)
+ bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, const std::chrono::milliseconds conn_timeout, t_callback &&cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support, t_connection_context&& initial)
{
TRY_ENTRY();
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support, std::move(initial)) );
@@ -2056,7 +2056,7 @@ namespace net_utils
}
});
//start async connect
- sock_.async_connect(remote_endpoint, [=](const boost::system::error_code& ec_)
+ sock_.async_connect(remote_endpoint, [=, cb = std::forward<t_callback>(cb)](const boost::system::error_code& ec_) mutable
{
t_connection_context conn_context = AUTO_VAL_INIT(conn_context);
boost::system::error_code ignored_ec;
diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h
index 07a14c7..8745569 100644
--- a/contrib/epee/include/net/levin_protocol_handler_async.h
+++ b/contrib/epee/include/net/levin_protocol_handler_async.h
@@ -109,7 +109,7 @@ public:
std::chrono::milliseconds m_invoke_timeout;
template<class callback_t>
- int invoke_async(int command, message_writer in_msg, boost::uuids::uuid connection_id, const callback_t &cb, std::chrono::milliseconds timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
+ int invoke_async(int command, message_writer in_msg, boost::uuids::uuid connection_id, callback_t &&cb, std::chrono::milliseconds timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
bool send(epee::byte_slice message, const boost::uuids::uuid& connection_id);
bool close(boost::uuids::uuid connection_id, const bool wait_for_shutdown);
@@ -223,12 +223,13 @@ public:
}
public:
- anvoke_handler(const callback_t& cb, const std::chrono::milliseconds timeout, std::shared_ptr<net_utils::service_endpoint<derived_handler>> con, int command)
+ template<typename F>
+ anvoke_handler(F&& cb, const std::chrono::milliseconds timeout, std::shared_ptr<net_utils::service_endpoint<derived_handler>> con, int command)
: invoke_response_handler_base(),
std::enable_shared_from_this<anvoke_handler<callback_t>>(),
m_con(con),
m_timer(con->get_io_context()),
- m_cb(std::move(cb)),
+ m_cb(std::forward<F>(cb)),
m_timeout(timeout),
m_command(command),
m_cancel_timer_called(false),
@@ -318,7 +319,7 @@ public:
}
template<class callback_t>
- bool add_invoke_response_handler(const callback_t &cb, const std::chrono::milliseconds timeout, std::shared_ptr<net_utils::service_endpoint<derived_handler>> con, int command)
+ bool add_invoke_response_handler(callback_t &&cb, const std::chrono::milliseconds timeout, std::shared_ptr<net_utils::service_endpoint<derived_handler>> con, int command)
{
CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock);
if (m_protocol_released)
@@ -326,7 +327,8 @@ public:
MERROR("Adding response handler to a released object");
return false;
}
- std::shared_ptr<invoke_response_handler_base> handler(std::make_shared<anvoke_handler<callback_t>>(cb, timeout, std::move(con), command));
+ std::shared_ptr<invoke_response_handler_base> handler =
+ std::make_shared<anvoke_handler<std::decay_t<callback_t>>>(std::forward<callback_t>(cb), timeout, std::move(con), command);
if (handler->reset_timer(true))
{
m_invoke_response_handlers.push_back(std::move(handler));
@@ -631,7 +633,7 @@ public:
}
template<class callback_t>
- bool async_invoke(std::shared_ptr<net_utils::service_endpoint<derived_handler>> self, int command, message_writer in_msg, const callback_t &cb, std::chrono::milliseconds timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
+ bool async_invoke(std::shared_ptr<net_utils::service_endpoint<derived_handler>> self, int command, message_writer in_msg, callback_t &&cb, std::chrono::milliseconds timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
{
assert(self && this == std::addressof(self->m_protocol_handler));
@@ -653,7 +655,7 @@ public:
break;
}
- if(!add_invoke_response_handler(cb, timeout, std::move(self), command))
+ if(!add_invoke_response_handler(std::forward<callback_t>(cb), timeout, std::move(self), command))
{
err_code = LEVIN_ERROR_CONNECTION_DESTROYED;
break;
@@ -774,13 +776,13 @@ std::shared_ptr<net_utils::service_endpoint<typename get_handler<t_connection_co
}
//------------------------------------------------------------------------------------------
template<class t_connection_context> template<class callback_t>
-int async_protocol_handler_config<t_connection_context>::invoke_async(int command, message_writer in_msg, boost::uuids::uuid connection_id, const callback_t &cb, const std::chrono::milliseconds timeout)
+int async_protocol_handler_config<t_connection_context>::invoke_async(int command, message_writer in_msg, boost::uuids::uuid connection_id, callback_t &&cb, const std::chrono::milliseconds timeout)
{
std::shared_ptr<levin_endpoint> con = find_and_lock_connection(connection_id);
if (!con)
return LEVIN_ERROR_CONNECTION_NOT_FOUND;
levin_endpoint& ref = *con;
- return ref.m_protocol_handler.async_invoke(std::move(con), command, std::move(in_msg), cb, timeout);
+ return ref.m_protocol_handler.async_invoke(std::move(con), command, std::move(in_msg), std::forward<callback_t>(cb), timeout);
}
//------------------------------------------------------------------------------------------
template<class t_connection_context> template<class callback_t>
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index 1a291f6..1c51549 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -56,14 +56,14 @@ namespace epee
namespace net_utils
{
template<class t_result, class t_arg, class callback_t, class t_transport>
- bool async_invoke_remote_command2(const epee::net_utils::connection_context_base &context, int command, const t_arg& out_struct, t_transport& transport, const callback_t &cb, const std::chrono::milliseconds inv_timeout = levin::LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
+ bool async_invoke_remote_command2(const epee::net_utils::connection_context_base &context, int command, const t_arg& out_struct, t_transport& transport, callback_t &&cb, const std::chrono::milliseconds inv_timeout = levin::LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
{
const boost::uuids::uuid &conn_id = context.m_connection_id;
typename serialization::portable_storage stg;
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
levin::message_writer to_send{16 * 1024};
stg.store_to_binary(to_send.buffer);
- int res = transport.invoke_async(command, std::move(to_send), conn_id, [cb, command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool
+ int res = transport.invoke_async(command, std::move(to_send), conn_id, [cb = std::forward<callback_t>(cb), command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool
{
t_result result_struct{};
if( code <=0 )
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index e80909b..b51083a 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -367,7 +367,7 @@ namespace nodetool
bool is_peer_used(const anchor_peerlist_entry& peer);
bool is_addr_connected(const epee::net_utils::network_address& peer);
template<class t_callback>
- bool try_ping(basic_node_data& node_data, p2p_connection_context& context, const t_callback &cb);
+ bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback &&cb);
bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f);
bool make_expected_connections_count(network_zone& zone, PeerType peer_type, size_t expected_connections);
void record_addr_failed(const epee::net_utils::network_address& addr);
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 3fa7093..e346345 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -2527,7 +2527,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_callback>
- bool node_server<t_payload_net_handler>::try_ping(basic_node_data& node_data, p2p_connection_context& context, const t_callback &cb)
+ bool node_server<t_payload_net_handler>::try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback &&cb)
{
if(!node_data.my_port)
return false;
@@ -2570,9 +2570,9 @@ namespace nodetool
address = epee::net_utils::network_address{epee::net_utils::ipv6_network_address(ipv6_addr, node_data.my_port)};
}
peerid_type pr = node_data.peer_id;
- bool r = zone.m_net_server.connect_async(ip, port, zone.m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this](
+ bool r = zone.m_net_server.connect_async(ip, port, zone.m_config.m_net_config.ping_connection_timeout, [cb = std::forward<t_callback>(cb), /*context,*/ address, pr, this] (
const typename net_server::t_connection_context& ping_context,
- const boost::system::error_code& ec)->bool
+ const boost::system::error_code& ec) mutable ->bool
{
if(ec)
{
@@ -2581,19 +2581,11 @@ namespace nodetool
}
COMMAND_PING::request req;
COMMAND_PING::response rsp;
- //vc2010 workaround
- /*std::string ip_ = ip;
- std::string port_=port;
- peerid_type pr_ = pr;
- auto cb_ = cb;*/
-
- // GCC 5.1.0 gives error with second use of uint64_t (peerid_type) variable.
- peerid_type pr_ = pr;
network_zone& zone = m_network_zones.at(address.get_zone());
bool inv_call_res = epee::net_utils::async_invoke_remote_command2<COMMAND_PING::response>(ping_context, COMMAND_PING::ID, req, zone.m_net_server.get_config_object(),
- [=](int code, const COMMAND_PING::response& rsp, p2p_connection_context& context)
+ [this, pr, cb = std::move(cb), ping_context = std::move(ping_context), address](int code, const COMMAND_PING::response& rsp, p2p_connection_context& context)
{
if(code <= 0)
{
@@ -2604,7 +2596,7 @@ namespace nodetool
network_zone& zone = m_network_zones.at(address.get_zone());
if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id)
{
- LOG_WARNING_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << peerid_to_string(rsp.peer_id));
+ LOG_WARNING_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr << ", rsp.peer_id=" << peerid_to_string(rsp.peer_id));
zone.m_net_server.get_config_object().close(ping_context.m_connection_id, false);
return;
}
@@ -2640,7 +2632,7 @@ namespace nodetool
COMMAND_REQUEST_SUPPORT_FLAGS::ID,
support_flags_request,
m_network_zones.at(epee::net_utils::zone::public_).m_net_server.get_config_object(),
- [=](int code, const typename COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context_)
+ [f = std::move(f)](int code, const typename COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context_)
{
if(code < 0)
{
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.