From 7799795fecb35db6ab4e548238c99d4f49f98a1d Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 12 Mar 2018 11:58:06 -0500 Subject: [PATCH 1/3] Added disable-peer-advertising and accept-incoming-connections params --- libraries/app/application.cpp | 25 ++++++++++++-- libraries/net/node.cpp | 60 ++++++++++++++++++++++++++++++++++ programs/witness_node/main.cpp | 9 ++++- 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 4a59384a71..9167795d72 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -113,6 +113,10 @@ namespace detail { bool _force_validate = false; application_options _app_options; + /////// + // @brief begin making connections to peers + // @param data_dir the directory that contains the configuration information (i.e. data_dir) + ////// void reset_p2p_node(const fc::path& data_dir) { try { _p2p_network = std::make_shared("BitShares Reference Implementation"); @@ -120,6 +124,7 @@ namespace detail { _p2p_network->load_configuration(data_dir / "p2p"); _p2p_network->set_node_delegate(this); + // The user specified specific seed node(s) that should be connected to if( _options->count("seed-node") ) { auto seeds = _options->at("seed-node").as>(); @@ -140,6 +145,7 @@ namespace detail { } } + // The user specified a collection of seed nodes if( _options->count("seed-nodes") ) { auto seeds_str = _options->at("seed-nodes").as(); @@ -161,6 +167,7 @@ namespace detail { } else { + // use the embedded list of seed nodes // https://bitsharestalk.org/index.php/topic,23715.0.html vector seeds = { "104.236.144.84:1777", // puppies (USA) @@ -204,12 +211,25 @@ namespace detail { _p2p_network->listen_to_p2p_network(); ilog("Configured p2p node to listen on ${ip}", ("ip", _p2p_network->get_actual_listening_endpoint())); + if ( _options->count("disable-peer-advertising") && _options->at("dissable_peer_advertising").as()) + _p2p_network->disable_peer_advertising(); + + if ( _options->count("accept-incoming-connections") ) + _p2p_network->accept_incoming_connections( _options->at("accept-incoming-connections").as()); + _p2p_network->connect_to_p2p_network(); + // start syncing our chain to what is available on the network _p2p_network->sync_from(net::item_id(net::core_message_type_enum::block_message_type, _chain_db->head_block_id()), std::vector()); } FC_CAPTURE_AND_RETHROW() } + ////// + // @brief for a string, parse into an fc::ip::endpoint + // NOTE: This does a resolve to convert hostnames to IP addresses + // @param endpoint_string the string in the format ip.a.d.dr:port or hostname:port + // @returns a collection of endpoints + ////// std::vector resolve_string_to_ip_endpoints(const std::string& endpoint_string) { try @@ -968,8 +988,9 @@ void application::set_program_options(boost::program_options::options_descriptio ("replay-blockchain", "Rebuild object graph by replaying all blocks") ("resync-blockchain", "Delete all blocks and re-sync with network from scratch") ("force-validate", "Force validation of all transactions") - ("genesis-timestamp", bpo::value(), - "Replace timestamp from genesis.json with current time plus this many seconds (experts only!)") + ("genesis-timestamp", bpo::value(), "Replace timestamp from genesis.json with current time plus this many seconds (experts only!)") + ("disable-peer-advertising", bpo::value()->implicit_value(false), "Disable peer advertising") + ("accept-incoming-connections", bpo::value()->implicit_value(true), "Accept incoming connections") ; command_line_options.add(_cli_options); configuration_file_options.add(_cfg_options); diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index 57125c2dc1..bbc184cd47 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -2157,6 +2157,11 @@ namespace graphene { namespace net { namespace detail { FC_THROW( "unexpected connection_rejected_message from peer" ); } + ////////////// + // @brief a remote peer asks for our list of peers + // @param originating_peer who requested + // @param address_request_message_received the message + ////////////// void node_impl::on_address_request_message(peer_connection* originating_peer, const address_request_message& address_request_message_received) { VERIFY_CORRECT_THREAD(); @@ -2186,6 +2191,11 @@ namespace graphene { namespace net { namespace detail { originating_peer->send_message(reply); } + ////////////////// + // @brief a remote peer has given us a list of addresses + // @param originating_peer where the message originated + // @param address_message_received the message + ////////////////// void node_impl::on_address_message(peer_connection* originating_peer, const address_message& address_message_received) { VERIFY_CORRECT_THREAD(); @@ -4513,6 +4523,10 @@ namespace graphene { namespace net { namespace detail { } } + /////// + // @brief listen for incoming p2p connections + // NOTE: can be disabled in configuration + /////// void node_impl::listen_to_p2p_network() { VERIFY_CORRECT_THREAD(); @@ -4608,6 +4622,9 @@ namespace graphene { namespace net { namespace detail { } } + ///////// + // @brief starts several tasks related to p2p connections and maintenance + ///////// void node_impl::connect_to_p2p_network() { VERIFY_CORRECT_THREAD(); @@ -4670,6 +4687,10 @@ namespace graphene { namespace net { namespace detail { }, "connect_to_task"); } + ///////// + // @brief attempt to connect to a specific endpoint + // @param remote_endpoint the endpoint to connect to + ///////// void node_impl::connect_to_endpoint(const fc::ip::endpoint& remote_endpoint) { VERIFY_CORRECT_THREAD(); @@ -4830,6 +4851,11 @@ namespace graphene { namespace net { namespace detail { // peer_to_disconnect->close_connection(); } + //////////// + // @brief listen on a particular endpoint + // @param ep the endpoint + // @param wait_if_not_available wait if the endpoint is busy + //////////// void node_impl::listen_on_endpoint( const fc::ip::endpoint& ep, bool wait_if_not_available ) { VERIFY_CORRECT_THREAD(); @@ -4838,6 +4864,10 @@ namespace graphene { namespace net { namespace detail { save_node_configuration(); } + /////////////// + // @brief configure the node to accept incoming connections + // @param accept true to accept, false to ignore + /////////////// void node_impl::accept_incoming_connections(bool accept) { VERIFY_CORRECT_THREAD(); @@ -4845,6 +4875,11 @@ namespace graphene { namespace net { namespace detail { save_node_configuration(); } + /////////// + // @brief listens on all interfaces + // @param port the port to listen on (0 allows system to select unused port) + // @param wait_if_not_available wait if endpoint is busy + /////////// void node_impl::listen_on_port( uint16_t port, bool wait_if_not_available ) { VERIFY_CORRECT_THREAD(); @@ -5173,11 +5208,18 @@ namespace graphene { namespace net { namespace detail { INVOKE_IN_IMPL(load_configuration, configuration_directory); } + /////// + // @brief listen for incoming p2p connections + // NOTE: can be disabled in configuration + /////// void node::listen_to_p2p_network() { INVOKE_IN_IMPL(listen_to_p2p_network); } + ///////// + // @brief starts several tasks related to p2p connections and maintenance + ///////// void node::connect_to_p2p_network() { INVOKE_IN_IMPL(connect_to_p2p_network); @@ -5188,21 +5230,39 @@ namespace graphene { namespace net { namespace detail { INVOKE_IN_IMPL(add_node, ep); } + ///////// + // @brief attempt to connect to a specific endpoint + // @param remote_endpoint the endpoint to connect to + ///////// void node::connect_to_endpoint( const fc::ip::endpoint& remote_endpoint ) { INVOKE_IN_IMPL(connect_to_endpoint, remote_endpoint); } + //////////// + // @brief listen on a particular endpoint + // @param ep the endpoint + // @param wait_if_not_available wait if the endpoint is busy + //////////// void node::listen_on_endpoint(const fc::ip::endpoint& ep , bool wait_if_not_available) { INVOKE_IN_IMPL(listen_on_endpoint, ep, wait_if_not_available); } + /////////////// + // @brief configure the node to accept incoming connections + // @param accept true to accept, false to ignore + /////////////// void node::accept_incoming_connections(bool accept) { INVOKE_IN_IMPL(accept_incoming_connections, accept); } + /////////// + // @brief listens on all interfaces + // @param port the port to listen on (0 allows system to select unused port) + // @param wait_if_not_available wait if endpoint is busy + /////////// void node::listen_on_port( uint16_t port, bool wait_if_not_available ) { INVOKE_IN_IMPL(listen_on_port, port, wait_if_not_available); diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 27097e30a3..addbe15f2b 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -91,11 +91,18 @@ class deduplicator const boost::shared_ptr (*modifier)(const boost::shared_ptr&); }; +////////////////// +// @brief load the configuration file +// @param config_ini_path the full path to the config.ini file +// @param cfg_options the known configuration options with a default value +// @param options the options passed on the command line +////////////////// static void load_config_file( const fc::path& config_ini_path, const bpo::options_description& cfg_options, bpo::variables_map& options ) { deduplicator dedup; bpo::options_description unique_options("Graphene Witness Node"); + // loop through known configuration options, making sure they are unique for( const boost::shared_ptr opt : cfg_options.options() ) { const boost::shared_ptr od = dedup.next(opt); @@ -105,7 +112,7 @@ static void load_config_file( const fc::path& config_ini_path, const bpo::option // get the basic options bpo::store(bpo::parse_config_file(config_ini_path.preferred_string().c_str(), - unique_options, true), options); + unique_options, true), options); // try to get logging options from the config file. try From 2b0b7571d778254db9f39172420af4dff1577f84 Mon Sep 17 00:00:00 2001 From: John Jones Date: Wed, 14 Mar 2018 09:42:41 -0500 Subject: [PATCH 2/3] Changes to help with testing --- libraries/net/include/graphene/net/node.hpp | 5 +- .../include/graphene/net/peer_connection.hpp | 5 +- libraries/net/node.cpp | 3 + tests/tests/p2p_node_tests.cpp | 85 +++++++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 tests/tests/p2p_node_tests.cpp diff --git a/libraries/net/include/graphene/net/node.hpp b/libraries/net/include/graphene/net/node.hpp index e17af148c2..97f3fb03df 100644 --- a/libraries/net/include/graphene/net/node.hpp +++ b/libraries/net/include/graphene/net/node.hpp @@ -29,6 +29,8 @@ #include +#include + #include namespace graphene { namespace net { @@ -292,7 +294,7 @@ namespace graphene { namespace net { void disable_peer_advertising(); fc::variant_object get_call_statistics() const; - private: + protected: std::unique_ptr my; }; @@ -312,6 +314,7 @@ namespace graphene { namespace net { void add_node_delegate(node_delegate* node_delegate_to_add); virtual uint32_t get_connection_count() const override { return 8; } + std::shared_ptr get_thread(); private: struct node_info; void message_sender(node_info* destination_node); diff --git a/libraries/net/include/graphene/net/peer_connection.hpp b/libraries/net/include/graphene/net/peer_connection.hpp index b6c24ef3de..04698cf2c2 100644 --- a/libraries/net/include/graphene/net/peer_connection.hpp +++ b/libraries/net/include/graphene/net/peer_connection.hpp @@ -271,8 +271,9 @@ namespace graphene { namespace net unsigned _send_message_queue_tasks_running; // temporary debugging #endif bool _currently_handling_message; // true while we're in the middle of handling a message from the remote system - private: + protected: peer_connection(peer_connection_delegate* delegate); + private: void destroy(); public: static peer_connection_ptr make_shared(peer_connection_delegate* delegate); // use this instead of the constructor @@ -286,7 +287,7 @@ namespace graphene { namespace net void on_connection_closed(message_oriented_connection* originating_connection) override; void send_queueable_message(std::unique_ptr&& message_to_send); - void send_message(const message& message_to_send, size_t message_send_time_field_offset = (size_t)-1); + virtual void send_message(const message& message_to_send, size_t message_send_time_field_offset = (size_t)-1); void send_item(const item_id& item_to_send); void close_connection(); void destroy_connection(); diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index bbc184cd47..7296ae9c39 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -5426,6 +5426,9 @@ namespace graphene { namespace net { namespace detail { network_nodes.push_back(new node_info(node_delegate_to_add)); } + std::shared_ptr simulated_network::get_thread() { return my->_thread; } + + namespace detail { #define ROLLING_WINDOW_SIZE 1000 diff --git a/tests/tests/p2p_node_tests.cpp b/tests/tests/p2p_node_tests.cpp new file mode 100644 index 0000000000..0605442911 --- /dev/null +++ b/tests/tests/p2p_node_tests.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include + +#include +#include + +#include + +namespace graphene +{ +namespace net +{ +namespace detail +{ +class node_impl : public graphene::net::peer_connection_delegate +{ +public: + void on_message( peer_connection* originating_peer, + const message& received_message ); + void on_connection_closed(peer_connection* originating_peer); + message get_message_for_item(const item_id& item); +}; +} +} +} + +class test_node : public graphene::net::simulated_network { +public: + test_node(const std::string& name) : simulated_network(name) {} + void on_message(graphene::net::peer_connection_ptr originating_peer, const graphene::net::message& received_message) + { + get_thread()->async([&](){ return my->on_message(originating_peer.get(), received_message); }, "thread invoke for method on_message").wait(); + } +}; + +class test_peer : public graphene::net::peer_connection +{ +public: + std::shared_ptr message_received; + void send_message(const graphene::net::message& message_to_send, size_t message_send_time_field_offset = (size_t)-1) override + { + message_received = std::shared_ptr(new graphene::net::message(message_to_send)); + } +public: + test_peer(graphene::net::peer_connection_delegate* del) : graphene::net::peer_connection(del) { + message_received = nullptr; + } + +}; + +BOOST_AUTO_TEST_CASE( p2p_disable_peer_advertising ) +{ + test_node my_node("Hello"); + graphene::net::detail::node_impl del; + std::shared_ptr my_peer(new test_peer{&del}); + graphene::net::address_request_message address_request_message_received; + my_node.on_message(my_peer, address_request_message_received); + BOOST_CHECK(my_peer->message_received != nullptr); +} From 0a93a15274b4c5b4025b3f26f4dd5302bed6f704 Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 19 Mar 2018 14:24:51 -0500 Subject: [PATCH 3/3] added tests --- tests/tests/p2p_node_tests.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/tests/p2p_node_tests.cpp b/tests/tests/p2p_node_tests.cpp index 0605442911..2a01918db6 100644 --- a/tests/tests/p2p_node_tests.cpp +++ b/tests/tests/p2p_node_tests.cpp @@ -76,10 +76,15 @@ class test_peer : public graphene::net::peer_connection BOOST_AUTO_TEST_CASE( p2p_disable_peer_advertising ) { + // first try without the disable-peer-advertising parameter test_node my_node("Hello"); graphene::net::detail::node_impl del; std::shared_ptr my_peer(new test_peer{&del}); + // add a node so it can be returned by the request + // make the request for peers graphene::net::address_request_message address_request_message_received; my_node.on_message(my_peer, address_request_message_received); BOOST_CHECK(my_peer->message_received != nullptr); + // now try with "disable_peer_advertising" set + my_node.disable_peer_advertising(); }