aboutsummaryrefslogtreecommitdiff
path: root/src/p2p
diff options
context:
space:
mode:
authorAntonio Juarez <antonio.maria.juarez@live.com>2014-03-03 22:07:58 +0000
committerAntonio Juarez <antonio.maria.juarez@live.com>2014-03-03 22:07:58 +0000
commit296ae46ed8f8f6e5f986f978febad302e3df231a (patch)
tree1629164454a239308f33c9e12afb22e7f3cd8eeb /src/p2p
parentchanged name (diff)
downloadmonero-296ae46ed8f8f6e5f986f978febad302e3df231a.tar.xz
moved all stuff to github
Diffstat (limited to 'src/p2p')
-rw-r--r--src/p2p/net_node.h204
-rw-r--r--src/p2p/net_node.inl1020
-rw-r--r--src/p2p/net_node_common.h62
-rw-r--r--src/p2p/net_peerlist.h375
-rw-r--r--src/p2p/net_peerlist_boost_serialization.h28
-rw-r--r--src/p2p/p2p_networks.h10
-rw-r--r--src/p2p/p2p_protocol_defs.h315
-rw-r--r--src/p2p/stdafx.h28
8 files changed, 2042 insertions, 0 deletions
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
new file mode 100644
index 000000000..32249a6d1
--- /dev/null
+++ b/src/p2p/net_node.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2012-2013 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 <boost/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/bimap.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/global_fun.hpp>
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/serialization/version.hpp>
+
+#include "warnings.h"
+#include "net/levin_server_cp2.h"
+#include "p2p_protocol_defs.h"
+#include "storages/levin_abstract_invoke2.h"
+#include "net_peerlist.h"
+#include "p2p_networks.h"
+#include "math_helper.h"
+#include "net_node_common.h"
+
+using namespace epee;
+
+PUSH_WARNINGS
+DISABLE_VS_WARNINGS(4355)
+
+namespace nodetool
+{
+ template<class base_type>
+ struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base
+ {
+ peerid_type peer_id;
+ };
+
+ template<class t_payload_net_handler>
+ class node_server: public levin::levin_commands_handler<p2p_connection_context_t<typename t_payload_net_handler::connection_context> >,
+ public i_p2p_endpoint<typename t_payload_net_handler::connection_context>
+ {
+ struct by_conn_id{};
+ struct by_peer_id{};
+ struct by_addr{};
+
+ typedef p2p_connection_context_t<typename t_payload_net_handler::connection_context> p2p_connection_context;
+
+ typedef COMMAND_HANDSHAKE_T<typename t_payload_net_handler::payload_type> COMMAND_HANDSHAKE;
+ typedef COMMAND_TIMED_SYNC_T<typename t_payload_net_handler::payload_type> COMMAND_TIMED_SYNC;
+
+ public:
+ typedef t_payload_net_handler payload_net_handler;
+ // Some code
+ node_server(t_payload_net_handler& payload_handler):m_payload_handler(payload_handler), m_allow_local_ip(false), m_hide_my_port(false)
+ {}
+
+ static void init_options(boost::program_options::options_description& desc);
+
+ bool run();
+ bool init(const boost::program_options::variables_map& vm);
+ bool deinit();
+ bool send_stop_signal();
+ uint32_t get_this_peer_port(){return m_listenning_port;}
+ t_payload_net_handler& get_payload_object();
+
+ template <class Archive, class t_version_type>
+ void serialize(Archive &a, const t_version_type ver)
+ {
+ a & m_peerlist;
+ a & m_config.m_peer_id;
+ }
+ // debug functions
+ bool log_peerlist();
+ bool log_connections();
+ virtual uint64_t get_connections_count();
+ size_t get_outgoing_connections_count();
+ peerlist_manager& get_peerlist_manager(){return m_peerlist;}
+ private:
+ typedef COMMAND_REQUEST_STAT_INFO_T<typename t_payload_net_handler::stat_info> COMMAND_REQUEST_STAT_INFO;
+
+ CHAIN_LEVIN_INVOKE_MAP2(p2p_connection_context); //move levin_commands_handler interface invoke(...) callbacks into invoke map
+ CHAIN_LEVIN_NOTIFY_MAP2(p2p_connection_context); //move levin_commands_handler interface notify(...) callbacks into nothing
+
+ BEGIN_INVOKE_MAP2(node_server)
+ HANDLE_INVOKE_T2(COMMAND_HANDSHAKE, &node_server::handle_handshake)
+ HANDLE_INVOKE_T2(COMMAND_TIMED_SYNC, &node_server::handle_timed_sync)
+ HANDLE_INVOKE_T2(COMMAND_PING, &node_server::handle_ping)
+#ifdef ALLOW_DEBUG_COMMANDS
+ HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info)
+ HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
+ HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
+#endif
+ CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
+ END_INVOKE_MAP2()
+
+ //----------------- commands handlers ----------------------------------------------
+ int handle_handshake(int command, typename COMMAND_HANDSHAKE::request& arg, typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context);
+ int handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context);
+ int handle_ping(int command, COMMAND_PING::request& arg, COMMAND_PING::response& rsp, p2p_connection_context& context);
+#ifdef ALLOW_DEBUG_COMMANDS
+ int handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context);
+ int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context);
+ int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context);
+#endif
+ bool init_config();
+ bool make_default_config();
+ bool store_config();
+ bool check_trust(const proof_of_trust& tr);
+
+
+ //----------------- levin_commands_handler -------------------------------------------------------------
+ virtual void on_connection_new(p2p_connection_context& context);
+ virtual void on_connection_close(p2p_connection_context& context);
+ virtual void callback(p2p_connection_context& context);
+ //----------------- i_p2p_endpoint -------------------------------------------------------------
+ virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
+ virtual void request_callback(const epee::net_utils::connection_context_base& context);
+ virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&)> f);
+ //-----------------------------------------------------------------------------------------------
+ bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr);
+ bool handle_command_line(const boost::program_options::variables_map& vm);
+ bool idle_worker();
+ bool handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const net_utils::connection_context_base& context);
+ bool get_local_node_data(basic_node_data& node_data);
+ //bool get_local_handshake_data(handshake_data& hshd);
+
+ bool merge_peerlist_with_local(const std::list<peerlist_entry>& bs);
+ bool fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
+
+ bool connections_maker();
+ bool peer_sync_idle_maker();
+ bool do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context, bool just_take_peerlist = false);
+ bool do_peer_timed_sync(const net_utils::connection_context_base& context, peerid_type peer_id);
+
+ bool make_new_connection_from_peerlist(bool use_white_list);
+ bool try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, bool white = true);
+ size_t get_random_index_with_fixed_probability(size_t max_index);
+ bool is_peer_used(const peerlist_entry& peer);
+ bool is_addr_connected(const net_address& peer);
+ template<class t_callback>
+ bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb);
+ bool make_expected_connections_count(bool white_list, size_t expected_connections);
+
+ //debug functions
+ std::string print_connections_container();
+
+
+ typedef net_utils::boosted_tcp_server<levin::async_protocol_handler<p2p_connection_context> > net_server;
+
+ struct config
+ {
+ network_config m_net_config;
+ uint64_t m_peer_id;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_net_config)
+ KV_SERIALIZE(m_peer_id)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ config m_config;
+ std::string m_config_folder;
+
+ bool m_have_address;
+ bool m_first_connection_maker_call;
+ uint32_t m_listenning_port;
+ uint32_t m_external_port;
+ uint32_t m_ip_address;
+ bool m_allow_local_ip;
+ bool m_hide_my_port;
+
+ //critical_section m_connections_lock;
+ //connections_indexed_container m_connections;
+
+ t_payload_net_handler& m_payload_handler;
+ peerlist_manager m_peerlist;
+
+ math_helper::once_a_time_seconds<P2P_DEFAULT_HANDSHAKE_INTERVAL> m_peer_handshake_idle_maker_interval;
+ math_helper::once_a_time_seconds<1> m_connections_maker_interval;
+ math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval;
+
+ std::string m_bind_ip;
+ std::string m_port;
+#ifdef ALLOW_DEBUG_COMMANDS
+ uint64_t m_last_stat_request_time;
+#endif
+ std::list<net_address> m_priority_peers;
+ std::vector<net_address> m_seed_nodes;
+ std::list<nodetool::peerlist_entry> m_command_line_peers;
+ uint64_t m_peer_livetime;
+ //keep connections to initiate some interactions
+ net_server m_net_server;
+ };
+}
+
+#include "net_node.inl"
+
+POP_WARNINGS
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
new file mode 100644
index 000000000..a5e534f8a
--- /dev/null
+++ b/src/p2p/net_node.inl
@@ -0,0 +1,1020 @@
+// Copyright (c) 2012-2013 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 "version.h"
+#include "string_tools.h"
+#include "common/command_line.h"
+#include "common/util.h"
+#include "net/net_helper.h"
+#include "math_helper.h"
+#include "p2p_protocol_defs.h"
+#include "net_peerlist_boost_serialization.h"
+#include "net/local_ip.h"
+#include "crypto/crypto.h"
+#include "storages/levin_abstract_invoke2.h"
+#define NET_MAKE_IP(b1,b2,b3,b4) ((LPARAM)(((DWORD)(b1)<<24)+((DWORD)(b2)<<16)+((DWORD)(b3)<<8)+((DWORD)(b4))))
+
+
+namespace nodetool
+{
+ namespace
+ {
+ const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"};
+ const command_line::arg_descriptor<std::string> arg_p2p_bind_port = {"p2p-bind-port", "Port for p2p network protocol", boost::to_string(P2P_DEFAULT_PORT)};
+ const command_line::arg_descriptor<uint32_t> arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0};
+ const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"};
+ const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"};
+ const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"};
+ const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
+ const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; }
+
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::init_options(boost::program_options::options_description& desc)
+ {
+ command_line::add_arg(desc, arg_p2p_bind_ip);
+ command_line::add_arg(desc, arg_p2p_bind_port);
+ command_line::add_arg(desc, arg_p2p_external_port);
+ command_line::add_arg(desc, arg_p2p_allow_local_ip);
+ command_line::add_arg(desc, arg_p2p_add_peer);
+ command_line::add_arg(desc, arg_p2p_add_priority_node);
+ command_line::add_arg(desc, arg_p2p_seed_node);
+ command_line::add_arg(desc, arg_p2p_hide_my_port); }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::init_config()
+ {
+ //
+ TRY_ENTRY();
+ std::string state_file_path = m_config_folder + "/" + P2P_NET_DATA_FILENAME;
+ std::ifstream p2p_data;
+ p2p_data.open( state_file_path , std::ios_base::binary | std::ios_base::in);
+ if(!p2p_data.fail())
+ {
+ boost::archive::binary_iarchive a(p2p_data);
+ a >> *this;
+ }else
+ {
+ make_default_config();
+ }
+
+ //at this moment we have hardcoded config
+ m_config.m_net_config.handshake_interval = P2P_DEFAULT_HANDSHAKE_INTERVAL;
+ m_config.m_net_config.connections_count = P2P_DEFAULT_CONNECTIONS_COUNT;
+ m_config.m_net_config.packet_max_size = P2P_DEFAULT_PACKET_MAX_SIZE; //20 MB limit
+ m_config.m_net_config.config_id = 0; // initial config
+ m_config.m_net_config.connection_timeout = P2P_DEFAULT_CONNECTION_TIMEOUT;
+ m_config.m_net_config.ping_connection_timeout = P2P_DEFAULT_PING_CONNECTION_TIMEOUT;
+ m_config.m_net_config.send_peerlist_sz = P2P_DEFAULT_PEERS_IN_HANDSHAKE;
+
+ m_first_connection_maker_call = true;
+ CATCH_ENTRY_L0("node_server::init_config", false);
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&)> f)
+ {
+ m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){
+ return f(cntx);
+ });
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::make_default_config()
+ {
+ m_config.m_peer_id = crypto::rand<uint64_t>();
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr)
+ {
+ return string_tools::parse_peer_from_string(pe.ip, pe.port, node_addr);
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::handle_command_line(const boost::program_options::variables_map& vm)
+ {
+ m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip);
+ m_port = command_line::get_arg(vm, arg_p2p_bind_port);
+ m_external_port = command_line::get_arg(vm, arg_p2p_external_port);
+ m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip);
+
+ if (command_line::has_arg(vm, arg_p2p_add_peer))
+ {
+ std::vector<std::string> perrs = command_line::get_arg(vm, arg_p2p_add_peer);
+ for(const std::string& pr_str: perrs)
+ {
+ nodetool::peerlist_entry pe = AUTO_VAL_INIT(pe);
+ pe.id = crypto::rand<uint64_t>();
+ bool r = parse_peer_from_string(pe.adr, pr_str);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str);
+ m_command_line_peers.push_back(pe);
+ }
+ }
+
+ if (command_line::has_arg(vm, arg_p2p_add_priority_node))
+ {
+ std::vector<std::string> perrs = command_line::get_arg(vm, arg_p2p_add_priority_node);
+ for(const std::string& pr_str: perrs)
+ {
+ nodetool::net_address na = AUTO_VAL_INIT(na);
+ bool r = parse_peer_from_string(na, pr_str);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str);
+ m_priority_peers.push_back(na);
+ }
+ }
+ if (command_line::has_arg(vm, arg_p2p_seed_node))
+ {
+ std::vector<std::string> seed_perrs = command_line::get_arg(vm, arg_p2p_seed_node);
+ for(const std::string& pr_str: seed_perrs)
+ {
+ nodetool::net_address na = AUTO_VAL_INIT(na);
+ bool r = parse_peer_from_string(na, pr_str);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to parse seed address from string: " << pr_str);
+ m_seed_nodes.push_back(na);
+ }
+ }
+ if(command_line::has_arg(vm, arg_p2p_hide_my_port))
+ m_hide_my_port = true; return true;
+ }
+ //-----------------------------------------------------------------------------------
+#define ADD_HARDCODED_SEED_NODE(addr_str) { nodetool::net_address na = AUTO_VAL_INIT(na);bool r = parse_peer_from_string(na, addr_str); \
+ CHECK_AND_ASSERT_MES(r, false, "Failed to parse seed address from string: " << addr_str); m_seed_nodes.push_back(na); }
+
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm)
+ {
+
+ ADD_HARDCODED_SEED_NODE("85.25.201.95:8080");
+ ADD_HARDCODED_SEED_NODE("85.25.196.145:8080");
+ ADD_HARDCODED_SEED_NODE("85.25.196.146:8080");
+ ADD_HARDCODED_SEED_NODE("85.25.196.144:8080");
+ ADD_HARDCODED_SEED_NODE("5.199.168.138:8080");
+ ADD_HARDCODED_SEED_NODE("62.75.236.152:8080");
+ ADD_HARDCODED_SEED_NODE("85.25.194.245:8080");
+ ADD_HARDCODED_SEED_NODE("95.211.224.160:8080");
+ ADD_HARDCODED_SEED_NODE("144.76.200.44:8080");
+
+ bool res = handle_command_line(vm);
+ CHECK_AND_ASSERT_MES(res, false, "Failed to handle command line");
+ m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir);
+
+ res = init_config();
+ CHECK_AND_ASSERT_MES(res, false, "Failed to init config.");
+
+ res = m_peerlist.init(m_allow_local_ip);
+ CHECK_AND_ASSERT_MES(res, false, "Failed to init peerlist.");
+
+
+ for(auto& p: m_command_line_peers)
+ m_peerlist.append_with_peer_white(p);
+
+ //only in case if we really sure that we have external visible ip
+ m_have_address = true;
+ m_ip_address = 0;
+ m_last_stat_request_time = 0;
+
+ //configure self
+ m_net_server.set_threads_prefix("P2P");
+ m_net_server.get_config_object().m_pcommands_handler = this;
+ m_net_server.get_config_object().m_invoke_timeout = P2P_DEFAULT_INVOKE_TIMEOUT;
+
+ //try to bind
+ LOG_PRINT_L0("Binding on " << m_bind_ip << ":" << m_port);
+ res = m_net_server.init_server(m_port, m_bind_ip);
+ CHECK_AND_ASSERT_MES(res, false, "Failed to bind server");
+
+ m_listenning_port = m_net_server.get_binded_port();
+ LOG_PRINT_GREEN("Net service binded on " << m_bind_ip << ":" << m_listenning_port, LOG_LEVEL_0);
+ if(m_external_port)
+ LOG_PRINT_L0("External port defined as " << m_external_port);
+ return res;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ typename node_server<t_payload_net_handler>::payload_net_handler& node_server<t_payload_net_handler>::get_payload_object()
+ {
+ return m_payload_handler;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::run()
+ {
+ //here you can set worker threads count
+ int thrds_count = 10;
+
+ m_net_server.add_idle_handler(boost::bind(&node_server<t_payload_net_handler>::idle_worker, this), 1000);
+ m_net_server.add_idle_handler(boost::bind(&t_payload_net_handler::on_idle, &m_payload_handler), 1000);
+
+ //go to loop
+ LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
+ if(!m_net_server.run_server(thrds_count))
+ {
+ LOG_ERROR("Failed to run net tcp server!");
+ }
+
+ LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
+ return true;
+ }
+
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ uint64_t node_server<t_payload_net_handler>::get_connections_count()
+ {
+ return m_net_server.get_config_object().get_connections_count();
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::deinit()
+ {
+ m_peerlist.deinit();
+ m_net_server.deinit_server();
+ return store_config();
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::store_config()
+ {
+
+ TRY_ENTRY();
+ if (!tools::create_directories_if_necessary(m_config_folder))
+ {
+ LOG_PRINT_L0("Failed to create data directory: " << m_config_folder);
+ return false;
+ }
+
+ std::string state_file_path = m_config_folder + "/" + P2P_NET_DATA_FILENAME;
+ std::ofstream p2p_data;
+ p2p_data.open( state_file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
+ if(p2p_data.fail())
+ {
+ LOG_PRINT_L0("Failed to save config to file " << state_file_path);
+ return false;
+ };
+
+ boost::archive::binary_oarchive a(p2p_data);
+ a << *this;
+ return true;
+ CATCH_ENTRY_L0("blockchain_storage::save", false);
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::send_stop_signal()
+ {
+ m_net_server.send_stop_signal();
+ LOG_PRINT_L0("[node] Stop signal sent");
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context_, bool just_take_peerlist)
+ {
+ typename COMMAND_HANDSHAKE::request arg;
+ typename COMMAND_HANDSHAKE::response rsp;
+ get_local_node_data(arg.node_data);
+ m_payload_handler.get_payload_sync_data(arg.payload_data);
+
+ simple_event ev;
+ std::atomic<bool> hsh_result(false);
+
+ bool r = net_utils::async_invoke_remote_command2<typename COMMAND_HANDSHAKE::response>(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, m_net_server.get_config_object(),
+ [this, &pi, &ev, &hsh_result, &just_take_peerlist](int code, const typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context)
+ {
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){ev.rise();});
+
+ if(code < 0)
+ {
+ LOG_PRINT_CC_RED(context, "COMMAND_HANDSHAKE invoke failed. (" << code << ", " << levin::get_err_descr(code) << ")", LOG_LEVEL_1);
+ return;
+ }
+
+ if(rsp.node_data.network_id != BYTECOIN_NETWORK)
+ {
+ LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong network! (" << string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection.");
+ return;
+ }
+
+ if(!handle_remote_peerlist(rsp.local_peerlist, rsp.node_data.local_time, context))
+ {
+ LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE: failed to handle_remote_peerlist(...), closing connection.");
+ return;
+ }
+ hsh_result = true;
+ if(!just_take_peerlist)
+ {
+ if(!m_payload_handler.process_payload_sync_data(rsp.payload_data, context, true))
+ {
+ LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE invoked, but process_payload_sync_data returned false, dropping connection.");
+ hsh_result = false;
+ return;
+ }
+
+ pi = context.peer_id = rsp.node_data.peer_id;
+ m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_ip, context.m_remote_port);
+
+ if(rsp.node_data.peer_id == m_config.m_peer_id)
+ {
+ LOG_PRINT_CCONTEXT_L2("Connection to self detected, dropping connection");
+ hsh_result = false;
+ return;
+ }
+ LOG_PRINT_CCONTEXT_L0(" COMMAND_HANDSHAKE INVOKED OK");
+ }else
+ {
+ LOG_PRINT_CCONTEXT_L0(" COMMAND_HANDSHAKE(AND CLOSE) INVOKED OK");
+ }
+ }, P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT);
+
+ if(r)
+ {
+ ev.wait();
+ }
+
+ if(!hsh_result)
+ {
+ LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed");
+ m_net_server.get_config_object().close(context_.m_connection_id);
+ }
+
+ return hsh_result;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::do_peer_timed_sync(const net_utils::connection_context_base& context_, peerid_type peer_id)
+ {
+ typename COMMAND_TIMED_SYNC::request arg = AUTO_VAL_INIT(arg);
+ m_payload_handler.get_payload_sync_data(arg.payload_data);
+
+ bool r = net_utils::async_invoke_remote_command2<typename COMMAND_TIMED_SYNC::response>(context_.m_connection_id, COMMAND_TIMED_SYNC::ID, arg, m_net_server.get_config_object(),
+ [this](int code, const typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context)
+ {
+ if(code < 0)
+ {
+ LOG_PRINT_CC_RED(context, "COMMAND_TIMED_SYNC invoke failed. (" << code << ", " << levin::get_err_descr(code) << ")", LOG_LEVEL_1);
+ return;
+ }
+
+ if(!handle_remote_peerlist(rsp.local_peerlist, rsp.local_time, context))
+ {
+ LOG_ERROR_CCONTEXT("COMMAND_TIMED_SYNC: failed to handle_remote_peerlist(...), closing connection.");
+ m_net_server.get_config_object().close(context.m_connection_id );
+ }
+ if(!context.m_is_income)
+ m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_ip, context.m_remote_port);
+ m_payload_handler.process_payload_sync_data(rsp.payload_data, context, false);
+ });
+
+ if(!r)
+ {
+ LOG_PRINT_CC_L2(context_, "COMMAND_TIMED_SYNC Failed");
+ return false;
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ size_t node_server<t_payload_net_handler>::get_random_index_with_fixed_probability(size_t max_index)
+ {
+ //divide by zero workaround
+ if(!max_index)
+ return 0;
+
+ size_t x = crypto::rand<size_t>()%(max_index+1);
+ size_t res = (x*x*x)/(max_index*max_index); //parabola \/
+ LOG_PRINT_L3("Random connection index=" << res << "(x="<< x << ", max_index=" << max_index << ")");
+ return res;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::is_peer_used(const peerlist_entry& peer)
+ {
+
+ if(m_config.m_peer_id == peer.id)
+ return true;//dont make connections to ourself
+
+ bool used = false;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr.ip == cntxt.m_remote_ip && peer.adr.port == cntxt.m_remote_port))
+ {
+ used = true;
+ return false;//stop enumerating
+ }
+ return true;
+ });
+
+ return used;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::is_addr_connected(const net_address& peer)
+ {
+ bool connected = false;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if(!cntxt.m_is_income && peer.ip == cntxt.m_remote_ip && peer.port == cntxt.m_remote_port)
+ {
+ connected = true;
+ return false;//stop enumerating
+ }
+ return true;
+ });
+
+ return connected;
+ }
+
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white)
+ {
+ LOG_PRINT_L0("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")...");
+
+ typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
+ bool res = m_net_server.connect(string_tools::get_ip_string_from_int32(na.ip),
+ string_tools::num_to_string_fast(na.port),
+ m_config.m_net_config.connection_timeout,
+ con);
+ if(!res)
+ {
+ LOG_PRINT_L0("Connect failed to "
+ << string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << string_tools::num_to_string_fast(na.port)
+ /*<< ", try " << try_count*/);
+ //m_peerlist.set_peer_unreachable(pe);
+ return false;
+ }
+ peerid_type pi = AUTO_VAL_INIT(pi);
+ res = do_handshake_with_peer(pi, con, just_take_peerlist);
+ if(!res)
+ {
+ LOG_PRINT_CC_L0(con, "Failed to HANDSHAKE with peer "
+ << string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << string_tools::num_to_string_fast(na.port)
+ /*<< ", try " << try_count*/);
+ return false;
+ }
+ if(just_take_peerlist)
+ {
+ m_net_server.get_config_object().close(con.m_connection_id);
+ LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK AND CLOSED.", LOG_LEVEL_2);
+ return true;
+ }
+
+ peerlist_entry pe_local = AUTO_VAL_INIT(pe_local);
+ pe_local.adr = na;
+ pe_local.id = pi;
+ time(&pe_local.last_seen);
+ m_peerlist.append_with_peer_white(pe_local);
+ //update last seen and push it to peerlist manager
+
+ LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK.", LOG_LEVEL_2);
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::make_new_connection_from_peerlist(bool use_white_list)
+ {
+ size_t local_peers_count = use_white_list ? m_peerlist.get_white_peers_count():m_peerlist.get_gray_peers_count();
+ if(!local_peers_count)
+ return false;//no peers
+
+ size_t max_random_index = std::min<uint64_t>(local_peers_count -1, 20);
+
+ std::set<size_t> tried_peers;
+
+ size_t try_count = 0;
+ size_t rand_count = 0;
+ while(rand_count < (max_random_index+1)*3 && try_count < 10 && !m_net_server.is_stop_signal_sent())
+ {
+ ++rand_count;
+ size_t random_index = get_random_index_with_fixed_probability(max_random_index);
+ CHECK_AND_ASSERT_MES(random_index < local_peers_count, false, "random_starter_index < peers_local.size() failed!!");
+
+ if(tried_peers.count(random_index))
+ continue;
+
+ tried_peers.insert(random_index);
+ peerlist_entry pe = AUTO_VAL_INIT(pe);
+ bool r = use_white_list ? m_peerlist.get_white_peer_by_index(pe, random_index):m_peerlist.get_gray_peer_by_index(pe, random_index);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to get random peer from peerlist(white:" << use_white_list << ")");
+
+ ++try_count;
+
+ if(is_peer_used(pe))
+ continue;
+
+ LOG_PRINT_L1("Selected peer: " << pe.id << " " << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port) << "[white=" << use_white_list << "] last_seen: " << (pe.last_seen ? misc_utils::get_time_interval_string(time(NULL) - pe.last_seen) : "never"));
+
+ if(!try_to_connect_and_handshake_with_new_peer(pe.adr, false, pe.last_seen, use_white_list))
+ continue;
+
+ return true;
+ }
+ return false;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::connections_maker()
+ {
+ if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size())
+ {
+ size_t try_count = 0;
+ size_t current_index = crypto::rand<size_t>()%m_seed_nodes.size();
+ while(true)
+ {
+ if(m_net_server.is_stop_signal_sent())
+ return false;
+
+ if(try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true))
+ break;
+ if(++try_count > m_seed_nodes.size())
+ {
+ LOG_PRINT_RED_L0("Failed to connect to any of seed peers, continuing without seeds");
+ break;
+ }
+ if(++current_index > m_seed_nodes.size())
+ current_index = 0;
+ }
+ }
+
+ for(const net_address& na: m_priority_peers)
+ {
+ if(m_net_server.is_stop_signal_sent())
+ return false;
+
+ if(is_addr_connected(na))
+ continue;
+ try_to_connect_and_handshake_with_new_peer(na);
+ }
+
+ size_t expected_white_connections = (m_config.m_net_config.connections_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
+
+ size_t conn_count = get_outgoing_connections_count();
+ if(conn_count < m_config.m_net_config.connections_count)
+ {
+ if(conn_count < expected_white_connections)
+ {
+ //start from white list
+ if(!make_expected_connections_count(true, expected_white_connections))
+ return false;
+ //and then do grey list
+ if(!make_expected_connections_count(false, m_config.m_net_config.connections_count))
+ return false;
+ }else
+ {
+ //start from grey list
+ if(!make_expected_connections_count(false, m_config.m_net_config.connections_count))
+ return false;
+ //and then do white list
+ if(!make_expected_connections_count(true, m_config.m_net_config.connections_count))
+ return false;
+ }
+ }
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::make_expected_connections_count(bool white_list, size_t expected_connections)
+ {
+ size_t conn_count = get_outgoing_connections_count();
+ //add new connections from white peers
+ while(conn_count < expected_connections)
+ {
+ if(m_net_server.is_stop_signal_sent())
+ return false;
+
+ if(!make_new_connection_from_peerlist(white_list))
+ break;
+ conn_count = get_outgoing_connections_count();
+ }
+ return true;
+ }
+
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ size_t node_server<t_payload_net_handler>::get_outgoing_connections_count()
+ {
+ size_t count = 0;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if(!cntxt.m_is_income)
+ ++count;
+ return true;
+ });
+
+ return count;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::idle_worker()
+ {
+ m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::peer_sync_idle_maker, this));
+ m_connections_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::connections_maker, this));
+ m_peerlist_store_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::store_config, this));
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::peer_sync_idle_maker()
+ {
+ LOG_PRINT_L2("STARTED PEERLIST IDLE HANDSHAKE");
+ typedef std::list<std::pair<net_utils::connection_context_base, peerid_type> > local_connects_type;
+ local_connects_type cncts;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if(cntxt.peer_id)
+ cncts.push_back(local_connects_type::value_type(cntxt, cntxt.peer_id));//do idle sync only with handshaked connections
+ return true;
+ });
+
+ std::for_each(cncts.begin(), cncts.end(), [&](const typename local_connects_type::value_type& vl){do_peer_timed_sync(vl.first, vl.second);});
+
+ LOG_PRINT_L2("FINISHED PEERLIST IDLE HANDSHAKE");
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
+ {
+ //fix time delta
+ time_t now = 0;
+ time(&now);
+ delta = now - local_time;
+
+ BOOST_FOREACH(peerlist_entry& be, local_peerlist)
+ {
+ if(be.last_seen > local_time)
+ {
+ LOG_PRINT_RED_L0("FOUND FUTURE peerlist for entry " << string_tools::get_ip_string_from_int32(be.adr.ip) << ":" << be.adr.port << " last_seen: " << be.last_seen << ", local_time(on remote node):" << local_time);
+ return false;
+ }
+ be.last_seen += delta;
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const net_utils::connection_context_base& context)
+ {
+ int64_t delta = 0;
+ std::list<peerlist_entry> peerlist_ = peerlist;
+ if(!fix_time_delta(peerlist_, local_time, delta))
+ return false;
+ LOG_PRINT_CCONTEXT_L2("REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size());
+ LOG_PRINT_CCONTEXT_L3("REMOTE PEERLIST: " << print_peerlist_to_string(peerlist_));
+ return m_peerlist.merge_peerlist(peerlist_);
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::get_local_node_data(basic_node_data& node_data)
+ {
+ time(&node_data.local_time);
+ node_data.peer_id = m_config.m_peer_id;
+ if(!m_hide_my_port)
+ node_data.my_port = m_external_port ? m_external_port : m_listenning_port;
+ else
+ node_data.my_port = 0;
+ node_data.network_id = BYTECOIN_NETWORK;
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+#ifdef ALLOW_DEBUG_COMMANDS
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::check_trust(const proof_of_trust& tr)
+ {
+ uint64_t local_time = time(NULL);
+ uint64_t time_delata = local_time > tr.time ? local_time - tr.time: tr.time - local_time;
+ if(time_delata > 24*60*60 )
+ {
+ LOG_ERROR("check_trust failed to check time conditions, local_time=" << local_time << ", proof_time=" << tr.time);
+ return false;
+ }
+ if(m_last_stat_request_time >= tr.time )
+ {
+ LOG_ERROR("check_trust failed to check time conditions, last_stat_request_time=" << m_last_stat_request_time << ", proof_time=" << tr.time);
+ return false;
+ }
+ if(m_config.m_peer_id != tr.peer_id)
+ {
+ LOG_ERROR("check_trust failed: peer_id mismatch (passed " << tr.peer_id << ", expected " << m_config.m_peer_id<< ")");
+ return false;
+ }
+ crypto::public_key pk = AUTO_VAL_INIT(pk);
+ string_tools::hex_to_pod(P2P_STAT_TRUSTED_PUB_KEY, pk);
+ crypto::hash h = tools::get_proof_of_trust_hash(tr);
+ if(!crypto::check_signature(h, pk, tr.sign))
+ {
+ LOG_ERROR("check_trust failed: sign check failed");
+ return false;
+ }
+ //update last request time
+ m_last_stat_request_time = tr.time;
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ int node_server<t_payload_net_handler>::handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context)
+ {
+ if(!check_trust(arg.tr))
+ {
+ drop_connection(context);
+ return 1;
+ }
+ rsp.connections_count = m_net_server.get_config_object().get_connections_count();
+ rsp.incoming_connections_count = rsp.connections_count - get_outgoing_connections_count();
+ rsp.version = PROJECT_VERSION_LONG;
+ rsp.os_version = tools::get_os_version_string();
+ m_payload_handler.get_stat_info(rsp.payload_info);
+ return 1;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ int node_server<t_payload_net_handler>::handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context)
+ {
+ if(!check_trust(arg.tr))
+ {
+ drop_connection(context);
+ return 1;
+ }
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ connection_entry ce;
+ ce.adr.ip = cntxt.m_remote_ip;
+ ce.adr.port = cntxt.m_remote_port;
+ ce.id = cntxt.peer_id;
+ ce.is_income = cntxt.m_is_income;
+ rsp.connections_list.push_back(ce);
+ return true;
+ });
+
+ m_peerlist.get_peerlist_full(rsp.local_peerlist_gray, rsp.local_peerlist_white);
+ rsp.my_id = m_config.m_peer_id;
+ rsp.local_time = time(NULL);
+ return 1;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ int node_server<t_payload_net_handler>::handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context)
+ {
+ rsp.my_id = m_config.m_peer_id;
+ return 1;
+ }
+#endif
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::request_callback(const epee::net_utils::connection_context_base& context)
+ {
+ m_net_server.get_config_object().request_callback(context.m_connection_id);
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
+ {
+ std::list<boost::uuids::uuid> connections;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if(cntxt.peer_id && context.m_connection_id != cntxt.m_connection_id)
+ connections.push_back(cntxt.m_connection_id);
+ return true;
+ });
+
+ BOOST_FOREACH(const auto& c_id, connections)
+ {
+ m_net_server.get_config_object().notify(command, data_buff, c_id);
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::callback(p2p_connection_context& context)
+ {
+ m_payload_handler.on_callback(context);
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)
+ {
+ int res = m_net_server.get_config_object().notify(command, req_buff, context.m_connection_id);
+ return res > 0;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
+ {
+ int res = m_net_server.get_config_object().invoke(command, req_buff, resp_buff, context.m_connection_id);
+ return res > 0;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::drop_connection(const epee::net_utils::connection_context_base& context)
+ {
+ m_net_server.get_config_object().close(context.m_connection_id);
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ 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, t_callback cb)
+ {
+ if(!node_data.my_port)
+ return false;
+
+ uint32_t actual_ip = context.m_remote_ip;
+ if(!m_peerlist.is_ip_allowed(actual_ip))
+ return false;
+ std::string ip = string_tools::get_ip_string_from_int32(actual_ip);
+ std::string port = string_tools::num_to_string_fast(node_data.my_port);
+ peerid_type pr = node_data.peer_id;
+ bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ ip, port, pr, this](
+ const typename net_server::t_connection_context& ping_context,
+ const boost::system::error_code& ec)->bool
+ {
+ if(ec)
+ {
+ LOG_PRINT_CC_L2(ping_context, "back ping connect failed to " << ip << ":" << port);
+ return false;
+ }
+ 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;*/
+ bool inv_call_res = net_utils::async_invoke_remote_command2<COMMAND_PING::response>(ping_context.m_connection_id, COMMAND_PING::ID, req, m_net_server.get_config_object(),
+ [=](int code, const COMMAND_PING::response& rsp, p2p_connection_context& context)
+ {
+ if(code <= 0)
+ {
+ LOG_PRINT_CC_L2(ping_context, "Failed to invoke COMMAND_PING to " << ip << ":" << port << "(" << code << ", " << levin::get_err_descr(code) << ")");
+ return;
+ }
+
+ if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id)
+ {
+ LOG_PRINT_CC_L2(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << ip << ":" << port << ", hsh_peer_id=" << pr << ", rsp.peer_id=" << rsp.peer_id);
+ return;
+ }
+ m_net_server.get_config_object().close(ping_context.m_connection_id);
+ cb();
+ });
+
+ if(!inv_call_res)
+ {
+ LOG_PRINT_CC_L2(ping_context, "back ping invoke failed to " << ip << ":" << port);
+ m_net_server.get_config_object().close(ping_context.m_connection_id);
+ return false;
+ }
+ return true;
+ });
+ if(!r)
+ {
+ LOG_ERROR("Failed to call connect_async, network error.");
+ }
+ return r;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ int node_server<t_payload_net_handler>::handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context)
+ {
+ if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false))
+ {
+ LOG_ERROR_CCONTEXT("Failed to process_payload_sync_data(), dropping connection");
+ drop_connection(context);
+ return 1;
+ }
+
+ //fill response
+ rsp.local_time = time(NULL);
+ m_peerlist.get_peerlist_head(rsp.local_peerlist);
+ m_payload_handler.get_payload_sync_data(rsp.payload_data);
+ LOG_PRINT_CCONTEXT_L2("COMMAND_TIMED_SYNC");
+ return 1;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ int node_server<t_payload_net_handler>::handle_handshake(int command, typename COMMAND_HANDSHAKE::request& arg, typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context)
+ {
+ if(arg.node_data.network_id != BYTECOIN_NETWORK)
+ {
+
+ LOG_PRINT_CCONTEXT_L0("WRONG NETWORK AGENT CONNECTED! id=" << string_tools::get_str_from_guid_a(arg.node_data.network_id));
+ drop_connection(context);
+ return 1;
+ }
+
+ if(!context.m_is_income)
+ {
+ LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE came not from incoming connection");
+ drop_connection(context);
+ return 1;
+ }
+
+ if(context.peer_id)
+ {
+ LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE came, but seems that connection already have associated peer_id (double COMMAND_HANDSHAKE?)");
+ drop_connection(context);
+ return 1;
+ }
+
+ if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true))
+ {
+ LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection.");
+ drop_connection(context);
+ return 1;
+ }
+ //associate peer_id with this connection
+ context.peer_id = arg.node_data.peer_id;
+
+ if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port)
+ {
+ peerid_type peer_id_l = arg.node_data.peer_id;
+ boost::uint32_t port_l = arg.node_data.my_port;
+ //try ping to be sure that we can add this peer to peer_list
+ try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]()
+ {
+ //called only(!) if success pinged, update local peerlist
+ peerlist_entry pe;
+ pe.adr.ip = context.m_remote_ip;
+ pe.adr.port = port_l;
+ time(&pe.last_seen);
+ pe.id = peer_id_l;
+ this->m_peerlist.append_with_peer_white(pe);
+ LOG_PRINT_CCONTEXT_L2("PING SUCCESS " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l);
+ });
+ }
+
+ //fill response
+ m_peerlist.get_peerlist_head(rsp.local_peerlist);
+ get_local_node_data(rsp.node_data);
+ m_payload_handler.get_payload_sync_data(rsp.payload_data);
+ LOG_PRINT_CCONTEXT_GREEN("COMMAND_HANDSHAKE", LOG_LEVEL_1);
+ return 1;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ int node_server<t_payload_net_handler>::handle_ping(int command, COMMAND_PING::request& arg, COMMAND_PING::response& rsp, p2p_connection_context& context)
+ {
+ LOG_PRINT_CCONTEXT_L2("COMMAND_PING");
+ rsp.status = PING_OK_RESPONSE_STATUS_TEXT;
+ rsp.peer_id = m_config.m_peer_id;
+ return 1;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::log_peerlist()
+ {
+ std::list<peerlist_entry> pl_wite;
+ std::list<peerlist_entry> pl_gray;
+ m_peerlist.get_peerlist_full(pl_gray, pl_wite);
+ LOG_PRINT_L0(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_wite) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) );
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::log_connections()
+ {
+ LOG_PRINT_L0("Connections: \r\n" << print_connections_container() );
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ std::string node_server<t_payload_net_handler>::print_connections_container()
+ {
+
+ std::stringstream ss;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ ss << string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) << ":" << cntxt.m_remote_port
+ << " \t\tpeer_id " << cntxt.peer_id
+ << " \t\tconn_id " << string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT")
+ << std::endl;
+ return true;
+ });
+ std::string s = ss.str();
+ return s;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::on_connection_new(p2p_connection_context& context)
+ {
+ LOG_PRINT_L2("["<< net_utils::print_connection_context(context) << "] NEW CONNECTION");
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::on_connection_close(p2p_connection_context& context)
+ {
+ LOG_PRINT_L2("["<< net_utils::print_connection_context(context) << "] CLOSE CONNECTION");
+ }
+ //-----------------------------------------------------------------------------------
+}
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
new file mode 100644
index 000000000..db8b63095
--- /dev/null
+++ b/src/p2p/net_node_common.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2012-2013 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 <boost/uuid/uuid.hpp>
+#include "net/net_utils_base.h"
+
+
+namespace nodetool
+{
+
+ typedef boost::uuids::uuid uuid;
+ typedef boost::uuids::uuid net_connection_id;
+
+ template<class t_connection_context>
+ struct i_p2p_endpoint
+ {
+ virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
+ virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
+ virtual uint64_t get_connections_count()=0;
+ virtual void for_each_connection(std::function<bool(t_connection_context&)> f)=0;
+ };
+
+ template<class t_connection_context>
+ struct p2p_endpoint_stub: public i_p2p_endpoint<t_connection_context>
+ {
+ virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
+ {
+ return false;
+ }
+ virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
+ {
+ return false;
+ }
+ virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)
+ {
+ return true;
+ }
+ virtual bool drop_connection(const epee::net_utils::connection_context_base& context)
+ {
+ return false;
+ }
+ virtual void request_callback(const epee::net_utils::connection_context_base& context)
+ {
+
+ }
+ virtual void for_each_connection(std::function<bool(t_connection_context&)> f)
+ {
+
+ }
+
+ virtual uint64_t get_connections_count()
+ {
+ return false;
+ }
+ };
+}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
new file mode 100644
index 000000000..65dfd011a
--- /dev/null
+++ b/src/p2p/net_peerlist.h
@@ -0,0 +1,375 @@
+// Copyright (c) 2012-2013 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 <list>
+#include <set>
+#include <map>
+#include <boost/foreach.hpp>
+//#include <boost/bimap.hpp>
+//#include <boost/bimap/multiset_of.hpp>
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/version.hpp>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/member.hpp>
+
+
+#include "syncobj.h"
+#include "net/local_ip.h"
+#include "p2p_protocol_defs.h"
+#include "cryptonote_config.h"
+#include "net_peerlist_boost_serialization.h"
+
+
+
+namespace nodetool
+{
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class peerlist_manager
+ {
+ public:
+ bool init(bool allow_local_ip);
+ bool deinit();
+ size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();}
+ size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();}
+ bool merge_peerlist(const std::list<peerlist_entry>& outer_bs);
+ bool get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
+ bool get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white);
+ bool get_white_peer_by_index(peerlist_entry& p, size_t i);
+ bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
+ bool append_with_peer_white(const peerlist_entry& pr);
+ bool append_with_peer_gray(const peerlist_entry& pr);
+ bool set_peer_just_seen(peerid_type peer, boost::uint32_t ip, boost::uint32_t port);
+ bool set_peer_just_seen(peerid_type peer, const net_address& addr);
+ bool set_peer_unreachable(const peerlist_entry& pr);
+ bool is_ip_allowed(uint32_t ip);
+ void trim_white_peerlist();
+ void trim_gray_peerlist();
+
+
+ private:
+ struct by_time{};
+ struct by_id{};
+ struct by_addr{};
+
+ struct modify_all_but_id
+ {
+ modify_all_but_id(const peerlist_entry& ple):m_ple(ple){}
+ void operator()(peerlist_entry& e)
+ {
+ e.id = m_ple.id;
+ }
+ private:
+ const peerlist_entry& m_ple;
+ };
+
+ struct modify_all
+ {
+ modify_all(const peerlist_entry& ple):m_ple(ple){}
+ void operator()(peerlist_entry& e)
+ {
+ e = m_ple;
+ }
+ private:
+ const peerlist_entry& m_ple;
+ };
+
+ struct modify_last_seen
+ {
+ modify_last_seen(time_t last_seen):m_last_seen(last_seen){}
+ void operator()(peerlist_entry& e)
+ {
+ e.last_seen = m_last_seen;
+ }
+ private:
+ time_t m_last_seen;
+ };
+
+
+ typedef boost::multi_index_container<
+ peerlist_entry,
+ boost::multi_index::indexed_by<
+ // access by peerlist_entry::net_adress
+ boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,net_address,&peerlist_entry::adr> >,
+ // sort by peerlist_entry::last_seen<
+ boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<peerlist_entry,time_t,&peerlist_entry::last_seen> >
+ >
+ > peers_indexed;
+
+ typedef boost::multi_index_container<
+ peerlist_entry,
+ boost::multi_index::indexed_by<
+ // access by peerlist_entry::id<
+ boost::multi_index::ordered_unique<boost::multi_index::tag<by_id>, boost::multi_index::member<peerlist_entry,uint64_t,&peerlist_entry::id> >,
+ // access by peerlist_entry::net_adress
+ boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,net_address,&peerlist_entry::adr> >,
+ // sort by peerlist_entry::last_seen<
+ boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<peerlist_entry,time_t,&peerlist_entry::last_seen> >
+ >
+ > peers_indexed_old;
+ public:
+
+ template <class Archive, class t_version_type>
+ void serialize(Archive &a, const t_version_type ver)
+ {
+ if(ver < 3)
+ return;
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ if(ver < 4)
+ {
+ //loading data from old storage
+ peers_indexed_old pio;
+ a & pio;
+ peers_indexed_from_old(pio, m_peers_white);
+ return;
+ }
+ a & m_peers_white;
+ a & m_peers_gray;
+ }
+
+ private:
+ bool peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi);
+
+ friend class boost::serialization::access;
+ epee::critical_section m_peerlist_lock;
+ std::string m_config_folder;
+ bool m_allow_local_ip;
+
+
+ peers_indexed m_peers_gray;
+ peers_indexed m_peers_white;
+ };
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::init(bool allow_local_ip)
+ {
+ m_allow_local_ip = allow_local_ip;
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::deinit()
+ {
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi)
+ {
+ for(auto x: pio)
+ {
+ auto by_addr_it = pi.get<by_addr>().find(x.adr);
+ if(by_addr_it == pi.get<by_addr>().end())
+ {
+ pi.insert(x);
+ }
+ }
+
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline void peerlist_manager::trim_white_peerlist()
+ {
+ while(m_peers_gray.size() > P2P_LOCAL_GRAY_PEERLIST_LIMIT)
+ {
+ peers_indexed::index<by_time>::type& sorted_index=m_peers_gray.get<by_time>();
+ sorted_index.erase(sorted_index.begin());
+ }
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline void peerlist_manager::trim_gray_peerlist()
+ {
+ while(m_peers_white.size() > P2P_LOCAL_WHITE_PEERLIST_LIMIT)
+ {
+ peers_indexed::index<by_time>::type& sorted_index=m_peers_white.get<by_time>();
+ sorted_index.erase(sorted_index.begin());
+ }
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::merge_peerlist(const std::list<peerlist_entry>& outer_bs)
+ {
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ BOOST_FOREACH(const peerlist_entry& be, outer_bs)
+ {
+ append_with_peer_gray(be);
+ }
+ // delete extra elements
+ trim_gray_peerlist();
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::get_white_peer_by_index(peerlist_entry& p, size_t i)
+ {
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ if(i >= m_peers_white.size())
+ return false;
+
+ peers_indexed::index<by_time>::type& by_time_index = m_peers_white.get<by_time>();
+ p = *epee::misc_utils::move_it_backward(--by_time_index.end(), i);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::get_gray_peer_by_index(peerlist_entry& p, size_t i)
+ {
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ if(i >= m_peers_gray.size())
+ return false;
+
+ peers_indexed::index<by_time>::type& by_time_index = m_peers_gray.get<by_time>();
+ p = *epee::misc_utils::move_it_backward(--by_time_index.end(), i);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::is_ip_allowed(uint32_t ip)
+ {
+ //never allow loopback ip
+ if(epee::net_utils::is_ip_loopback(ip))
+ return false;
+
+ if(!m_allow_local_ip && epee::net_utils::is_ip_local(ip))
+ return false;
+
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth)
+ {
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>();
+ uint32_t cnt = 0;
+ BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index)
+ {
+ if(!vl.last_seen)
+ continue;
+ bs_head.push_back(vl);
+ if(cnt++ > depth)
+ break;
+ }
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white)
+ {
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ peers_indexed::index<by_time>::type& by_time_index_gr=m_peers_gray.get<by_time>();
+ BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index_gr)
+ {
+ pl_gray.push_back(vl);
+ }
+
+ peers_indexed::index<by_time>::type& by_time_index_wt=m_peers_white.get<by_time>();
+ BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index_wt)
+ {
+ pl_white.push_back(vl);
+ }
+
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::set_peer_just_seen(peerid_type peer, boost::uint32_t ip, boost::uint32_t port)
+ {
+ net_address addr;
+ addr.ip = ip;
+ addr.port = port;
+ return set_peer_just_seen(peer, addr);
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::set_peer_just_seen(peerid_type peer, const net_address& addr)
+ {
+ TRY_ENTRY();
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ //find in white list
+ peerlist_entry ple;
+ ple.adr = addr;
+ ple.id = peer;
+ ple.last_seen = time(NULL);
+ return append_with_peer_white(ple);
+ CATCH_ENTRY_L0("peerlist_manager::set_peer_just_seen()", false);
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::append_with_peer_white(const peerlist_entry& ple)
+ {
+ TRY_ENTRY();
+ if(!is_ip_allowed(ple.adr.ip))
+ return true;
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ //find in white list
+ auto by_addr_it_wt = m_peers_white.get<by_addr>().find(ple.adr);
+ if(by_addr_it_wt == m_peers_white.get<by_addr>().end())
+ {
+ //put new record into white list
+ m_peers_white.insert(ple);
+ trim_white_peerlist();
+ }else
+ {
+ //update record in white list
+ m_peers_white.replace(by_addr_it_wt, ple);
+ }
+ //remove from gray list, if need
+ auto by_addr_it_gr = m_peers_gray.get<by_addr>().find(ple.adr);
+ if(by_addr_it_gr != m_peers_gray.get<by_addr>().end())
+ {
+ m_peers_gray.erase(by_addr_it_gr);
+ }
+ return true;
+ CATCH_ENTRY_L0("peerlist_manager::append_with_peer_white()", false);
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::append_with_peer_gray(const peerlist_entry& ple)
+ {
+ TRY_ENTRY();
+ if(!is_ip_allowed(ple.adr.ip))
+ return true;
+
+ if(ple.adr.port != 8080)
+ assert(false);
+
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+ //find in white list
+ auto by_addr_it_wt = m_peers_white.get<by_addr>().find(ple.adr);
+ if(by_addr_it_wt != m_peers_white.get<by_addr>().end())
+ return true;
+
+ //update gray list
+ auto by_addr_it_gr = m_peers_gray.get<by_addr>().find(ple.adr);
+ if(by_addr_it_gr == m_peers_gray.get<by_addr>().end())
+ {
+ //put new record into white list
+ m_peers_gray.insert(ple);
+ trim_gray_peerlist();
+ }else
+ {
+ //update record in white list
+ m_peers_gray.replace(by_addr_it_gr, ple);
+ }
+ return true;
+ CATCH_ENTRY_L0("peerlist_manager::append_with_peer_gray()", false);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+}
+
+BOOST_CLASS_VERSION(nodetool::peerlist_manager, 4)
diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h
new file mode 100644
index 000000000..23a253f25
--- /dev/null
+++ b/src/p2p/net_peerlist_boost_serialization.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012-2013 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
+
+namespace boost
+{
+ namespace serialization
+ {
+ //BOOST_CLASS_VERSION(odetool::net_adress, 1)
+ template <class Archive, class ver_type>
+ inline void serialize(Archive &a, nodetool::net_address& na, const ver_type ver)
+ {
+ a & na.ip;
+ a & na.port;
+ }
+
+
+ template <class Archive, class ver_type>
+ inline void serialize(Archive &a, nodetool::peerlist_entry& pl, const ver_type ver)
+ {
+ a & pl.adr;
+ a & pl.id;
+ a & pl.last_seen;
+ }
+ }
+}
diff --git a/src/p2p/p2p_networks.h b/src/p2p/p2p_networks.h
new file mode 100644
index 000000000..3fa409006
--- /dev/null
+++ b/src/p2p/p2p_networks.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2012-2013 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
+
+namespace nodetool
+{
+ const static boost::uuids::uuid BYTECOIN_NETWORK = { { 0x11 ,0x10, 0x01, 0x11 , 0x11, 0x00 , 0x01, 0x01, 0x10, 0x11, 0x00, 0x12, 0x10, 0x11, 0x01, 0x10} }; //Bender's nightmare
+}
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
new file mode 100644
index 000000000..7ae6d08f3
--- /dev/null
+++ b/src/p2p/p2p_protocol_defs.h
@@ -0,0 +1,315 @@
+// Copyright (c) 2012-2013 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 <boost/uuid/uuid.hpp>
+#include "serialization/keyvalue_serialization.h"
+#include "misc_language.h"
+#include "cryptonote_config.h"
+#include "crypto/crypto.h"
+
+namespace nodetool
+{
+ typedef boost::uuids::uuid uuid;
+ typedef uint64_t peerid_type;
+
+#pragma pack (push, 1)
+
+ struct net_address
+ {
+ boost::uint32_t ip;
+ boost::uint32_t port;
+ };
+
+ struct peerlist_entry
+ {
+ net_address adr;
+ peerid_type id;
+ time_t last_seen;
+ };
+
+ struct connection_entry
+ {
+ net_address adr;
+ peerid_type id;
+ bool is_income;
+ };
+
+#pragma pack(pop)
+
+ inline
+ bool operator < (const net_address& a, const net_address& b)
+ {
+ return epee::misc_utils::is_less_as_pod(a, b);
+ }
+
+ inline
+ bool operator == (const net_address& a, const net_address& b)
+ {
+ return memcmp(&a, &b, sizeof(a)) == 0;
+ }
+ inline
+ std::string print_peerlist_to_string(const std::list<peerlist_entry>& pl)
+ {
+ time_t now_time = 0;
+ time(&now_time);
+ std::stringstream ss;
+ ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase;
+ BOOST_FOREACH(const peerlist_entry& pe, pl)
+ {
+ ss << pe.id << "\t" << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port) << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl;
+ }
+ return ss.str();
+ }
+
+
+ struct network_config
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(connections_count)
+ KV_SERIALIZE(handshake_interval)
+ KV_SERIALIZE(packet_max_size)
+ KV_SERIALIZE(config_id)
+ END_KV_SERIALIZE_MAP()
+
+ boost::uint32_t connections_count;
+ boost::uint32_t connection_timeout;
+ boost::uint32_t ping_connection_timeout;
+ boost::uint32_t handshake_interval;
+ boost::uint32_t packet_max_size;
+ boost::uint32_t config_id;
+ boost::uint32_t send_peerlist_sz;
+ };
+
+ struct basic_node_data
+ {
+ uuid network_id;
+ time_t local_time;
+ uint32_t my_port;
+ peerid_type peer_id;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_VAL_POD_AS_BLOB(network_id)
+ KV_SERIALIZE(peer_id)
+ KV_SERIALIZE(local_time)
+ KV_SERIALIZE(my_port)
+ END_KV_SERIALIZE_MAP()
+ };
+
+
+#define P2P_COMMANDS_POOL_BASE 1000
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ template<class t_playload_type>
+ struct COMMAND_HANDSHAKE_T
+ {
+ const static int ID = P2P_COMMANDS_POOL_BASE + 1;
+
+ struct request
+ {
+ basic_node_data node_data;
+ t_playload_type payload_data;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(node_data)
+ KV_SERIALIZE(payload_data)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ basic_node_data node_data;
+ t_playload_type payload_data;
+ std::list<peerlist_entry> local_peerlist;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(node_data)
+ KV_SERIALIZE(payload_data)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ template<class t_playload_type>
+ struct COMMAND_TIMED_SYNC_T
+ {
+ const static int ID = P2P_COMMANDS_POOL_BASE + 2;
+
+ struct request
+ {
+ t_playload_type payload_data;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(payload_data)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ time_t local_time;
+ t_playload_type payload_data;
+ std::list<peerlist_entry> local_peerlist;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(local_time)
+ KV_SERIALIZE(payload_data)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+
+ struct COMMAND_PING
+ {
+ /*
+ Used to make "callback" connection, to be sure that opponent node
+ have accessible connection point. Only other nodes can add peer to peerlist,
+ and ONLY in case when peer has accepted connection and answered to ping.
+ */
+ const static int ID = P2P_COMMANDS_POOL_BASE + 3;
+
+#define PING_OK_RESPONSE_STATUS_TEXT "OK"
+
+ struct request
+ {
+ /*actually we don't need to send any real data*/
+
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+ peerid_type peer_id;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(peer_id)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+
+#ifdef ALLOW_DEBUG_COMMANDS
+ //These commands are considered as insecure, and made in debug purposes for a limited lifetime.
+ //Anyone who feel unsafe with this commands can disable the ALLOW_GET_STAT_COMMAND macro.
+
+ struct proof_of_trust
+ {
+ peerid_type peer_id;
+ uint64_t time;
+ crypto::signature sign;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(peer_id)
+ KV_SERIALIZE(time)
+ KV_SERIALIZE_VAL_POD_AS_BLOB(sign)
+ END_KV_SERIALIZE_MAP()
+ };
+
+
+ template<class payload_stat_info>
+ struct COMMAND_REQUEST_STAT_INFO_T
+ {
+ const static int ID = P2P_COMMANDS_POOL_BASE + 4;
+
+ struct request
+ {
+ proof_of_trust tr;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(tr)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string version;
+ std::string os_version;
+ uint64_t connections_count;
+ uint64_t incoming_connections_count;
+ payload_stat_info payload_info;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(version)
+ KV_SERIALIZE(os_version)
+ KV_SERIALIZE(connections_count)
+ KV_SERIALIZE(incoming_connections_count)
+ KV_SERIALIZE(payload_info)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct COMMAND_REQUEST_NETWORK_STATE
+ {
+ const static int ID = P2P_COMMANDS_POOL_BASE + 5;
+
+ struct request
+ {
+ proof_of_trust tr;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(tr)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::list<peerlist_entry> local_peerlist_white;
+ std::list<peerlist_entry> local_peerlist_gray;
+ std::list<connection_entry> connections_list;
+ peerid_type my_id;
+ uint64_t local_time;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist_white)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist_gray)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(connections_list)
+ KV_SERIALIZE(my_id)
+ KV_SERIALIZE(local_time)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct COMMAND_REQUEST_PEER_ID
+ {
+ const static int ID = P2P_COMMANDS_POOL_BASE + 6;
+
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ peerid_type my_id;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(my_id)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+#endif
+
+
+}
+
+
+
diff --git a/src/p2p/stdafx.h b/src/p2p/stdafx.h
new file mode 100644
index 000000000..1cc72f811
--- /dev/null
+++ b/src/p2p/stdafx.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012-2013 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 "targetver.h"
+
+
+#if !defined(__GNUC__)
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+
+
+
+#include <stdio.h>
+
+
+#define BOOST_FILESYSTEM_VERSION 3
+#define ENABLE_RELEASE_LOGGING
+#include "log_opt_defs.h"
+#include "misc_log_ex.h"
+
+
+