danicoin/src/P2p/NetNode.h
2016-01-18 15:33:29 +00:00

261 lines
9.3 KiB
C++

// Copyright (c) 2011-2016 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <functional>
#include <unordered_map>
#include <boost/functional/hash.hpp>
#include <System/Context.h>
#include <System/ContextGroup.h>
#include <System/Dispatcher.h>
#include <System/Event.h>
#include <System/Timer.h>
#include <System/TcpConnection.h>
#include <System/TcpListener.h>
#include "CryptoNoteCore/OnceInInterval.h"
#include "CryptoNoteProtocol/CryptoNoteProtocolHandler.h"
#include "Common/CommandLine.h"
#include "Logging/LoggerRef.h"
#include "ConnectionContext.h"
#include "LevinProtocol.h"
#include "NetNodeCommon.h"
#include "NetNodeConfig.h"
#include "P2pProtocolDefinitions.h"
#include "P2pNetworks.h"
#include "PeerListManager.h"
namespace System {
class TcpConnection;
}
namespace CryptoNote
{
class LevinProtocol;
class ISerializer;
struct P2pMessage {
enum Type {
COMMAND,
REPLY,
NOTIFY
};
P2pMessage(Type type, uint32_t command, const BinaryArray& buffer, int32_t returnCode = 0) :
type(type), command(command), buffer(buffer), returnCode(returnCode) {
}
P2pMessage(P2pMessage&& msg) :
type(msg.type), command(msg.command), buffer(std::move(msg.buffer)), returnCode(msg.returnCode) {
}
size_t size() {
return buffer.size();
}
Type type;
uint32_t command;
const BinaryArray buffer;
int32_t returnCode;
};
struct P2pConnectionContext : public CryptoNoteConnectionContext {
public:
using Clock = std::chrono::steady_clock;
using TimePoint = Clock::time_point;
System::Context<void>* context;
PeerIdType peerId;
System::TcpConnection connection;
P2pConnectionContext(System::Dispatcher& dispatcher, Logging::ILogger& log, System::TcpConnection&& conn) :
context(nullptr),
peerId(0),
connection(std::move(conn)),
logger(log, "node_server"),
queueEvent(dispatcher),
stopped(false) {
}
P2pConnectionContext(P2pConnectionContext&& ctx) :
CryptoNoteConnectionContext(std::move(ctx)),
context(ctx.context),
peerId(ctx.peerId),
connection(std::move(ctx.connection)),
logger(ctx.logger.getLogger(), "node_server"),
queueEvent(std::move(ctx.queueEvent)),
stopped(std::move(ctx.stopped)) {
}
bool pushMessage(P2pMessage&& msg);
std::vector<P2pMessage> popBuffer();
void interrupt();
uint64_t writeDuration(TimePoint now) const;
private:
Logging::LoggerRef logger;
TimePoint writeOperationStartTime;
System::Event queueEvent;
std::vector<P2pMessage> writeQueue;
size_t writeQueueSize = 0;
bool stopped;
};
class NodeServer : public IP2pEndpoint
{
public:
static void init_options(boost::program_options::options_description& desc);
NodeServer(System::Dispatcher& dispatcher, CryptoNote::CryptoNoteProtocolHandler& payload_handler, Logging::ILogger& log);
bool run();
bool init(const NetNodeConfig& config);
bool deinit();
bool sendStopSignal();
uint32_t get_this_peer_port(){return m_listeningPort;}
CryptoNote::CryptoNoteProtocolHandler& get_payload_object();
void serialize(ISerializer& s);
// debug functions
bool log_peerlist();
bool log_connections();
virtual uint64_t get_connections_count() override;
size_t get_outgoing_connections_count();
CryptoNote::PeerlistManager& getPeerlistManager() { return m_peerlist; }
private:
int handleCommand(const LevinProtocol::Command& cmd, BinaryArray& buff_out, P2pConnectionContext& context, bool& handled);
//----------------- commands handlers ----------------------------------------------
int handle_handshake(int command, COMMAND_HANDSHAKE::request& arg, COMMAND_HANDSHAKE::response& rsp, P2pConnectionContext& context);
int handle_timed_sync(int command, COMMAND_TIMED_SYNC::request& arg, COMMAND_TIMED_SYNC::response& rsp, P2pConnectionContext& context);
int handle_ping(int command, COMMAND_PING::request& arg, COMMAND_PING::response& rsp, P2pConnectionContext& context);
#ifdef ALLOW_DEBUG_COMMANDS
int handle_get_stat_info(int command, COMMAND_REQUEST_STAT_INFO::request& arg, COMMAND_REQUEST_STAT_INFO::response& rsp, P2pConnectionContext& context);
int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, P2pConnectionContext& context);
int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, P2pConnectionContext& context);
#endif
bool init_config();
bool make_default_config();
bool store_config();
bool check_trust(const proof_of_trust& tr);
void initUpnp();
bool handshake(CryptoNote::LevinProtocol& proto, P2pConnectionContext& context, bool just_take_peerlist = false);
bool timedSync();
bool handleTimedSyncResponse(const BinaryArray& in, P2pConnectionContext& context);
void forEachConnection(std::function<void(P2pConnectionContext&)> action);
void on_connection_new(P2pConnectionContext& context);
void on_connection_close(P2pConnectionContext& context);
//----------------- i_p2p_endpoint -------------------------------------------------------------
virtual void relay_notify_to_all(int command, const BinaryArray& data_buff, const net_connection_id* excludeConnection) override;
virtual bool invoke_notify_to_peer(int command, const BinaryArray& req_buff, const CryptoNoteConnectionContext& context) override;
virtual void for_each_connection(std::function<void(CryptoNote::CryptoNoteConnectionContext&, PeerIdType)> f) override;
virtual void externalRelayNotifyToAll(int command, const BinaryArray& data_buff) override;
//-----------------------------------------------------------------------------------------------
bool handle_command_line(const boost::program_options::variables_map& vm);
bool handleConfig(const NetNodeConfig& config);
bool append_net_address(std::vector<NetworkAddress>& nodes, const std::string& addr);
bool idle_worker();
bool handle_remote_peerlist(const std::list<PeerlistEntry>& peerlist, time_t local_time, const CryptoNoteConnectionContext& context);
bool get_local_node_data(basic_node_data& node_data);
bool merge_peerlist_with_local(const std::list<PeerlistEntry>& bs);
bool fix_time_delta(std::list<PeerlistEntry>& local_peerlist, time_t local_time, int64_t& delta);
bool connections_maker();
bool make_new_connection_from_peerlist(bool use_white_list);
bool try_to_connect_and_handshake_with_new_peer(const NetworkAddress& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, bool white = true);
bool is_peer_used(const PeerlistEntry& peer);
bool is_addr_connected(const NetworkAddress& peer);
bool try_ping(basic_node_data& node_data, P2pConnectionContext& context);
bool make_expected_connections_count(bool white_list, size_t expected_connections);
bool is_priority_node(const NetworkAddress& na);
bool connect_to_peerlist(const std::vector<NetworkAddress>& peers);
bool parse_peers_and_add_to_container(const boost::program_options::variables_map& vm,
const command_line::arg_descriptor<std::vector<std::string> > & arg, std::vector<NetworkAddress>& container);
//debug functions
std::string print_connections_container();
typedef std::unordered_map<boost::uuids::uuid, P2pConnectionContext, boost::hash<boost::uuids::uuid>> ConnectionContainer;
typedef ConnectionContainer::iterator ConnectionIterator;
ConnectionContainer m_connections;
void acceptLoop();
void connectionHandler(const boost::uuids::uuid& connectionId, P2pConnectionContext& connection);
void writeHandler(P2pConnectionContext& ctx);
void onIdle();
void timedSyncLoop();
void timeoutLoop();
struct config
{
network_config m_net_config;
uint64_t m_peer_id;
void serialize(ISerializer& s) {
KV_MEMBER(m_net_config)
KV_MEMBER(m_peer_id)
}
};
config m_config;
std::string m_config_folder;
bool m_have_address;
bool m_first_connection_maker_call;
uint32_t m_listeningPort;
uint32_t m_external_port;
uint32_t m_ip_address;
bool m_allow_local_ip;
bool m_hide_my_port;
std::string m_p2p_state_filename;
System::Dispatcher& m_dispatcher;
System::ContextGroup m_workingContextGroup;
System::Event m_stopEvent;
System::Timer m_idleTimer;
System::Timer m_timeoutTimer;
System::TcpListener m_listener;
Logging::LoggerRef logger;
std::atomic<bool> m_stop;
CryptoNoteProtocolHandler& m_payload_handler;
PeerlistManager m_peerlist;
// OnceInInterval m_peer_handshake_idle_maker_interval;
OnceInInterval m_connections_maker_interval;
OnceInInterval m_peerlist_store_interval;
System::Timer m_timedSyncTimer;
std::string m_bind_ip;
std::string m_port;
#ifdef ALLOW_DEBUG_COMMANDS
uint64_t m_last_stat_request_time;
#endif
std::vector<NetworkAddress> m_priority_peers;
std::vector<NetworkAddress> m_exclusive_peers;
std::vector<NetworkAddress> m_seed_nodes;
std::list<PeerlistEntry> m_command_line_peers;
uint64_t m_peer_livetime;
boost::uuids::uuid m_network_id;
};
}