mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Implemented socket message templates to support broadcast (shared_ptr) and to achieve buffer zero-copy.
156 lines
4.8 KiB
C++
156 lines
4.8 KiB
C++
#include <iostream>
|
|
#include "../sock/socket_server.hpp"
|
|
#include "../sock/socket_client.hpp"
|
|
#include "../conf.hpp"
|
|
#include "../crypto.hpp"
|
|
#include "../util.hpp"
|
|
#include "../hplog.hpp"
|
|
#include "p2p.hpp"
|
|
|
|
namespace p2p
|
|
{
|
|
/**
|
|
* Peer connections exposing to the application
|
|
*/
|
|
std::unordered_map<std::string, sock::socket_session<peer_outbound_message> *> peer_connections;
|
|
|
|
/**
|
|
* Peer session handler instance. This instance's methods will be fired for any peer socket activity.
|
|
*/
|
|
p2p::peer_session_handler global_peer_session_handler;
|
|
|
|
/**
|
|
* IO context used by the boost library in creating sockets
|
|
*/
|
|
net::io_context ioc;
|
|
|
|
/**
|
|
* The thread the peer server and client is running on. (not exposed out of this namespace)
|
|
* Peer connection watchdog runs on this thread.
|
|
*/
|
|
std::thread peer_watchdog_thread;
|
|
|
|
/**
|
|
* The thread the peer listener is running on. (not exposed out of this namespace)
|
|
*/
|
|
std::thread peer_thread;
|
|
|
|
std::map<std::string, time_t> recent_peer_msghash;
|
|
|
|
int init()
|
|
{
|
|
//Entry point for p2p which will start peer connections to other nodes
|
|
start_peer_connections();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void start_peer_connections()
|
|
{
|
|
auto address = net::ip::make_address(conf::cfg.listenip);
|
|
|
|
// Start listening to peers
|
|
std::make_shared<sock::socket_server<peer_outbound_message>>(
|
|
ioc,
|
|
tcp::endpoint{address, conf::cfg.peerport},
|
|
global_peer_session_handler)
|
|
->run();
|
|
|
|
LOG_INFO << "Started listening for incoming peer connections on " << conf::cfg.listenip << ":" << conf::cfg.peerport;
|
|
|
|
// Scan peers and trying to keep up the connections if drop. This action is run on a seperate thread.
|
|
peer_watchdog_thread = std::thread([&] { peer_connection_watchdog(); });
|
|
|
|
// Peer listener thread.
|
|
peer_thread = std::thread([&] { ioc.run(); });
|
|
}
|
|
|
|
// Scan peer connections continually and attempt to maintain the connection if they drop
|
|
void peer_connection_watchdog()
|
|
{
|
|
//todo: implement exit gracefully.
|
|
while (true)
|
|
{
|
|
for (auto &v : conf::cfg.peers)
|
|
{
|
|
if (peer_connections.find(v.first) == peer_connections.end())
|
|
{
|
|
LOG_DBG << "Trying to connect :" << v.second.first << ":" << v.second.second;
|
|
std::make_shared<sock::socket_client<peer_outbound_message>>(ioc, global_peer_session_handler)
|
|
->run(v.second.first, v.second.second);
|
|
}
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(conf::cfg.roundtime * 4));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate the incoming p2p message. Check for message version, timestamp and signature.
|
|
*
|
|
* @param message binary message content.
|
|
* @param signature binary message signature.
|
|
* @param pubkey binary public key of message originating node.
|
|
* @param timestamp message timestamp.
|
|
* @param version message timestamp.
|
|
* @return whether message is validated or not.
|
|
*/
|
|
bool validate_peer_message(std::string_view message, std::string_view signature, std::string_view pubkey, time_t timestamp, uint16_t version)
|
|
{
|
|
//Validation are prioritzed base on expensiveness of validation.
|
|
//i.e - signature validation is done at the end.
|
|
|
|
std::time_t time_now = std::time(nullptr);
|
|
|
|
//check protocol version of message whether it is greater than minimum supported protocol version.
|
|
if (version < util::MIN_PEERMSG_VERSION)
|
|
{
|
|
LOG_DBG << "Recieved message is from unsupported version";
|
|
return false;
|
|
}
|
|
|
|
// validate if the message is not from a node of current node's unl list.
|
|
if (!conf::cfg.unl.count(pubkey.data()))
|
|
{
|
|
LOG_DBG << "pubkey verification failed";
|
|
return false;
|
|
}
|
|
|
|
//check message timestamp. < timestamp now - 4* round time.
|
|
/*todo:this might change to check only current stage related. (Base on how consensus algorithm implementation take shape)
|
|
check message stage is for valid stage(node's current consensus stage - 1)
|
|
*/
|
|
if (timestamp < (time_now - conf::cfg.roundtime * 4))
|
|
{
|
|
LOG_DBG << "Recieved message from peer is old";
|
|
return false;
|
|
}
|
|
|
|
//verify message signature.
|
|
//this should be the last validation since this is bit expensive
|
|
auto signature_verified = crypto::verify(message, signature, pubkey);
|
|
|
|
if (signature_verified != 0)
|
|
{
|
|
LOG_DBG << "Signature verification failed";
|
|
return false;
|
|
}
|
|
|
|
// After signature is verified, get message hash and see wheteher
|
|
// message is already recieved -> abandon if duplicate.
|
|
auto messageHash = crypto::sha_512_hash(message, "PEERMSG", 7);
|
|
|
|
if (recent_peer_msghash.count(messageHash) == 0)
|
|
{
|
|
recent_peer_msghash.try_emplace(std::move(messageHash), timestamp);
|
|
}
|
|
else
|
|
{
|
|
LOG_DBG << "Duplicate message";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace p2p
|