From eabb519605cab00dbaa5a1868d229f09c74570a6 Mon Sep 17 00:00:00 2001 From: rfree2monero Date: Mon, 5 Jan 2015 20:30:17 +0100 Subject: 2014 network limit 1.0a +utils +toc -doc -drmonero commands and options for network limiting works very well e.g. for 50 KiB/sec up and down ToS (QoS) flag peer number limit TODO some spikes in ingress/download TODO problems when other up and down limit added "otshell utils" - simple logging (with colors, text files channels) --- src/p2p/CMakeLists.txt | 46 +++++ src/p2p/connection_basic.cpp | 362 ++++++++++++++++++++++++++++++++++ src/p2p/connection_basic.hpp | 139 +++++++++++++ src/p2p/net_node.h | 31 ++- src/p2p/net_node.inl | 187 ++++++++++++++---- src/p2p/network_throttle-detail.cpp | 382 ++++++++++++++++++++++++++++++++++++ src/p2p/network_throttle-detail.hpp | 133 +++++++++++++ src/p2p/network_throttle.cpp | 121 ++++++++++++ src/p2p/network_throttle.hpp | 187 ++++++++++++++++++ 9 files changed, 1541 insertions(+), 47 deletions(-) create mode 100644 src/p2p/CMakeLists.txt create mode 100644 src/p2p/connection_basic.cpp create mode 100644 src/p2p/connection_basic.hpp create mode 100644 src/p2p/network_throttle-detail.cpp create mode 100644 src/p2p/network_throttle-detail.hpp create mode 100644 src/p2p/network_throttle.cpp create mode 100644 src/p2p/network_throttle.hpp (limited to 'src/p2p') diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt new file mode 100644 index 000000000..541b90fa9 --- /dev/null +++ b/src/p2p/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (c) 2014, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +cmake_minimum_required (VERSION 2.6) +project (bitmonero CXX) + +file(GLOB P2P *) +source_group(p2p FILES ${P2P}) + +#add_library(p2p ${P2P}) + +#bitmonero_private_headers(p2p ${P2P}) +bitmonero_add_library(p2p ${P2P}) +#target_link_libraries(p2p) +# LINK_PRIVATE +# ${Boost_CHRONO_LIBRARY} +# ${Boost_REGEX_LIBRARY} +# ${Boost_SYSTEM_LIBRARY} +# ${Boost_THREAD_LIBRARY} +# ${EXTRA_LIBRARIES}) +add_dependencies(p2p + version) diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp new file mode 100644 index 000000000..35b0d4c8e --- /dev/null +++ b/src/p2p/connection_basic.cpp @@ -0,0 +1,362 @@ +/// @file +/// @author rfree (current maintainer in monero.cc project) +/// @brief base for connection, contains e.g. the ratelimit hooks + +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* rfree: implementation for the non-template base, can be used by connection<> template class in abstract_tcp_server2 file */ + +#include "connection_basic.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "syncobj.h" + +#include "../../contrib/epee/include/net/net_utils_base.h" +#include "../../contrib/epee/include/misc_log_ex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "misc_language.h" +#include "pragma_comp_defs.h" +#include +#include +#include +#include +#include + +#include +#include +#include "../../contrib/epee/include/net/abstract_tcp_server2.h" + +#include "../../contrib/otshell_utils/utils.hpp" +using namespace nOT::nUtils; + +// TODO: +#include "../../src/p2p/network_throttle-detail.hpp" +#include "../../src/cryptonote_core/cryptonote_core.h" + +// ################################################################################################ +// local (TU local) headers +// ################################################################################################ + +namespace epee +{ +namespace net_utils +{ + + +/* ============================================================================ */ + +class connection_basic_pimpl { + public: + connection_basic_pimpl(const std::string &name); + + static int m_default_tos; + + network_throttle_bw m_throttle; // per-perr + critical_section m_throttle_lock; + + int m_peer_number; // e.g. for debug/stats +}; + + +} // namespace +} // namespace + +// ################################################################################################ +// The implementation part +// ################################################################################################ + +namespace epee +{ +namespace net_utils +{ + +// ================================================================================================ +// connection_basic_pimpl +// ================================================================================================ + +connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_throttle(name) { } + +// ================================================================================================ +// connection_basic +// ================================================================================================ + +// static variables: +int connection_basic_pimpl::m_default_tos; + +// methods: +connection_basic::connection_basic(boost::asio::io_service& io_service, std::atomic &ref_sock_count, std::atomic &sock_number) + : + mI( new connection_basic_pimpl("peer") ), + strand_(io_service), + socket_(io_service), + m_want_close_connection(false), + m_was_shutdown(false), + m_ref_sock_count(ref_sock_count) +{ + ++ref_sock_count; // increase the global counter + mI->m_peer_number = sock_number.fetch_add(1); // use, and increase the generated number + _note("Spawned connection p2p#"<m_peer_number<<" currently we have sockets count:" << m_ref_sock_count); + boost::filesystem::create_directories("log/dr-monero/net/"); + /*boost::asio::SettableSocketOption option;// = new boost::asio::SettableSocketOption(); + option.level(IPPROTO_IP); + option.name(IP_TOS); + option.value(&tos); + option.size = sizeof(tos); + socket_.set_option(option);*/ + // TODO socket options +} + +connection_basic::~connection_basic() { + _note("Destructing connection p2p#"<m_peer_number); +} + +void connection_basic::set_rate_up_limit(uint64_t limit) { + save_limit_to_file(limit); + { + // TODO remove __SCALING_FACTOR... + const double SCALING_FACTOR = 2.25; // to acheve the best performance + limit *= SCALING_FACTOR; + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + network_throttle_manager::get_global_throttle_out().set_target_speed(limit); + } + // connection_basic_pimpl::m_throttle_global.m_out.set_target_speed(limit); +} + +void connection_basic::set_rate_down_limit(uint64_t limit) { + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_in ); + network_throttle_manager::get_global_throttle_in().set_target_speed(limit); + } + + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_inreq ); + network_throttle_manager::get_global_throttle_inreq().set_target_speed(limit); + } + save_limit_to_file(limit); +} + +void connection_basic::set_rate_limit(uint64_t limit) { + // TODO +} +void connection_basic::set_kill_limit (uint64_t limit) { + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_in ); + network_throttle_manager::get_global_throttle_in().set_target_kill(limit); + } + + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + network_throttle_manager::get_global_throttle_out().set_target_kill(limit); + } + + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_inreq ); + network_throttle_manager::get_global_throttle_inreq().set_target_kill(limit); + } +} + +void connection_basic::save_limit_to_file(int limit) { + // saving limit to file + std::ofstream file; + file.open("log/dr-monero/limit.info"); + file << limit; +} + +void connection_basic::set_rate_autodetect(uint64_t limit) { + // TODO + LOG_PRINT_L0("inside connection_basic we set autodetect (this is additional notification).."); +} + +void connection_basic::set_tos_flag(int tos) { + connection_basic_pimpl::m_default_tos = tos; +} + +int connection_basic::get_tos_flag() { + return connection_basic_pimpl::m_default_tos; +} + +void connection_basic::sleep_before_packet(size_t packet_size, int phase, int q_len) { + double delay=0; // will be calculated + do + { // rate limiting + //XXX + /*if (::cryptonote::core::get_is_stopping()) { + _dbg1("We are stopping - so abort sleep"); + return; + }*/ + if (m_was_shutdown) { + _dbg2("m_was_shutdown - so abort sleep"); + return; + } + + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + delay = network_throttle_manager::get_global_throttle_out().get_sleep_time_after_tick( packet_size ); // decission from global + } + + + delay *= 0.50; + delay = 0; // XXX + if (delay > 0) { + //delay += rand2*0.1; + long int ms = (long int)(delay * 1000); + _info_c("net/sleep", "Sleeping in " << __FUNCTION__ << " for " << ms << " ms before packet_size="< 0); + +// XXX LATER XXX + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + network_throttle_manager::get_global_throttle_out().handle_trafic_tcp( packet_size ); // increase counter - global + //epee::critical_region_t guard(m_throttle_global_lock); // *** critical *** + //m_throttle_global.m_out.handle_trafic_tcp( packet_size ); // increase counter - global + } + +} +void connection_basic::set_start_time() { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + m_start_time = network_throttle_manager::get_global_throttle_out().get_time_seconds(); +} + +void connection_basic::do_send_handler_start(const void* ptr , size_t cb ) { + _fact_c("net/out/size", "*** do_sen() called for packet="< max sending time + //if (sending_time > 0.1) network_throttle_manager::get_global_throttle_out().set_overheat(sending_time); // TODO + +} + +void connection_basic::do_send_handler_write_from_queue( const boost::system::error_code& e, size_t cb, int q_len ) { + sleep_before_packet(cb,2,q_len); + _info_c("net/out/size", "handler_write (after write, from queue="<m_throttle_global_lock)> guard(mI->m_throttle_global_lock); // *** critical *** + // mI->m_throttle_global.m_in.handle_trafic_tcp( packet_size ); // increase counter - global + } +} + +void connection_basic::logger_handle_net_peer(size_t size, bool io) { // network data written + // TODO OPTIMIZE! do NOT reopen idiotically :) + std::ostringstream oss; + std::string filename; + if (io) { // write + double time = network_throttle_manager::get_global_throttle_in().get_time_seconds() ; + oss << "log/dr-monero/net/in-peer-" << (mI->m_peer_number) << ".dat" << std::ends; + filename = oss.str(); + network_throttle_manager::get_global_throttle_out().logger_handle_net(filename,time,size); + } + else { // read + double time = network_throttle_manager::get_global_throttle_out().get_time_seconds() ; + oss << "log/dr-monero/net/out-peer-" << (mI->m_peer_number) << ".dat" << std::ends; + filename = oss.str(); + network_throttle_manager::get_global_throttle_in().logger_handle_net(filename,time,size); + } +} + +void connection_basic::logger_handle_net_read(size_t size) { // network data read + std::string filename = "log/dr-monero/net/in-all.data"; + + double time = network_throttle_manager::get_global_throttle_in().get_time_seconds() ; + network_throttle_manager::get_global_throttle_in().logger_handle_net(filename, time, size); + logger_handle_net_peer(size,0); +} + +void connection_basic::logger_handle_net_write(size_t size) { + std::string filename = "log/dr-monero/net/out-all.data"; + double time = network_throttle_manager::get_global_throttle_out().get_time_seconds() ; + network_throttle_manager::get_global_throttle_out().logger_handle_net(filename, time, size); + logger_handle_net_peer(size,1); + +} + +double connection_basic::get_sleep_time(size_t cb) { + auto t = network_throttle_manager::get_global_throttle_out().get_sleep_time(cb); + return t; +} + + +} // namespace +} // namespace + diff --git a/src/p2p/connection_basic.hpp b/src/p2p/connection_basic.hpp new file mode 100644 index 000000000..1b5a2c8ad --- /dev/null +++ b/src/p2p/connection_basic.hpp @@ -0,0 +1,139 @@ +/// @file +/// @author rfree (current maintainer in monero.cc project) +/// @brief base for connection, contains e.g. the ratelimit hooks + +// ! This file might contain variable names same as in template class connection<> +// ! from files contrib/epee/include/net/abstract_tcp_server2.* +// ! I am not a lawyer; afaik APIs, var names etc are not copyrightable ;) +// ! (how ever if in some wonderful juristdictions that is not the case, then why not make another sub-class withat that members and licence it as epee part) +// ! Working on above premise, IF this is valid in your juristdictions, then consider this code as released as: + +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +/* rfree: place for hanlers for the non-template base, can be used by connection<> template class in abstract_tcp_server2 file */ + +#ifndef INCLUDED_p2p_connection_basic_hpp +#define INCLUDED_p2p_connection_basic_hpp + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../../contrib/epee/include/net/net_utils_base.h" +#include "../../contrib/epee/include/syncobj.h" + +namespace epee +{ +namespace net_utils +{ + + /************************************************************************/ + /* */ + /************************************************************************/ + /// Represents a single connection from a client. + +class connection_basic_pimpl; // PIMPL for this class + +class connection_basic { // not-templated base class for rapid developmet of some code parts + public: + std::unique_ptr< connection_basic_pimpl > mI; // my Implementation + + // moved here from orginal connecton<> - common member variables that do not depend on template in connection<> + volatile uint32_t m_want_close_connection; + std::atomic m_was_shutdown; + critical_section m_send_que_lock; + std::list m_send_que; + volatile bool m_is_multithreaded; + double m_start_time; + /// Strand to ensure the connection's handlers are not called concurrently. + boost::asio::io_service::strand strand_; + /// Socket for the connection. + boost::asio::ip::tcp::socket socket_; + + std::atomic &m_ref_sock_count; // reference to external counter of existing sockets that we will ++/-- + public: + // first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator + connection_basic(boost::asio::io_service& io_service, std::atomic &ref_sock_count, std::atomic &sock_number); + + virtual ~connection_basic(); + + // various handlers to be called from connection class: + void do_send_handler_start(const void * ptr , size_t cb); + void do_send_handler_delayed(const void * ptr , size_t cb); + void do_send_handler_write(const void * ptr , size_t cb); + void do_send_handler_stop(const void * ptr , size_t cb); + void do_send_handler_after_write( const boost::system::error_code& e, size_t cb ); // from handle_write + void do_send_handler_write_from_queue(const boost::system::error_code& e, size_t cb , int q_len); // from handle_write, sending next part + void do_read_handler_start(const boost::system::error_code& e, std::size_t bytes_transferred); // from read, after read completion + + void logger_handle_net_write(size_t size); // network data written + void logger_handle_net_read(size_t size); // network data read + void logger_handle_net_peer(size_t size, bool io); + + void set_start_time(); + + // config for rate limit + + static void set_rate_up_limit(uint64_t limit); + static void set_rate_down_limit(uint64_t limit); + static void set_rate_limit(uint64_t limit); + static void set_rate_autodetect(uint64_t limit); + static void set_kill_limit (uint64_t limit); + + // config misc + static void set_tos_flag(int tos); // ToS / QoS flag + static int get_tos_flag(); + + // handlers and sleep + void sleep_before_packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?) + static void save_limit_to_file(int limit); ///< for dr-monero + static double get_sleep_time(size_t cb); +}; + +} // nameserver +} // nameserver + +#endif + + diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 97fcd56c8..48737193e 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -80,14 +80,12 @@ namespace nodetool public: typedef t_payload_net_handler payload_net_handler; - node_server( - t_payload_net_handler& payload_handler - , boost::uuids::uuid network_id - ) - : m_payload_handler(payload_handler) - , m_allow_local_ip(false) - , m_hide_my_port(false) - , m_network_id(std::move(network_id)) + node_server(t_payload_net_handler& payload_handler, boost::uuids::uuid network_id) + :m_payload_handler(payload_handler), + m_allow_local_ip(false), + m_no_igd(false), + m_hide_my_port(false), + m_network_id(std::move(network_id)) {} static void init_options(boost::program_options::options_description& desc); @@ -111,6 +109,7 @@ namespace nodetool virtual uint64_t get_connections_count(); size_t get_outgoing_connections_count(); peerlist_manager& get_peerlist_manager(){return m_peerlist;} + void delete_connections(size_t count); private: const std::vector m_seed_nodes_list = { "seeds.moneroseeds.se" @@ -118,6 +117,9 @@ namespace nodetool , "seeds.moneroseeds.ch" , "seeds.moneroseeds.li" }; + + bool islimitup=false; + bool islimitdown=false; typedef COMMAND_REQUEST_STAT_INFO_T COMMAND_REQUEST_STAT_INFO; @@ -197,6 +199,13 @@ namespace nodetool template bool parse_peers_and_add_to_container(const boost::program_options::variables_map& vm, const command_line::arg_descriptor > & arg, Container& container); + bool set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max); + bool set_tos_flag(const boost::program_options::variables_map& vm, int limit); + + bool set_rate_up_limit(const boost::program_options::variables_map& vm, int64_t limit); + bool set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit); + bool set_rate_limit(const boost::program_options::variables_map& vm, uint64_t limit); + //debug functions std::string print_connections_container(); @@ -214,7 +223,10 @@ namespace nodetool END_KV_SERIALIZE_MAP() }; - config m_config; + public: + config m_config; // TODO was private, add getters? + + private: std::string m_config_folder; bool m_have_address; @@ -224,6 +236,7 @@ namespace nodetool uint32_t m_ip_address; bool m_allow_local_ip; bool m_hide_my_port; + bool m_no_igd; //critical_section m_connections_lock; //connections_indexed_container m_connections; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ee4a10789..ce70e241a 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -84,6 +84,14 @@ namespace nodetool " If this option is given the options add-priority-node and seed-node are ignored"}; const command_line::arg_descriptor > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; + + const command_line::arg_descriptor arg_no_igd = {"no-igd", "Disable UPnP port mapping"}; + const command_line::arg_descriptor arg_out_peers = {"out-peers", "set max limit of out peers", -1}; + const command_line::arg_descriptor arg_tos_flag = {"tos-flag", "set TOS flag", -1}; + + const command_line::arg_descriptor arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", -1}; + const command_line::arg_descriptor arg_limit_rate_down = {"limit-rate-down", "set limit-rate-down [kB/s]", -1}; + const command_line::arg_descriptor arg_limit_rate = {"limit-rate", "set limit-rate [kB/s]", 128}; } //----------------------------------------------------------------------------------- @@ -99,7 +107,13 @@ namespace nodetool command_line::add_arg(desc, arg_p2p_add_priority_node); command_line::add_arg(desc, arg_p2p_add_exclusive_node); command_line::add_arg(desc, arg_p2p_seed_node); - command_line::add_arg(desc, arg_p2p_hide_my_port); } + command_line::add_arg(desc, arg_p2p_hide_my_port); + command_line::add_arg(desc, arg_no_igd); + command_line::add_arg(desc, arg_out_peers); + command_line::add_arg(desc, arg_tos_flag); + command_line::add_arg(desc, arg_limit_rate_up); + command_line::add_arg(desc, arg_limit_rate_down); + command_line::add_arg(desc, arg_limit_rate); } //----------------------------------------------------------------------------------- template bool node_server::init_config() @@ -120,7 +134,6 @@ namespace nodetool //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; @@ -165,6 +178,7 @@ namespace nodetool m_port = command_line::get_arg(vm, p2p_bind_arg); 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); + m_no_igd = command_line::get_arg(vm, arg_no_igd); if (command_line::has_arg(vm, arg_p2p_add_peer)) { @@ -184,11 +198,13 @@ namespace nodetool if (!parse_peers_and_add_to_container(vm, arg_p2p_add_exclusive_node, m_exclusive_peers)) return false; } + if (command_line::has_arg(vm, arg_p2p_add_priority_node)) { if (!parse_peers_and_add_to_container(vm, arg_p2p_add_priority_node, m_priority_peers)) return false; } + if (command_line::has_arg(vm, arg_p2p_seed_node)) { if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes)) @@ -197,6 +213,21 @@ namespace nodetool if(command_line::has_arg(vm, arg_p2p_hide_my_port)) m_hide_my_port = true; + + if ( !set_max_out_peers(vm, command_line::get_arg(vm, arg_out_peers) ) ) + return false; + + if ( !set_tos_flag(vm, command_line::get_arg(vm, arg_tos_flag) ) ) + return false; + + if ( !set_rate_up_limit(vm, command_line::get_arg(vm, arg_limit_rate_up) ) ) + return false; + + if ( !set_rate_down_limit(vm, command_line::get_arg(vm, arg_limit_rate_down) ) ) + return false; + + if ( !set_rate_limit(vm, command_line::get_arg(vm, arg_limit_rate) ) ) + return false; return true; } @@ -375,42 +406,43 @@ namespace nodetool LOG_PRINT_L0("External port defined as " << m_external_port); // Add UPnP port mapping - LOG_PRINT_L0("Attempting to add IGD port mapping."); - int result; - UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result); - UPNPUrls urls; - IGDdatas igdData; - char lanAddress[64]; - result = UPNP_GetValidIGD(deviceList, &urls, &igdData, lanAddress, sizeof lanAddress); - freeUPNPDevlist(deviceList); - if (result != 0) { - if (result == 1) { - std::ostringstream portString; - portString << m_listenning_port; - - // Delete the port mapping before we create it, just in case we have dangling port mapping from the daemon not being shut down correctly - UPNP_DeletePortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), "TCP", 0); - - int portMappingResult; - portMappingResult = UPNP_AddPortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), portString.str().c_str(), lanAddress, CRYPTONOTE_NAME, "TCP", 0, "0"); - if (portMappingResult != 0) { - LOG_ERROR("UPNP_AddPortMapping failed, error: " << strupnperror(portMappingResult)); - } else { - LOG_PRINT_GREEN("Added IGD port mapping.", LOG_LEVEL_0); - } - } else if (result == 2) { - LOG_PRINT_L0("IGD was found but reported as not connected."); - } else if (result == 3) { - LOG_PRINT_L0("UPnP device was found but not recoginzed as IGD."); - } else { - LOG_ERROR("UPNP_GetValidIGD returned an unknown result code."); - } - - FreeUPNPUrls(&urls); - } else { - LOG_PRINT_L0("No IGD was found."); - } - + if(m_no_igd == false) { + LOG_PRINT_L0("Attempting to add IGD port mapping."); + int result; + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result); + UPNPUrls urls; + IGDdatas igdData; + char lanAddress[64]; + result = UPNP_GetValidIGD(deviceList, &urls, &igdData, lanAddress, sizeof lanAddress); + freeUPNPDevlist(deviceList); + if (result != 0) { + if (result == 1) { + std::ostringstream portString; + portString << m_listenning_port; + + // Delete the port mapping before we create it, just in case we have dangling port mapping from the daemon not being shut down correctly + UPNP_DeletePortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), "TCP", 0); + + int portMappingResult; + portMappingResult = UPNP_AddPortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), portString.str().c_str(), lanAddress, CRYPTONOTE_NAME, "TCP", 0, "0"); + if (portMappingResult != 0) { + LOG_ERROR("UPNP_AddPortMapping failed, error: " << strupnperror(portMappingResult)); + } else { + LOG_PRINT_GREEN("Added IGD port mapping.", LOG_LEVEL_0); + } + } else if (result == 2) { + LOG_PRINT_L0("IGD was found but reported as not connected."); + } else if (result == 3) { + LOG_PRINT_L0("UPnP device was found but not recoginzed as IGD."); + } else { + LOG_ERROR("UPNP_GetValidIGD returned an unknown result code."); + } + + FreeUPNPUrls(&urls); + } else { + LOG_PRINT_L0("No IGD was found."); + } + } return res; } //----------------------------------------------------------------------------------- @@ -1300,4 +1332,83 @@ namespace nodetool return true; } + + template + bool node_server::set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max) + { + if(max == -1) { + m_config.m_net_config.connections_count = P2P_DEFAULT_CONNECTIONS_COUNT; + return true; + } + + m_config.m_net_config.connections_count = max; + LOG_PRINT_RED_L0("connections_count: " << m_config.m_net_config.connections_count); + return true; + } + + template + void node_server::delete_connections(size_t count) + { + m_net_server.get_config_object().del_connections(count); + } + + template + bool node_server::set_tos_flag(const boost::program_options::variables_map& vm, int flag) + { + if(flag==-1){ + return true; + } + epee::net_utils::connection >::set_tos_flag(flag); + _dbg1("Set ToS flag " << flag); + return true; + } + + template + bool node_server::set_rate_up_limit(const boost::program_options::variables_map& vm, int64_t limit) + { + this->islimitup=true; + + if (limit==-1) { + limit=128; + this->islimitup=false; + } + + limit *= 1024; + epee::net_utils::connection >::set_rate_up_limit( limit ); + LOG_PRINT_L0("Set limit-up to " << limit/1024 << " kB/s"); + return true; + } + + template + bool node_server::set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit) + { + this->islimitdown=true; + if(limit==-1) { + limit=128; + this->islimitdown=false; + } + limit *= 1024; + epee::net_utils::connection >::set_rate_down_limit( limit ); + LOG_PRINT_L0("Set limit-down to " << limit/1024 << " kB/s"); + return true; + } + + template + bool node_server::set_rate_limit(const boost::program_options::variables_map& vm, uint64_t limit) + { + limit *= 1024; + if(this->islimitdown==false && this->islimitup==false) { + epee::net_utils::connection >::set_rate_up_limit( limit ); + epee::net_utils::connection >::set_rate_down_limit( limit ); + LOG_PRINT_L0("Set limit to " << limit/1024 << " kB/s"); + } + else if(this->islimitdown==false && this->islimitup==true ) { + epee::net_utils::connection >::set_rate_down_limit( limit ); + } + else if(this->islimitdown==true && this->islimitup==false ) { + epee::net_utils::connection >::set_rate_up_limit( limit ); + } + + return true; + } } diff --git a/src/p2p/network_throttle-detail.cpp b/src/p2p/network_throttle-detail.cpp new file mode 100644 index 000000000..6ea3076a9 --- /dev/null +++ b/src/p2p/network_throttle-detail.cpp @@ -0,0 +1,382 @@ +/// @file +/// @author rfree (current maintainer in monero.cc project) +/// @brief implementaion for throttling of connection (count and rate-limit speed etc) + +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* rfree: implementation for throttle details */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "syncobj.h" + +#include "../../contrib/epee/include/net/net_utils_base.h" +#include "../../contrib/epee/include/misc_log_ex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "misc_language.h" +#include "pragma_comp_defs.h" +#include +#include +#include + + + +#include +#include +#include "../../contrib/epee/include/net/abstract_tcp_server2.h" + +// TODO: +#include "../../src/p2p/network_throttle-detail.hpp" + +#include "../../contrib/otshell_utils/utils.hpp" +using namespace nOT::nUtils; + +// ################################################################################################ +// ################################################################################################ +// the "header part". Not separeted out for .hpp because point of this modification is +// to rebuild just 1 translation unit while working on this code. +// (But maybe common parts will be separated out later though - if needed) +// ################################################################################################ +// ################################################################################################ + +using namespace nOT::nUtils; + +namespace epee +{ +namespace net_utils +{ + + +/* ============================================================================ */ + +class connection_basic_pimpl { + public: + connection_basic_pimpl(const std::string &name); + + static int m_default_tos; + + network_throttle_bw m_throttle; // per-perr + critical_section m_throttle_lock; + + void _packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?) could be used for different kinds of sleep e.g. direct/queue write +}; + + +} // namespace +} // namespace + + + + + + +// ################################################################################################ +// ################################################################################################ +// The implementation part +// ################################################################################################ +// ################################################################################################ + +namespace epee +{ +namespace net_utils +{ + +// ================================================================================================ +// network_throttle +// ================================================================================================ + +network_throttle::~network_throttle() { } + +network_throttle::packet_info::packet_info() + : m_size(0) +{ +} + +network_throttle::network_throttle(const std::string &nameshort, const std::string &name, int window_size) + : m_window_size( (window_size==-1) ? 10 : window_size ), + m_history( m_window_size ), m_nameshort(nameshort) +{ + set_name(name); + m_network_add_cost = 128; + m_network_minimal_segment = 256; + m_network_max_segment = 1024*1024; + m_any_packet_yet = false; + m_slot_size = 1.0; // hard coded in few places + m_target_speed = 16 * 1024; // other defaults are probably defined in the command-line parsing code when this class is used e.g. as main global throttle + m_target_MB = 0; + +} + +void network_throttle::set_name(const std::string &name) +{ + m_name = name; +} + +void network_throttle::set_target_speed( network_speed_kbps target ) +{ + m_target_speed = target; + _note_c("net/"+m_nameshort, "Setting LIMIT: " << target << " kbps"); +} + +void network_throttle::set_target_kill( network_MB target ) +{ + _note_c("net/"+m_nameshort, "Setting KILL: " << target << " MB hard limit"); + m_target_MB = target; +} + + +void network_throttle::tick() +{ + double time_now = get_time_seconds(); + if (!m_any_packet_yet) m_start_time = time_now; // starting now + + network_time_seconds current_sample_time_slot = time_to_slot( time_now ); // T=13.7 --> 13 (for 1-second smallwindow) + network_time_seconds last_sample_time_slot = time_to_slot( m_last_sample_time ); + + // moving to next position, and filling gaps + // !! during this loop the m_last_sample_time and last_sample_time_slot mean the variable moved in +1 + // TODO optimize when moving few slots at once + while ( (!m_any_packet_yet) || (last_sample_time_slot < current_sample_time_slot)) + { + LOG_PRINT_L4("Moving counter buffer by 1 second " << last_sample_time_slot << " < " << current_sample_time_slot << " (last time " << m_last_sample_time<<")"); + // rotate buffer + for (size_t i=m_history.size()-1; i>=1; --i) m_history[i] = m_history[i-1]; + m_history[0] = packet_info(); + if (! m_any_packet_yet) + { + m_last_sample_time = time_now; + } + m_last_sample_time += 1; last_sample_time_slot = time_to_slot( m_last_sample_time ); // increase and recalculate time, time slot + m_any_packet_yet=true; + } + m_last_sample_time = time_now; // the real exact last time +} + +void network_throttle::handle_trafic_exact(size_t packet_size) +{ + _handle_trafic_exact(packet_size, packet_size); +} + +void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_size) +{ + tick(); + + calculate_times_struct cts ; calculate_times(packet_size, cts , false, -1); + calculate_times_struct cts2; calculate_times(packet_size, cts2, false, 5); + m_history[0].m_size += packet_size; + + std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; + std::string history_str = oss.str(); + + logger_handle_net("log/dr-monero/net/inreq-all.data",get_time_seconds(),packet_size); + _info_c( "net/" + m_nameshort , "Throttle " << m_name << ": packet of ~"<0) ? force_window : m_window_size) + ); + + if (!m_any_packet_yet) { + cts.window=0; cts.average=0; cts.delay=0; + cts.recomendetDataSize = m_network_minimal_segment; // should be overrided by caller anyway + return ; // no packet yet, I can not decide about sleep time + } + + network_time_seconds window_len = (the_window_size-1) * m_slot_size ; // -1 since current slot is not finished + window_len += (m_last_sample_time - time_to_slot(m_last_sample_time)); // add the time for current slot e.g. 13.7-13 = 0.7 + + auto time_passed = get_time_seconds() - m_start_time; + cts.window = std::max( std::min( window_len , time_passed ) , m_slot_size ) ; // window length resulting from size of history but limited by how long ago history was started, + // also at least slot size (e.g. 1 second) to not be ridiculous + // window_len e.g. 5.7 because takes into account current slot time + + size_t Epast = 0; // summ of traffic till now + for (auto sample : m_history) Epast += sample.m_size; + + const size_t E = Epast; + const size_t Enow = Epast + packet_size ; // including the data we're about to send now + + const double M = m_target_speed; // max + const double D1 = (Epast - M*cts.window) / M; // delay - how long to sleep to get back to target speed + const double D2 = (Enow - M*cts.window) / M; // delay - how long to sleep to get back to target speed (including current packet) + + auto O = get_current_overheat(); + auto Ouse = O * 0 ; // XXX TODO + cts.delay = (D1*0.80 + D2*0.20) + Ouse; // finall sleep depends on both with/without current packet + // update_overheat(); + cts.average = Epast/cts.window; // current avg. speed (for info) + + if (Epast <= 0) { + if (cts.delay>=0) cts.delay = 0; // no traffic in history so we will not wait + } + + double Wgood=-1; + { // how much data we recommend now to download + Wgood = the_window_size + 1; + cts.recomendetDataSize = M*cts.window - E; + } + + if (dbg) { + std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; + std::string history_str = oss.str(); + _dbg1_c( "net/"+m_nameshort+"_c" , + "dbg " << m_name << ": " + << "speed is A=" << std::setw(8) <100 elements + + std::vector< packet_info > m_history; // the history of bw usage + network_time_seconds m_last_sample_time; // time of last history[0] - so we know when to rotate the buffer + network_time_seconds m_start_time; // when we were created + bool m_any_packet_yet; // did we yet got any packet to count + + double m_overheat; // last overheat + double m_overheat_time; // time in seconds after epoch + + std::string m_name; // my name for debug and logs + std::string m_nameshort; // my name for debug and logs (used in log file name) + + // each sample is now 1 second + public: + network_throttle(const std::string &nameshort, const std::string &name, int window_size=-1); + virtual ~network_throttle(); + virtual void set_name(const std::string &name); + virtual void set_target_speed( network_speed_kbps target ); + virtual void set_target_kill( network_MB target ); + + // add information about events: + virtual void handle_trafic_exact(size_t packet_size); ///< count the new traffic/packet; the size is exact considering all network costs + virtual void handle_trafic_tcp(size_t packet_size); ///< count the new traffic/packet; the size is as TCP, we will consider MTU etc + virtual void handle_congestion(double overheat); ///< call this when congestion is detected; see example use + + virtual void tick(); ///< poke and update timers/history (recalculates, moves the history if needed, checks the real clock etc) + + virtual double get_time_seconds() const ; ///< timer that we use, time in seconds, monotionic + virtual double get_current_overheat() const; ///< did we detected congestion now. NOT USED NOW TODO + virtual void set_overheat(double lag); ///< did we detected congestion now. NOT USED NOW TODO. rename to add_overheat ? + + // time calculations: + virtual void calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const; ///< MAIN LOGIC (see base class for info) + + virtual network_time_seconds get_sleep_time_after_tick(size_t packet_size); ///< increase the timer if needed, and get the package size + virtual network_time_seconds get_sleep_time(size_t packet_size) const; ///< gets the Delay (recommended Delay time) from calc. (not safe: only if time didnt change?) TODO + + virtual size_t get_recommended_size_of_planned_transport() const; ///< what should be the size (bytes) of next data block to be transported + virtual size_t get_recommended_size_of_planned_transport_window(double force_window) const; ///< ditto, but for given windows time frame + //virtual void add_planned_transport(size_t size); + + private: + virtual network_time_seconds time_to_slot(network_time_seconds t) const { return std::floor( t ); } // convert exact time eg 13.7 to rounded time for slot number in history 13 + virtual void _handle_trafic_exact(size_t packet_size, size_t orginal_size); + virtual void logger_handle_net(const std::string &filename, double time, size_t size); +}; + +/*** + * The complete set of traffic throttle for one typical connection +*/ +struct network_throttle_bw { + public: + network_throttle m_in; ///< for incomming traffic (this we can not controll directly as it depends of what others send to us - usually) + network_throttle m_inreq; ///< for requesting incomming traffic (this is exact usually) + network_throttle m_out; ///< for outgoing traffic that we just sent (this is exact usually) + + public: + network_throttle_bw(const std::string &name1); +}; + + + +} // namespace net_utils +} // namespace epee + + +#endif + + diff --git a/src/p2p/network_throttle.cpp b/src/p2p/network_throttle.cpp new file mode 100644 index 000000000..3d5edcdcd --- /dev/null +++ b/src/p2p/network_throttle.cpp @@ -0,0 +1,121 @@ +/** +@file +@author rfree (current maintainer in monero.cc project) +@brief interface for throttling of connection (count and rate-limit speed etc) +@details
+
+Throttling work by:
+1) taking note of all traffic (hooks added e.g. to connection class) and measuring speed
+2) depending on that information we sleep before sending out data (or send smaller portions of data)
+3) depending on the information we can also sleep before sending requests or ask for smaller sets of data to download
+
+
+ +@image html images/net/rate1-down-1k.png +@image html images/net/rate1-down-full.png +@image html images/net/rate1-up-10k.png +@image html images/net/rate1-up-full.png +@image html images/net/rate2-down-100k.png +@image html images/net/rate2-down-10k.png +@image html images/net/rate2-down-50k.png +@image html images/net/rate2-down-full.png +@image html images/net/rate2-up-100k.png +@image html images/net/rate2-up-10k.png +@image html images/net/rate3-up-10k.png + + +*/ + +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "../../src/p2p/network_throttle-detail.hpp" + +namespace epee +{ +namespace net_utils +{ + +// ================================================================================================ +// network_throttle_manager +// ================================================================================================ + +// ================================================================================================ +// static: +std::mutex network_throttle_manager::m_lock_get_global_throttle_in; +std::mutex network_throttle_manager::m_lock_get_global_throttle_inreq; +std::mutex network_throttle_manager::m_lock_get_global_throttle_out; + +int network_throttle_manager::xxx; + + +// ================================================================================================ +// methods: +i_network_throttle & network_throttle_manager::get_global_throttle_in() { + + std::call_once(m_once_get_global_throttle_in, [] { m_obj_get_global_throttle_in.reset(new network_throttle("in/all","<<< global-IN",10)); } ); + return * m_obj_get_global_throttle_in; +} +std::once_flag network_throttle_manager::m_once_get_global_throttle_in; +std::unique_ptr network_throttle_manager::m_obj_get_global_throttle_in; + + + +i_network_throttle & network_throttle_manager::get_global_throttle_inreq() { + std::call_once(m_once_get_global_throttle_inreq, [] { m_obj_get_global_throttle_inreq.reset(new network_throttle("inreq/all", "<== global-IN-REQ",10)); } ); + return * m_obj_get_global_throttle_inreq; +} +std::once_flag network_throttle_manager::m_once_get_global_throttle_inreq; +std::unique_ptr network_throttle_manager::m_obj_get_global_throttle_inreq; + + +i_network_throttle & network_throttle_manager::get_global_throttle_out() { + std::call_once(m_once_get_global_throttle_out, [] { m_obj_get_global_throttle_out.reset(new network_throttle("out/all", ">>> global-OUT",10)); } ); + return * m_obj_get_global_throttle_out; +} +std::once_flag network_throttle_manager::m_once_get_global_throttle_out; +std::unique_ptr network_throttle_manager::m_obj_get_global_throttle_out; + + + + +network_throttle_bw::network_throttle_bw(const std::string &name1) + : m_in("in/"+name1, name1+"-DOWNLOAD"), m_inreq("inreq/"+name1, name1+"-DOWNLOAD-REQUESTS"), m_out("out/"+name1, name1+"-UPLOAD") +{ } + + + + +} // namespace +} // namespace + + + + + diff --git a/src/p2p/network_throttle.hpp b/src/p2p/network_throttle.hpp new file mode 100644 index 000000000..dc25a2c45 --- /dev/null +++ b/src/p2p/network_throttle.hpp @@ -0,0 +1,187 @@ +/// @file +/// @author rfree (current maintainer in monero.cc project) +/// @brief interface for throttling of connection (count and rate-limit speed etc) + +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +/* rfree: throttle basic interface */ +/* rfree: also includes the manager for singeton/global such objects */ + + +#ifndef INCLUDED_p2p_network_throttle_hpp +#define INCLUDED_p2p_network_throttle_hpp + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "syncobj.h" + +#include "../../contrib/epee/include/net/net_utils_base.h" +#include "../../contrib/epee/include/misc_log_ex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "misc_language.h" +#include "pragma_comp_defs.h" +#include +#include +#include + +#include +#include +#include + +namespace epee +{ +namespace net_utils +{ + +// just typedefs to in code define the units used. TODO later it will be enforced that casts to other numericals are only explicit to avoid mistakes? use boost::chrono? +typedef double network_speed_kbps; +typedef double network_time_seconds; +typedef double network_MB; + +class i_network_throttle; + +/*** +@brief All information about given throttle - speed calculations +*/ +struct calculate_times_struct { + double average; + double window; + double delay; + double recomendetDataSize; +}; +typedef calculate_times_struct calculate_times_struct; + + +namespace cryptonote { class cryptonote_protocol_handler_base; }; // a friend class // TODO friend not working + +/*** +@brief Access to simple throttles, with singlton to access global network limits +*/ +class network_throttle_manager { + // provides global (singleton) in/inreq/out throttle access + + // [[note1]] see also http://www.nuonsoft.com/blog/2012/10/21/implementing-a-thread-safe-singleton-with-c11/ + // [[note2]] _inreq is the requested in traffic - we anticipate we will get in-bound traffic soon as result of what we do (e.g. that we sent network downloads requests) + + //protected: + public: // XXX + // [[note1]] + static std::once_flag m_once_get_global_throttle_in; + static std::once_flag m_once_get_global_throttle_inreq; // [[note2]] + static std::once_flag m_once_get_global_throttle_out; + static std::unique_ptr m_obj_get_global_throttle_in; + static std::unique_ptr m_obj_get_global_throttle_inreq; + static std::unique_ptr m_obj_get_global_throttle_out; + + static std::mutex m_lock_get_global_throttle_in; + static std::mutex m_lock_get_global_throttle_inreq; + static std::mutex m_lock_get_global_throttle_out; + + friend class cryptonote::cryptonote_protocol_handler_base; // FRIEND - to directly access global throttle-s. !! REMEMBER TO USE LOCKS! + friend class connection_basic; // FRIEND - to directly access global throttle-s. !! REMEMBER TO USE LOCKS! + friend class connection_basic_pimpl; // ditto + + static int xxx; + + public: + static i_network_throttle & get_global_throttle_in(); ///< singleton ; for friend class ; caller MUST use proper locks! like m_lock_get_global_throttle_in + static i_network_throttle & get_global_throttle_inreq(); ///< ditto ; use lock ... use m_lock_get_global_throttle_inreq obviously + static i_network_throttle & get_global_throttle_out(); ///< ditto ; use lock ... use m_lock_get_global_throttle_out obviously +}; + + + +/*** +@brief interface for the throttle, see the derivated class +*/ +class i_network_throttle { + public: + virtual void set_name(const std::string &name)=0; + virtual void set_target_speed( network_speed_kbps target )=0; + virtual void set_target_kill( network_MB target )=0; + + virtual void handle_trafic_exact(size_t packet_size) =0; // count the new traffic/packet; the size is exact considering all network costs + virtual void handle_trafic_tcp(size_t packet_size) =0; // count the new traffic/packet; the size is as TCP, we will consider MTU etc + virtual void handle_congestion(double overheat) =0; // call this when congestion is detected; see example use + virtual void tick() =0; // poke and update timers/history + + // time calculations: + + virtual void calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const =0; // assuming sending new package (or 0), calculate: + // Average, Window, Delay, Recommended data size ; also gets dbg=debug flag, and forced widnow size if >0 or -1 for not forcing window size + + // Average speed, Window size, recommended Delay to sleep now, Recommended size of data to send now + + virtual network_time_seconds get_sleep_time(size_t packet_size) const =0; // gets the D (recommended Delay time) from calc + virtual network_time_seconds get_sleep_time_after_tick(size_t packet_size) =0; // ditto, but first tick the timer + + virtual size_t get_recommended_size_of_planned_transport() const =0; // what should be the recommended limit of data size that we can transport over current network_throttle in near future + + virtual double get_time_seconds() const =0; // a timer + virtual double get_current_overheat() const =0; + virtual void set_overheat(double lag) =0; + virtual void logger_handle_net(const std::string &filename, double time, size_t size)=0; + + +}; + + +// ... more in the -advanced.h file + + +} // namespace net_utils +} // namespace epee + + +#endif + + + -- cgit v1.2.3 From 5ce4256e3d6ff2e1595750e3875865089e20a03b Mon Sep 17 00:00:00 2001 From: rfree2monero Date: Thu, 12 Feb 2015 20:59:39 +0100 Subject: 2014 network limit 1.1 +utils +toc -doc -drmonero Update of the PR with network limits works very well for all speeds (but remember that low download speed can stop upload because we then slow down downloading of blockchain requests too) more debug options fixed pedantic warnings in our code should work again on Mac OS X and FreeBSD fixed warning about size_t tested on Debian, Ubuntu, Windows(testing now) TCP options and ToS (QoS) flag FIXED peer number limit FIXED some spikes in ingress/download FIXED problems when other up and down limit --- src/p2p/connection_basic.cpp | 167 +++++++++++------------------------- src/p2p/connection_basic.hpp | 11 +-- src/p2p/data_logger.cpp | 81 +++++++++++++++++ src/p2p/data_logger.hpp | 46 ++++++++++ src/p2p/net_node.h | 12 ++- src/p2p/net_node.inl | 66 ++++++++++++-- src/p2p/network_throttle-detail.cpp | 75 ++++++++-------- src/p2p/network_throttle-detail.hpp | 10 +-- src/p2p/network_throttle.hpp | 8 +- 9 files changed, 293 insertions(+), 183 deletions(-) create mode 100644 src/p2p/data_logger.cpp create mode 100644 src/p2p/data_logger.hpp (limited to 'src/p2p') diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp index 35b0d4c8e..0e2fd5942 100644 --- a/src/p2p/connection_basic.cpp +++ b/src/p2p/connection_basic.cpp @@ -78,6 +78,7 @@ #include "../../contrib/epee/include/net/abstract_tcp_server2.h" #include "../../contrib/otshell_utils/utils.hpp" +#include "data_logger.hpp" using namespace nOT::nUtils; // TODO: @@ -146,31 +147,31 @@ connection_basic::connection_basic(boost::asio::io_service& io_service, std::ato { ++ref_sock_count; // increase the global counter mI->m_peer_number = sock_number.fetch_add(1); // use, and increase the generated number - _note("Spawned connection p2p#"<m_peer_number<<" currently we have sockets count:" << m_ref_sock_count); + + string remote_addr_str = "?"; + try { remote_addr_str = socket_.remote_endpoint().address().to_string(); } catch(...){} ; + + _note("Spawned connection p2p#"<m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_ref_sock_count); boost::filesystem::create_directories("log/dr-monero/net/"); - /*boost::asio::SettableSocketOption option;// = new boost::asio::SettableSocketOption(); - option.level(IPPROTO_IP); - option.name(IP_TOS); - option.value(&tos); - option.size = sizeof(tos); - socket_.set_option(option);*/ - // TODO socket options } connection_basic::~connection_basic() { - _note("Destructing connection p2p#"<m_peer_number); + string remote_addr_str = "?"; + try { remote_addr_str = socket_.remote_endpoint().address().to_string(); } catch(...){} ; + _note("Destructing connection p2p#"<m_peer_number << " to " << remote_addr_str); } void connection_basic::set_rate_up_limit(uint64_t limit) { - save_limit_to_file(limit); + + // TODO remove __SCALING_FACTOR... + const double SCALING_FACTOR = 2.1; // to acheve the best performance + limit *= SCALING_FACTOR; { - // TODO remove __SCALING_FACTOR... - const double SCALING_FACTOR = 2.25; // to acheve the best performance - limit *= SCALING_FACTOR; CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); network_throttle_manager::get_global_throttle_out().set_target_speed(limit); + network_throttle_manager::get_global_throttle_out().set_real_target_speed(limit / SCALING_FACTOR); } - // connection_basic_pimpl::m_throttle_global.m_out.set_target_speed(limit); + save_limit_to_file(limit); } void connection_basic::set_rate_down_limit(uint64_t limit) { @@ -186,36 +187,30 @@ void connection_basic::set_rate_down_limit(uint64_t limit) { save_limit_to_file(limit); } -void connection_basic::set_rate_limit(uint64_t limit) { - // TODO -} -void connection_basic::set_kill_limit (uint64_t limit) { - { - CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_in ); - network_throttle_manager::get_global_throttle_in().set_target_kill(limit); - } - - { - CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); - network_throttle_manager::get_global_throttle_out().set_target_kill(limit); - } - - { - CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_inreq ); - network_throttle_manager::get_global_throttle_inreq().set_target_kill(limit); - } -} void connection_basic::save_limit_to_file(int limit) { // saving limit to file - std::ofstream file; - file.open("log/dr-monero/limit.info"); - file << limit; -} - -void connection_basic::set_rate_autodetect(uint64_t limit) { - // TODO - LOG_PRINT_L0("inside connection_basic we set autodetect (this is additional notification).."); + if (!epee::net_utils::data_logger::m_save_graph) + return; + std::ofstream file_up, file_down; + file_up.open("log/dr-monero/limit_up.info", std::ofstream::out | std::ofstream::app); + file_up.precision(8); + file_down.open("log/dr-monero/limit_down.info", std::ofstream::out | std::ofstream::app); + file_down.precision(8); + using namespace boost::chrono; + auto point = steady_clock::now(); + auto time_from_epoh = point.time_since_epoch(); + auto s = duration_cast< seconds >( time_from_epoh ).count(); + + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + file_up << s << " " << network_throttle_manager::get_global_throttle_out().get_terget_speed() / 1024 << "\n"; + } + + { + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_in ); + file_down << s << " " << network_throttle_manager::get_global_throttle_in().get_terget_speed() / 1024 << "\n"; + } } void connection_basic::set_tos_flag(int tos) { @@ -230,39 +225,30 @@ void connection_basic::sleep_before_packet(size_t packet_size, int phase, int q double delay=0; // will be calculated do { // rate limiting - //XXX - /*if (::cryptonote::core::get_is_stopping()) { - _dbg1("We are stopping - so abort sleep"); - return; - }*/ if (m_was_shutdown) { _dbg2("m_was_shutdown - so abort sleep"); return; } { - CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); delay = network_throttle_manager::get_global_throttle_out().get_sleep_time_after_tick( packet_size ); // decission from global } - delay *= 0.50; - delay = 0; // XXX if (delay > 0) { - //delay += rand2*0.1; - long int ms = (long int)(delay * 1000); - _info_c("net/sleep", "Sleeping in " << __FUNCTION__ << " for " << ms << " ms before packet_size="< 0); // XXX LATER XXX { CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); - network_throttle_manager::get_global_throttle_out().handle_trafic_tcp( packet_size ); // increase counter - global - //epee::critical_region_t guard(m_throttle_global_lock); // *** critical *** - //m_throttle_global.m_out.handle_trafic_tcp( packet_size ); // increase counter - global + network_throttle_manager::get_global_throttle_out().handle_trafic_exact( packet_size * 700); // increase counter - global } } @@ -271,34 +257,12 @@ void connection_basic::set_start_time() { m_start_time = network_throttle_manager::get_global_throttle_out().get_time_seconds(); } -void connection_basic::do_send_handler_start(const void* ptr , size_t cb ) { - _fact_c("net/out/size", "*** do_sen() called for packet="< max sending time - //if (sending_time > 0.1) network_throttle_manager::get_global_throttle_out().set_overheat(sending_time); // TODO - -} - void connection_basic::do_send_handler_write_from_queue( const boost::system::error_code& e, size_t cb, int q_len ) { sleep_before_packet(cb,2,q_len); _info_c("net/out/size", "handler_write (after write, from queue="<m_throttle_global_lock)> guard(mI->m_throttle_global_lock); // *** critical *** - // mI->m_throttle_global.m_in.handle_trafic_tcp( packet_size ); // increase counter - global - } -} - -void connection_basic::logger_handle_net_peer(size_t size, bool io) { // network data written - // TODO OPTIMIZE! do NOT reopen idiotically :) - std::ostringstream oss; - std::string filename; - if (io) { // write - double time = network_throttle_manager::get_global_throttle_in().get_time_seconds() ; - oss << "log/dr-monero/net/in-peer-" << (mI->m_peer_number) << ".dat" << std::ends; - filename = oss.str(); - network_throttle_manager::get_global_throttle_out().logger_handle_net(filename,time,size); - } - else { // read - double time = network_throttle_manager::get_global_throttle_out().get_time_seconds() ; - oss << "log/dr-monero/net/out-peer-" << (mI->m_peer_number) << ".dat" << std::ends; - filename = oss.str(); - network_throttle_manager::get_global_throttle_in().logger_handle_net(filename,time,size); - } -} - void connection_basic::logger_handle_net_read(size_t size) { // network data read - std::string filename = "log/dr-monero/net/in-all.data"; - - double time = network_throttle_manager::get_global_throttle_in().get_time_seconds() ; - network_throttle_manager::get_global_throttle_in().logger_handle_net(filename, time, size); - logger_handle_net_peer(size,0); + size /= 1024; + epee::net_utils::data_logger::get_instance().add_data("download", size); } void connection_basic::logger_handle_net_write(size_t size) { - std::string filename = "log/dr-monero/net/out-all.data"; - double time = network_throttle_manager::get_global_throttle_out().get_time_seconds() ; - network_throttle_manager::get_global_throttle_out().logger_handle_net(filename, time, size); - logger_handle_net_peer(size,1); - + size /= 1024; + epee::net_utils::data_logger::get_instance().add_data("upload", size); } double connection_basic::get_sleep_time(size_t cb) { @@ -356,6 +285,10 @@ double connection_basic::get_sleep_time(size_t cb) { return t; } +void connection_basic::set_save_graph(bool save_graph) { + epee::net_utils::data_logger::m_save_graph = save_graph; +} + } // namespace } // namespace diff --git a/src/p2p/connection_basic.hpp b/src/p2p/connection_basic.hpp index 1b5a2c8ad..e9fdc3add 100644 --- a/src/p2p/connection_basic.hpp +++ b/src/p2p/connection_basic.hpp @@ -99,17 +99,11 @@ class connection_basic { // not-templated base class for rapid developmet of som virtual ~connection_basic(); // various handlers to be called from connection class: - void do_send_handler_start(const void * ptr , size_t cb); - void do_send_handler_delayed(const void * ptr , size_t cb); void do_send_handler_write(const void * ptr , size_t cb); - void do_send_handler_stop(const void * ptr , size_t cb); - void do_send_handler_after_write( const boost::system::error_code& e, size_t cb ); // from handle_write void do_send_handler_write_from_queue(const boost::system::error_code& e, size_t cb , int q_len); // from handle_write, sending next part - void do_read_handler_start(const boost::system::error_code& e, std::size_t bytes_transferred); // from read, after read completion void logger_handle_net_write(size_t size); // network data written void logger_handle_net_read(size_t size); // network data read - void logger_handle_net_peer(size_t size, bool io); void set_start_time(); @@ -117,9 +111,6 @@ class connection_basic { // not-templated base class for rapid developmet of som static void set_rate_up_limit(uint64_t limit); static void set_rate_down_limit(uint64_t limit); - static void set_rate_limit(uint64_t limit); - static void set_rate_autodetect(uint64_t limit); - static void set_kill_limit (uint64_t limit); // config misc static void set_tos_flag(int tos); // ToS / QoS flag @@ -129,6 +120,8 @@ class connection_basic { // not-templated base class for rapid developmet of som void sleep_before_packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?) static void save_limit_to_file(int limit); ///< for dr-monero static double get_sleep_time(size_t cb); + + static void set_save_graph(bool save_graph); }; } // nameserver diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp new file mode 100644 index 000000000..6a8eb25be --- /dev/null +++ b/src/p2p/data_logger.cpp @@ -0,0 +1,81 @@ +#include "data_logger.hpp" + +#include +#include + +namespace epee +{ +namespace net_utils +{ + data_logger &data_logger::get_instance() + { + static data_logger instance; + return instance; + } + + data_logger::data_logger() + { + //create timer + std::shared_ptr logger_thread(new std::thread([&]() + { + while (true) + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + saveToFile(); + } + })); + logger_thread->detach(); + + mFilesMap["peers"] = data_logger::fileData("log/dr-monero/peers.data"); + mFilesMap["download"] = data_logger::fileData("log/dr-monero/net/in-all.data"); + mFilesMap["upload"] = data_logger::fileData("log/dr-monero/net/out-all.data"); + mFilesMap["request"] = data_logger::fileData("log/dr-monero/net/req-all.data"); + mFilesMap["sleep_down"] = data_logger::fileData("log/dr-monero/down_sleep_log.data"); + mFilesMap["sleep_up"] = data_logger::fileData("log/dr-monero/up_sleep_log.data"); + + } + + void data_logger::add_data(std::string filename, unsigned int data) + { + if (mFilesMap.find(filename) == mFilesMap.end()) + return; // TODO: exception + + mFilesMap[filename].mDataToSave += data; + } + + double data_logger::fileData::get_current_time() + { + using namespace boost::chrono; + auto point = steady_clock::now(); + auto time_from_epoh = point.time_since_epoch(); + auto ms = duration_cast< milliseconds >( time_from_epoh ).count(); + double ms_f = ms; + return ms_f / 1000.; + } + + data_logger::fileData::fileData(std::string pFile) + { + mFile = std::make_shared (pFile); + } + + void data_logger::fileData::save() + { + if (!data_logger::m_save_graph) + return; + *mFile << static_cast(get_current_time()) << " " << mDataToSave << std::endl; + } + + void data_logger::saveToFile() + { + std::lock_guard lock(mSaveMutex); + for (auto &element : mFilesMap) + { + element.second.save(); + element.second.mDataToSave = 0; + } + } + +std::atomic data_logger::m_save_graph(false); + +} // namespace +} // namespace diff --git a/src/p2p/data_logger.hpp b/src/p2p/data_logger.hpp new file mode 100644 index 000000000..2b8503df3 --- /dev/null +++ b/src/p2p/data_logger.hpp @@ -0,0 +1,46 @@ +#ifndef INCLUDED_p2p_data_logger_hpp +#define INCLUDED_p2p_data_logger_hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace epee +{ +namespace net_utils +{ + + class data_logger { + public: + static data_logger &get_instance(); + data_logger(const data_logger &ob) = delete; + data_logger(data_logger &&ob) = delete; + void add_data(std::string filename, unsigned int data); + static std::atomic m_save_graph; + private: + data_logger(); + class fileData + { + public: + fileData(){} + fileData(std::string pFile); + + std::shared_ptr mFile; + long int mDataToSave = 0; + static double get_current_time(); + void save(); + }; + + std::map mFilesMap; + std::mutex mSaveMutex; + void saveToFile(); + }; + +} // namespace +} // namespace + +#endif diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 48737193e..ea7d5c383 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -86,7 +86,10 @@ namespace nodetool m_no_igd(false), m_hide_my_port(false), m_network_id(std::move(network_id)) - {} + { + m_number_of_out_peers = 0; + m_save_graph = false; + } static void init_options(boost::program_options::options_description& desc); @@ -225,6 +228,12 @@ namespace nodetool public: config m_config; // TODO was private, add getters? + std::atomic m_number_of_out_peers; + void set_save_graph(bool save_graph) + { + m_save_graph = save_graph; + epee::net_utils::connection_basic::set_save_graph(save_graph); + } private: std::string m_config_folder; @@ -237,6 +246,7 @@ namespace nodetool bool m_allow_local_ip; bool m_hide_my_port; bool m_no_igd; + std::atomic m_save_graph; //critical_section m_connections_lock; //connections_indexed_container m_connections; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ce70e241a..60eed1f36 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -46,6 +46,7 @@ #include "net/local_ip.h" #include "crypto/crypto.h" #include "storages/levin_abstract_invoke2.h" +#include "data_logger.hpp" // We have to look for miniupnpc headers in different places, dependent on if its compiled or external #ifdef UPNP_STATIC @@ -85,8 +86,8 @@ namespace nodetool const command_line::arg_descriptor > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; - const command_line::arg_descriptor arg_no_igd = {"no-igd", "Disable UPnP port mapping"}; - const command_line::arg_descriptor arg_out_peers = {"out-peers", "set max limit of out peers", -1}; + const command_line::arg_descriptor arg_no_igd = {"no-igd", "Disable UPnP port mapping"}; + const command_line::arg_descriptor arg_out_peers = {"out-peers", "set max limit of out peers", -1}; const command_line::arg_descriptor arg_tos_flag = {"tos-flag", "set TOS flag", -1}; const command_line::arg_descriptor arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", -1}; @@ -289,6 +290,31 @@ namespace nodetool std::vector> dns_results; dns_results.resize(m_seed_nodes_list.size()); + + std::shared_ptr peersLoggerThread (new std::thread([&]() + { + unsigned int number_of_peers; + while (1) + { + if (m_save_graph) + { + //number_of_peers = m_net_server.get_config_object().get_connections_count(); + number_of_peers = 0; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if(!cntxt.m_is_income) + ++number_of_peers; + return true; + }); // lambda + + m_number_of_out_peers = number_of_peers; + epee::net_utils::data_logger::get_instance().add_data("peers", number_of_peers); + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + })); // lambda + + peersLoggerThread->detach(); std::list dns_threads; uint64_t result_index = 0; @@ -487,6 +513,7 @@ namespace nodetool { m_peerlist.deinit(); m_net_server.deinit_server(); + return store_config(); } //----------------------------------------------------------------------------------- @@ -697,6 +724,16 @@ namespace nodetool template bool node_server::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white) { + if (m_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit + { + return false; + } + else if (m_number_of_out_peers > m_config.m_net_config.connections_count) + { + m_net_server.get_config_object().del_out_connections(1); + m_number_of_out_peers --; // atomic variable, update time = 1s + return false; + } LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":" << epee::string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never") @@ -784,16 +821,22 @@ namespace nodetool ++try_count; - if(is_peer_used(pe)) + _note("Considering connecting (out) to peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast(pe.adr.port)); + + if(is_peer_used(pe)) { + _note("Peer is used"); continue; + } LOG_PRINT_L1("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast(pe.adr.port) << "[white=" << use_white_list << "] last_seen: " << (pe.last_seen ? epee::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)) + if(!try_to_connect_and_handshake_with_new_peer(pe.adr, false, pe.last_seen, use_white_list)) { + _note("Handshake failed"); continue; + } return true; } @@ -1336,20 +1379,31 @@ namespace nodetool template bool node_server::set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max) { + using namespace std::chrono; + auto point = steady_clock::now(); + auto time_from_epoh = point.time_since_epoch(); + auto ms = duration_cast< milliseconds >( time_from_epoh ).count(); + double ms_f = ms; + ms_f /= 1000.; + + std::ofstream limitFile("log/dr-monero/peers_limit.info", std::ios::app); + limitFile.precision(7); if(max == -1) { m_config.m_net_config.connections_count = P2P_DEFAULT_CONNECTIONS_COUNT; + if (m_save_graph) + limitFile << static_cast(ms_f) << " " << P2P_DEFAULT_CONNECTIONS_COUNT << std::endl; return true; } m_config.m_net_config.connections_count = max; - LOG_PRINT_RED_L0("connections_count: " << m_config.m_net_config.connections_count); + limitFile << static_cast(ms_f) << " " << max << std::endl; return true; } template void node_server::delete_connections(size_t count) { - m_net_server.get_config_object().del_connections(count); + m_net_server.get_config_object().del_out_connections(count); } template diff --git a/src/p2p/network_throttle-detail.cpp b/src/p2p/network_throttle-detail.cpp index 6ea3076a9..6b2ee698e 100644 --- a/src/p2p/network_throttle-detail.cpp +++ b/src/p2p/network_throttle-detail.cpp @@ -78,6 +78,7 @@ #include "../../src/p2p/network_throttle-detail.hpp" #include "../../contrib/otshell_utils/utils.hpp" +#include "data_logger.hpp" using namespace nOT::nUtils; // ################################################################################################ @@ -152,8 +153,6 @@ network_throttle::network_throttle(const std::string &nameshort, const std::stri m_any_packet_yet = false; m_slot_size = 1.0; // hard coded in few places m_target_speed = 16 * 1024; // other defaults are probably defined in the command-line parsing code when this class is used e.g. as main global throttle - m_target_MB = 0; - } void network_throttle::set_name(const std::string &name) @@ -163,16 +162,20 @@ void network_throttle::set_name(const std::string &name) void network_throttle::set_target_speed( network_speed_kbps target ) { - m_target_speed = target; + m_target_speed = target * 1024; _note_c("net/"+m_nameshort, "Setting LIMIT: " << target << " kbps"); + set_real_target_speed(target); } -void network_throttle::set_target_kill( network_MB target ) +void network_throttle::set_real_target_speed( network_speed_kbps real_target ) { - _note_c("net/"+m_nameshort, "Setting KILL: " << target << " MB hard limit"); - m_target_MB = target; + m_real_target_speed = real_target * 1024; } +network_speed_kbps network_throttle::get_terget_speed() +{ + return m_real_target_speed / 1024; +} void network_throttle::tick() { @@ -187,7 +190,7 @@ void network_throttle::tick() // TODO optimize when moving few slots at once while ( (!m_any_packet_yet) || (last_sample_time_slot < current_sample_time_slot)) { - LOG_PRINT_L4("Moving counter buffer by 1 second " << last_sample_time_slot << " < " << current_sample_time_slot << " (last time " << m_last_sample_time<<")"); + _dbg3("Moving counter buffer by 1 second " << last_sample_time_slot << " < " << current_sample_time_slot << " (last time " << m_last_sample_time<<")"); // rotate buffer for (size_t i=m_history.size()-1; i>=1; --i) m_history[i] = m_history[i-1]; m_history[0] = packet_info(); @@ -217,7 +220,6 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; std::string history_str = oss.str(); - logger_handle_net("log/dr-monero/net/inreq-all.data",get_time_seconds(),packet_size); _info_c( "net/" + m_nameshort , "Throttle " << m_name << ": packet of ~"<(time) << " " << static_cast(size/1024) << "\n"; file.close(); } mutex.unlock(); } @@ -257,27 +258,11 @@ void network_throttle::logger_handle_net(const std::string &filename, double tim // fine tune this to decide about sending speed: network_time_seconds network_throttle::get_sleep_time(size_t packet_size) const { - //_scope_mark(""); double D2=0; calculate_times_struct cts = { 0, 0, 0, 0}; - //calculate_times(packet_size, cts, false, m_window_size/2); D2=cts.delay; - //calculate_times(packet_size, cts, true, m_window_size/2); D2=cts.delay; calculate_times(packet_size, cts, true, m_window_size); D2=cts.delay; return D2; } -double network_throttle::get_current_overheat() const { - auto now = get_time_seconds(); - auto diff = now - m_overheat_time; - auto overheat = m_overheat - diff; - overheat = std::max(m_overheat, 0.); - return overheat; -} - -void network_throttle::set_overheat(double lag) { - m_overheat += lag; - m_overheat_time = get_time_seconds(); - LOG_PRINT_L0("Lag: " << lag << ", overheat: " << m_overheat ); -} // MAIN LOGIC: void network_throttle::calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const @@ -310,9 +295,7 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc const double D1 = (Epast - M*cts.window) / M; // delay - how long to sleep to get back to target speed const double D2 = (Enow - M*cts.window) / M; // delay - how long to sleep to get back to target speed (including current packet) - auto O = get_current_overheat(); - auto Ouse = O * 0 ; // XXX TODO - cts.delay = (D1*0.80 + D2*0.20) + Ouse; // finall sleep depends on both with/without current packet + cts.delay = (D1*0.80 + D2*0.20); // finall sleep depends on both with/without current packet // update_overheat(); cts.average = Epast/cts.window; // current avg. speed (for info) @@ -329,13 +312,13 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc if (dbg) { std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; std::string history_str = oss.str(); - _dbg1_c( "net/"+m_nameshort+"_c" , - "dbg " << m_name << ": " + _info_c( "net/"+m_nameshort+"_c" , + (cts.delay > 0 ? "SLEEP" : "") + << "dbg " << m_name << ": " << "speed is A=" << std::setw(8) <( time_from_epoh ).count(); @@ -368,14 +351,28 @@ size_t network_throttle::get_recommended_size_of_planned_transport_window(double size_t network_throttle::get_recommended_size_of_planned_transport() const { size_t R1=0,R2=0,R3=0; R1 = get_recommended_size_of_planned_transport_window( -1 ); - R2 = get_recommended_size_of_planned_transport_window( m_window_size/2); - R3 = get_recommended_size_of_planned_transport_window( 8 ); + R2 = get_recommended_size_of_planned_transport_window(m_window_size / 2); + R3 = get_recommended_size_of_planned_transport_window( 5 ); auto RM = std::min(R1, std::min(R2,R3)); - const double a1=70, a2=10, a3=10, am=10; // weight of the various windows in decisssion + const double a1=20, a2=10, a3=10, am=10; // weight of the various windows in decisssion // TODO 70 => 20 return (R1*a1 + R2*a2 + R3*a3 + RM*am) / (a1+a2+a3+am); } +double network_throttle::get_current_speed() const { + unsigned int bytes_transferred = 0; + if (m_history.size() == 0 || m_slot_size == 0) + return 0; + + auto it = m_history.begin(); + while (it < m_history.end() - 1) + { + bytes_transferred += it->m_size; + it ++; + } + + return bytes_transferred / ((m_history.size() - 1) * m_slot_size); +} } // namespace } // namespace diff --git a/src/p2p/network_throttle-detail.hpp b/src/p2p/network_throttle-detail.hpp index 9d492c534..063dac850 100644 --- a/src/p2p/network_throttle-detail.hpp +++ b/src/p2p/network_throttle-detail.hpp @@ -54,7 +54,7 @@ class network_throttle : public i_network_throttle { network_speed_kbps m_target_speed; - network_MB m_target_MB; + network_speed_kbps m_real_target_speed; size_t m_network_add_cost; // estimated add cost of headers size_t m_network_minimal_segment; // estimated minimal cost of sending 1 byte to round up to size_t m_network_max_segment; // recommended max size of 1 TCP transmission @@ -80,18 +80,16 @@ class network_throttle : public i_network_throttle { virtual ~network_throttle(); virtual void set_name(const std::string &name); virtual void set_target_speed( network_speed_kbps target ); - virtual void set_target_kill( network_MB target ); + virtual void set_real_target_speed( network_speed_kbps real_target ); // only for throttle_out + virtual network_speed_kbps get_terget_speed(); // add information about events: virtual void handle_trafic_exact(size_t packet_size); ///< count the new traffic/packet; the size is exact considering all network costs virtual void handle_trafic_tcp(size_t packet_size); ///< count the new traffic/packet; the size is as TCP, we will consider MTU etc - virtual void handle_congestion(double overheat); ///< call this when congestion is detected; see example use virtual void tick(); ///< poke and update timers/history (recalculates, moves the history if needed, checks the real clock etc) virtual double get_time_seconds() const ; ///< timer that we use, time in seconds, monotionic - virtual double get_current_overheat() const; ///< did we detected congestion now. NOT USED NOW TODO - virtual void set_overheat(double lag); ///< did we detected congestion now. NOT USED NOW TODO. rename to add_overheat ? // time calculations: virtual void calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const; ///< MAIN LOGIC (see base class for info) @@ -101,7 +99,7 @@ class network_throttle : public i_network_throttle { virtual size_t get_recommended_size_of_planned_transport() const; ///< what should be the size (bytes) of next data block to be transported virtual size_t get_recommended_size_of_planned_transport_window(double force_window) const; ///< ditto, but for given windows time frame - //virtual void add_planned_transport(size_t size); + virtual double get_current_speed() const; private: virtual network_time_seconds time_to_slot(network_time_seconds t) const { return std::floor( t ); } // convert exact time eg 13.7 to rounded time for slot number in history 13 diff --git a/src/p2p/network_throttle.hpp b/src/p2p/network_throttle.hpp index dc25a2c45..add4daa86 100644 --- a/src/p2p/network_throttle.hpp +++ b/src/p2p/network_throttle.hpp @@ -100,7 +100,7 @@ struct calculate_times_struct { typedef calculate_times_struct calculate_times_struct; -namespace cryptonote { class cryptonote_protocol_handler_base; }; // a friend class // TODO friend not working +namespace cryptonote { class cryptonote_protocol_handler_base; } // a friend class // TODO friend not working /*** @brief Access to simple throttles, with singlton to access global network limits @@ -146,11 +146,11 @@ class i_network_throttle { public: virtual void set_name(const std::string &name)=0; virtual void set_target_speed( network_speed_kbps target )=0; - virtual void set_target_kill( network_MB target )=0; + virtual void set_real_target_speed(network_speed_kbps real_target)=0; + virtual network_speed_kbps get_terget_speed()=0; virtual void handle_trafic_exact(size_t packet_size) =0; // count the new traffic/packet; the size is exact considering all network costs virtual void handle_trafic_tcp(size_t packet_size) =0; // count the new traffic/packet; the size is as TCP, we will consider MTU etc - virtual void handle_congestion(double overheat) =0; // call this when congestion is detected; see example use virtual void tick() =0; // poke and update timers/history // time calculations: @@ -166,8 +166,6 @@ class i_network_throttle { virtual size_t get_recommended_size_of_planned_transport() const =0; // what should be the recommended limit of data size that we can transport over current network_throttle in near future virtual double get_time_seconds() const =0; // a timer - virtual double get_current_overheat() const =0; - virtual void set_overheat(double lag) =0; virtual void logger_handle_net(const std::string &filename, double time, size_t size)=0; -- cgit v1.2.3 From ae2a50659f7dc74a5446a0dc3a5f8f78563b9e1f Mon Sep 17 00:00:00 2001 From: rfree2monero Date: Fri, 20 Feb 2015 22:28:03 +0100 Subject: 2014 network limit 1.2 +utils +toc -doc -drmonero new update of the pr with network limits more debug options: discarding downloaded blocks all or after given height. trying to trigger the locking errors. debug levels polished/tuned to sane values. debug/logging improved. warning: this pr should be correct code, but it could make an existing (in master version) locking error appear more often. it's a race on the list (map) of peers, e.g. between closing/deleting them versus working on them in net-limit sleep in sending chunk. the bug is not in this code/this pr, but in the master version. the locking problem of master will be fixed in other pr. problem is ub, and in practice is seems to usually cause program abort (tested on debian stable with updated gcc). see --help for option to add sleep to trigger the error faster. --- src/p2p/connection_basic.cpp | 15 +++---------- src/p2p/data_logger.cpp | 36 +++++++++++++++++++++++------ src/p2p/data_logger.hpp | 3 +++ src/p2p/net_node.h | 4 ++-- src/p2p/net_node.inl | 45 +++++++++++++------------------------ src/p2p/network_throttle-detail.cpp | 4 ++-- 6 files changed, 55 insertions(+), 52 deletions(-) (limited to 'src/p2p') diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp index 0e2fd5942..4a4a32384 100644 --- a/src/p2p/connection_basic.cpp +++ b/src/p2p/connection_basic.cpp @@ -152,7 +152,7 @@ connection_basic::connection_basic(boost::asio::io_service& io_service, std::ato try { remote_addr_str = socket_.remote_endpoint().address().to_string(); } catch(...){} ; _note("Spawned connection p2p#"<m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_ref_sock_count); - boost::filesystem::create_directories("log/dr-monero/net/"); + //boost::filesystem::create_directories("log/dr-monero/net/"); } connection_basic::~connection_basic() { @@ -192,24 +192,15 @@ void connection_basic::save_limit_to_file(int limit) { // saving limit to file if (!epee::net_utils::data_logger::m_save_graph) return; - std::ofstream file_up, file_down; - file_up.open("log/dr-monero/limit_up.info", std::ofstream::out | std::ofstream::app); - file_up.precision(8); - file_down.open("log/dr-monero/limit_down.info", std::ofstream::out | std::ofstream::app); - file_down.precision(8); - using namespace boost::chrono; - auto point = steady_clock::now(); - auto time_from_epoh = point.time_since_epoch(); - auto s = duration_cast< seconds >( time_from_epoh ).count(); { CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); - file_up << s << " " << network_throttle_manager::get_global_throttle_out().get_terget_speed() / 1024 << "\n"; + epee::net_utils::data_logger::get_instance().add_data("upload_limit", network_throttle_manager::get_global_throttle_out().get_terget_speed() / 1024); } { CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_in ); - file_down << s << " " << network_throttle_manager::get_global_throttle_in().get_terget_speed() / 1024 << "\n"; + epee::net_utils::data_logger::get_instance().add_data("download_limit", network_throttle_manager::get_global_throttle_in().get_terget_speed() / 1024); } } diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index 6a8eb25be..77f647bed 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -1,7 +1,9 @@ #include "data_logger.hpp" #include +#include #include +#include "../../contrib/otshell_utils/utils.hpp" namespace epee { @@ -32,7 +34,16 @@ namespace net_utils mFilesMap["request"] = data_logger::fileData("log/dr-monero/net/req-all.data"); mFilesMap["sleep_down"] = data_logger::fileData("log/dr-monero/down_sleep_log.data"); mFilesMap["sleep_up"] = data_logger::fileData("log/dr-monero/up_sleep_log.data"); + mFilesMap["calc_time"] = data_logger::fileData("log/dr-monero/get_objects_calc_time.data"); + mFilesMap["blockchain_processing_time"] = data_logger::fileData("log/dr-monero/blockchain_log.data"); + mFilesMap["peers_limit"] = data_logger::fileData("log/dr-monero/peers_limit.info"); + mFilesMap["download_limit"] = data_logger::fileData("log/dr-monero/limit_down.info"); + mFilesMap["upload_limit"] = data_logger::fileData("log/dr-monero/limit_up.info"); + + mFilesMap["peers_limit"].mLimitFile = true; + mFilesMap["download_limit"].mLimitFile = true; + mFilesMap["upload_limit"].mLimitFile = true; } void data_logger::add_data(std::string filename, unsigned int data) @@ -40,7 +51,14 @@ namespace net_utils if (mFilesMap.find(filename) == mFilesMap.end()) return; // TODO: exception - mFilesMap[filename].mDataToSave += data; + + nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); + + std::lock_guard lock(mSaveMutex); + if (mFilesMap[filename].mLimitFile) + mFilesMap[filename].mDataToSave = data; + else + mFilesMap[filename].mDataToSave += data; } double data_logger::fileData::get_current_time() @@ -56,23 +74,27 @@ namespace net_utils data_logger::fileData::fileData(std::string pFile) { mFile = std::make_shared (pFile); + mPath = pFile; } void data_logger::fileData::save() { if (!data_logger::m_save_graph) return; + mFile->open(mPath, std::ios::app); *mFile << static_cast(get_current_time()) << " " << mDataToSave << std::endl; + mFile->close(); } void data_logger::saveToFile() { - std::lock_guard lock(mSaveMutex); - for (auto &element : mFilesMap) - { - element.second.save(); - element.second.mDataToSave = 0; - } + std::lock_guard lock(mSaveMutex); + for (auto &element : mFilesMap) + { + element.second.save(); + if (!element.second.mLimitFile) + element.second.mDataToSave = 0; + } } std::atomic data_logger::m_save_graph(false); diff --git a/src/p2p/data_logger.hpp b/src/p2p/data_logger.hpp index 2b8503df3..50beb847a 100644 --- a/src/p2p/data_logger.hpp +++ b/src/p2p/data_logger.hpp @@ -27,12 +27,15 @@ namespace net_utils { public: fileData(){} + fileData(const fileData &ob) = delete; fileData(std::string pFile); std::shared_ptr mFile; long int mDataToSave = 0; static double get_current_time(); void save(); + std::string mPath; + bool mLimitFile = false; }; std::map mFilesMap; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index ea7d5c383..5417ffa52 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -87,7 +87,7 @@ namespace nodetool m_hide_my_port(false), m_network_id(std::move(network_id)) { - m_number_of_out_peers = 0; + m_current_number_of_out_peers = 0; m_save_graph = false; } @@ -228,7 +228,7 @@ namespace nodetool public: config m_config; // TODO was private, add getters? - std::atomic m_number_of_out_peers; + std::atomic m_current_number_of_out_peers; void set_save_graph(bool save_graph) { m_save_graph = save_graph; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 60eed1f36..a015763bf 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -296,20 +296,18 @@ namespace nodetool unsigned int number_of_peers; while (1) { - if (m_save_graph) + //number_of_peers = m_net_server.get_config_object().get_connections_count(); + number_of_peers = 0; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - //number_of_peers = m_net_server.get_config_object().get_connections_count(); - number_of_peers = 0; - m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) - { - if(!cntxt.m_is_income) - ++number_of_peers; - return true; - }); // lambda + if(!cntxt.m_is_income) + ++number_of_peers; + return true; + }); // lambda + + m_current_number_of_out_peers = number_of_peers; + epee::net_utils::data_logger::get_instance().add_data("peers", number_of_peers); - m_number_of_out_peers = number_of_peers; - epee::net_utils::data_logger::get_instance().add_data("peers", number_of_peers); - } std::this_thread::sleep_for(std::chrono::seconds(1)); } })); // lambda @@ -724,14 +722,14 @@ namespace nodetool template bool node_server::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white) { - if (m_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit + if (m_current_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit { return false; } - else if (m_number_of_out_peers > m_config.m_net_config.connections_count) + else if (m_current_number_of_out_peers > m_config.m_net_config.connections_count) { m_net_server.get_config_object().del_out_connections(1); - m_number_of_out_peers --; // atomic variable, update time = 1s + m_current_number_of_out_peers --; // atomic variable, update time = 1s return false; } LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":" @@ -1378,25 +1376,14 @@ namespace nodetool template bool node_server::set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max) - { - using namespace std::chrono; - auto point = steady_clock::now(); - auto time_from_epoh = point.time_since_epoch(); - auto ms = duration_cast< milliseconds >( time_from_epoh ).count(); - double ms_f = ms; - ms_f /= 1000.; - - std::ofstream limitFile("log/dr-monero/peers_limit.info", std::ios::app); - limitFile.precision(7); + { if(max == -1) { m_config.m_net_config.connections_count = P2P_DEFAULT_CONNECTIONS_COUNT; - if (m_save_graph) - limitFile << static_cast(ms_f) << " " << P2P_DEFAULT_CONNECTIONS_COUNT << std::endl; + epee::net_utils::data_logger::get_instance().add_data("peers_limit", m_config.m_net_config.connections_count); return true; } - + epee::net_utils::data_logger::get_instance().add_data("peers_limit", max); m_config.m_net_config.connections_count = max; - limitFile << static_cast(ms_f) << " " << max << std::endl; return true; } diff --git a/src/p2p/network_throttle-detail.cpp b/src/p2p/network_throttle-detail.cpp index 6b2ee698e..7426e6dc7 100644 --- a/src/p2p/network_throttle-detail.cpp +++ b/src/p2p/network_throttle-detail.cpp @@ -220,7 +220,7 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; std::string history_str = oss.str(); - _info_c( "net/" + m_nameshort , "Throttle " << m_name << ": packet of ~"< 0 ? "SLEEP" : "") << "dbg " << m_name << ": " << "speed is A=" << std::setw(8) < Date: Tue, 24 Feb 2015 20:12:56 +0100 Subject: 2014 network limit 1.3 fix log/path/data +utils +toc -doc -drmonero Fixed the windows path, and improved logging and data (for graph) logging, fixed some locks and added more checks. Still there is a locking error, not added by my patches, but present in master version (locking of map/list of peers). --- src/p2p/connection_basic.cpp | 1 + src/p2p/data_logger.cpp | 143 +++++++++++++++++++++++++++++-------------- src/p2p/data_logger.hpp | 52 ++++++++++++---- src/p2p/network_throttle.cpp | 1 - 4 files changed, 137 insertions(+), 60 deletions(-) (limited to 'src/p2p') diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp index 4a4a32384..ed15c0986 100644 --- a/src/p2p/connection_basic.cpp +++ b/src/p2p/connection_basic.cpp @@ -272,6 +272,7 @@ void connection_basic::logger_handle_net_write(size_t size) { } double connection_basic::get_sleep_time(size_t cb) { + CRITICAL_REGION_LOCAL(epee::net_utils::network_throttle_manager::network_throttle_manager::m_lock_get_global_throttle_out); auto t = network_throttle_manager::get_global_throttle_out().get_sleep_time(cb); return t; } diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index 77f647bed..d62af133e 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -1,4 +1,5 @@ #include "data_logger.hpp" +#include #include #include @@ -9,25 +10,25 @@ namespace epee { namespace net_utils { - data_logger &data_logger::get_instance() - { - static data_logger instance; - return instance; + data_logger &data_logger::get_instance() { + std::call_once(m_singleton, + [] { + _info_c("dbg/data","Creating singleton of data_logger"); + if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw std::runtime_error("data_logger singleton"); } + m_state = data_logger_state::state_during_init; + m_obj.reset(new data_logger()); + m_state = data_logger_state::state_ready_to_use; + } + ); + return * m_obj; } - data_logger::data_logger() - { - //create timer - std::shared_ptr logger_thread(new std::thread([&]() - { - while (true) - { - std::this_thread::sleep_for(std::chrono::seconds(1)); - saveToFile(); - } - })); - logger_thread->detach(); + data_logger::data_logger() { + _warn_c("dbg/data","Starting data logger (for graphs data)"); + if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw std::runtime_error("data_logger ctor state"); } + std::lock_guard lock(mMutex); // lock + // prepare all the files for given data channels: mFilesMap["peers"] = data_logger::fileData("log/dr-monero/peers.data"); mFilesMap["download"] = data_logger::fileData("log/dr-monero/net/in-all.data"); mFilesMap["upload"] = data_logger::fileData("log/dr-monero/net/out-all.data"); @@ -44,25 +45,80 @@ namespace net_utils mFilesMap["peers_limit"].mLimitFile = true; mFilesMap["download_limit"].mLimitFile = true; mFilesMap["upload_limit"].mLimitFile = true; + + // do NOT modify mFilesMap below this point, since there is no locking for this used (yet) + + _note_c("dbg/data","Creating thread for data logger"); // create timer thread + m_thread_maybe_running=true; + std::shared_ptr logger_thread(new std::thread([&]() { + _note_c("dbg/data","Inside thread for data logger"); + while (m_state == data_logger_state::state_during_init) { // wait for creation to be done (in other thread, in singleton) before actually running + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + _note_c("dbg/data","Inside thread for data logger - going into main loop"); + while (m_state == data_logger_state::state_ready_to_use) { // run as long as we are not closing the single object + std::this_thread::sleep_for(std::chrono::seconds(1)); + saveToFile(); // save all the pending data + } + _note_c("dbg/data","Inside thread for data logger - done the main loop"); + m_thread_maybe_running=false; + })); + logger_thread->detach(); + _info_c("dbg/data","Data logger constructed"); + } + + data_logger::~data_logger() { + _note_c("dbg/data","Destructor of the data logger"); + { + std::lock_guard lock(mMutex); + m_state = data_logger_state::state_dying; + } + _info_c("dbg/data","State was set to dying"); + while(m_thread_maybe_running) { // wait for the thread to exit + std::this_thread::sleep_for(std::chrono::seconds(1)); + _info_c("dbg/data","Waiting for background thread to exit"); + } + _info_c("dbg/data","Thread exited"); + } + + void data_logger::kill_instance() { + m_state = m_state = data_logger_state::state_dying; + m_obj.reset(); } - void data_logger::add_data(std::string filename, unsigned int data) - { - if (mFilesMap.find(filename) == mFilesMap.end()) - return; // TODO: exception - - - nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); + void data_logger::add_data(std::string filename, unsigned int data) { + std::lock_guard lock(mMutex); + if (m_state != data_logger_state::state_ready_to_use) { _info_c("dbg/data","Data logger is not ready, returning."); return; } + + if (mFilesMap.find(filename) == mFilesMap.end()) { // no such file/counter + _erro_c("dbg/data","Trying to use not opened data file filename="< lock(mSaveMutex); - if (mFilesMap[filename].mLimitFile) + if (mFilesMap[filename].mLimitFile) { // this holds a number (that is not additive) - e.g. the limit setting mFilesMap[filename].mDataToSave = data; - else - mFilesMap[filename].mDataToSave += data; + } else { + mFilesMap[filename].mDataToSave += data; // this holds a number that should be sum of all accumulated samples + } + } + + void data_logger::saveToFile() { + _dbg2_c("dbg/data","saving to files"); + std::lock_guard lock(mMutex); + if (m_state != data_logger_state::state_ready_to_use) { _info_c("dbg/data","Data logger is not ready, returning."); return; } + nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); + for (auto &element : mFilesMap) + { + element.second.save(); + if (!element.second.mLimitFile) element.second.mDataToSave = 0; + } } + + // the inner class: - double data_logger::fileData::get_current_time() - { + double data_logger::fileData::get_current_time() { using namespace boost::chrono; auto point = steady_clock::now(); auto time_from_epoh = point.time_since_epoch(); @@ -71,33 +127,28 @@ namespace net_utils return ms_f / 1000.; } - data_logger::fileData::fileData(std::string pFile) - { + data_logger::fileData::fileData(std::string pFile) { + _dbg3_c("dbg/data","opening data file named pFile="<close(); } - void data_logger::saveToFile() - { - std::lock_guard lock(mSaveMutex); - for (auto &element : mFilesMap) - { - element.second.save(); - if (!element.second.mLimitFile) - element.second.mDataToSave = 0; - } - } -std::atomic data_logger::m_save_graph(false); +data_logger_state data_logger::m_state(data_logger_state::state_before_init); ///< (static) state of the singleton object +std::atomic data_logger::m_save_graph(false); // (static) +std::atomic data_logger::m_thread_maybe_running(false); // (static) +std::once_flag data_logger::m_singleton; // (static) +std::unique_ptr data_logger::m_obj; // (static) } // namespace } // namespace + diff --git a/src/p2p/data_logger.hpp b/src/p2p/data_logger.hpp index 50beb847a..215912167 100644 --- a/src/p2p/data_logger.hpp +++ b/src/p2p/data_logger.hpp @@ -13,34 +13,60 @@ namespace epee { namespace net_utils { + +enum class data_logger_state { state_before_init, state_during_init, state_ready_to_use, state_dying }; +/*** +@note: use it ONLY via singleton! It will be spawned then, and will auto destruct on program exit. +@note: do call ::kill_instance() before exiting main, at end of main. But before make sure no one else (e.g. no other threads) will try to use this/singleton +@note: it is not allowed to use this class from code "runnig before or after main", e.g. from ctors of static objects, because of static-creation-order races +@note: on creation (e.g. from singleton), it spawns a thread that saves all data in background +*/ class data_logger { public: - static data_logger &get_instance(); - data_logger(const data_logger &ob) = delete; + static data_logger &get_instance(); ///< singleton + static void kill_instance(); ///< call this before ending main to allow more gracefull shutdown of the main singleton and it's background thread + ~data_logger(); ///< destr, will be called when singleton is killed when global m_obj dies. will kill theads etc + + private: + data_logger(); ///< constructor is private, use only via singleton get_instance + + public: + data_logger(const data_logger &ob) = delete; // use only one per program data_logger(data_logger &&ob) = delete; - void add_data(std::string filename, unsigned int data); - static std::atomic m_save_graph; + data_logger & operator=(const data_logger&) = delete; + data_logger & operator=(data_logger&&) = delete; + + void add_data(std::string filename, unsigned int data); ///< use this to append data here. Use it only the singleton. It locks itself. + + static std::atomic m_save_graph; ///< global setting flag, should we save all the data or not (can disable logging graphs data) + private: - data_logger(); - class fileData - { + static std::once_flag m_singleton; ///< to guarantee singleton creates the object exactly once + static data_logger_state m_state; ///< state of the singleton object + static std::atomic m_thread_maybe_running; ///< is the background thread (more or less) running, or is it fully finished + static std::unique_ptr m_obj; ///< the singleton object. Only use it via get_instance(). Can be killed by kill_instance() + + /*** + * one graph/file with data + */ + class fileData { public: - fileData(){} + fileData() = default; fileData(const fileData &ob) = delete; fileData(std::string pFile); std::shared_ptr mFile; - long int mDataToSave = 0; + long int mDataToSave = 0; ///< sum of the data (in current interval, will be counted from 0 on next interval) static double get_current_time(); void save(); std::string mPath; - bool mLimitFile = false; + bool mLimitFile = false; ///< this holds a number (that is not additive) - e.g. the limit setting }; - std::map mFilesMap; - std::mutex mSaveMutex; - void saveToFile(); + std::map mFilesMap; + std::mutex mMutex; + void saveToFile(); ///< write data to the target files. do not use this directly }; } // namespace diff --git a/src/p2p/network_throttle.cpp b/src/p2p/network_throttle.cpp index 3d5edcdcd..7bc89881d 100644 --- a/src/p2p/network_throttle.cpp +++ b/src/p2p/network_throttle.cpp @@ -78,7 +78,6 @@ int network_throttle_manager::xxx; // ================================================================================================ // methods: i_network_throttle & network_throttle_manager::get_global_throttle_in() { - std::call_once(m_once_get_global_throttle_in, [] { m_obj_get_global_throttle_in.reset(new network_throttle("in/all","<<< global-IN",10)); } ); return * m_obj_get_global_throttle_in; } -- cgit v1.2.3 From f79821ac7ebc269b18dd2edd8ac0cb022861ad11 Mon Sep 17 00:00:00 2001 From: rfree2monero Date: Tue, 24 Feb 2015 21:02:48 +0100 Subject: fix locking in count-peers thread (2) --- src/p2p/data_logger.cpp | 8 +++++++- src/p2p/net_node.h | 11 ++++++++++- src/p2p/net_node.inl | 19 ++++++++++--------- 3 files changed, 27 insertions(+), 11 deletions(-) (limited to 'src/p2p') diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index d62af133e..69e50141a 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -20,6 +20,12 @@ namespace net_utils m_state = data_logger_state::state_ready_to_use; } ); + + if (m_state != data_logger_state::state_ready_to_use) { + _erro ("trying to use not working data_logger"); + throw std::runtime_error("data_logger ctor state"); + } + return * m_obj; } @@ -82,7 +88,7 @@ namespace net_utils } void data_logger::kill_instance() { - m_state = m_state = data_logger_state::state_dying; + m_state = data_logger_state::state_dying; m_obj.reset(); } diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 5417ffa52..5b034ce25 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -89,6 +89,7 @@ namespace nodetool { m_current_number_of_out_peers = 0; m_save_graph = false; + is_closing = false; } static void init_options(boost::program_options::options_description& desc); @@ -209,6 +210,13 @@ namespace nodetool bool set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit); bool set_rate_limit(const boost::program_options::variables_map& vm, uint64_t limit); + void kill() { ///< will be called e.g. from deinit() + _info("Killing the net_node"); + is_closing = true; + mPeersLoggerThread->join(); // make sure the thread finishes + _info("Joined extra background net_node threads"); + } + //debug functions std::string print_connections_container(); @@ -247,7 +255,8 @@ namespace nodetool bool m_hide_my_port; bool m_no_igd; std::atomic m_save_graph; - + std::atomic is_closing; + std::unique_ptr mPeersLoggerThread; //critical_section m_connections_lock; //connections_indexed_container m_connections; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index a015763bf..afc6436f3 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -291,17 +291,17 @@ namespace nodetool std::vector> dns_results; dns_results.resize(m_seed_nodes_list.size()); - std::shared_ptr peersLoggerThread (new std::thread([&]() + // creating thread to log number of connections + mPeersLoggerThread.reset(new std::thread([&]() { - unsigned int number_of_peers; - while (1) - { + _note("Thread monitor number of peers - start"); + while (!is_closing) + { // main loop of thread //number_of_peers = m_net_server.get_config_object().get_connections_count(); - number_of_peers = 0; + unsigned int number_of_peers = 0; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - if(!cntxt.m_is_income) - ++number_of_peers; + if (!cntxt.m_is_income) ++number_of_peers; return true; }); // lambda @@ -309,10 +309,10 @@ namespace nodetool epee::net_utils::data_logger::get_instance().add_data("peers", number_of_peers); std::this_thread::sleep_for(std::chrono::seconds(1)); - } + } // main loop of thread + _note("Thread monitor number of peers - done"); })); // lambda - peersLoggerThread->detach(); std::list dns_threads; uint64_t result_index = 0; @@ -509,6 +509,7 @@ namespace nodetool template bool node_server::deinit() { + kill(); m_peerlist.deinit(); m_net_server.deinit_server(); -- cgit v1.2.3 From c511abf0058b8c1d020255faaad418b0ffd2eb26 Mon Sep 17 00:00:00 2001 From: rfree2monero Date: Wed, 1 Apr 2015 19:00:45 +0200 Subject: remerged; commands JSON. logging upgrade. doxygen --- src/p2p/data_logger.cpp | 19 ++++++++++-- src/p2p/data_logger.hpp | 1 + src/p2p/net_node.h | 19 +++++++----- src/p2p/net_node.inl | 60 +++++++++++++++++++++---------------- src/p2p/network_throttle-detail.cpp | 9 ++++-- 5 files changed, 69 insertions(+), 39 deletions(-) (limited to 'src/p2p') diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index 69e50141a..bbb9fba3e 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -43,6 +43,7 @@ namespace net_utils mFilesMap["sleep_up"] = data_logger::fileData("log/dr-monero/up_sleep_log.data"); mFilesMap["calc_time"] = data_logger::fileData("log/dr-monero/get_objects_calc_time.data"); mFilesMap["blockchain_processing_time"] = data_logger::fileData("log/dr-monero/blockchain_log.data"); + mFilesMap["block_processing"] = data_logger::fileData("log/dr-monero/block_proc.data"); mFilesMap["peers_limit"] = data_logger::fileData("log/dr-monero/peers_limit.info"); mFilesMap["download_limit"] = data_logger::fileData("log/dr-monero/limit_down.info"); @@ -109,6 +110,15 @@ namespace net_utils mFilesMap[filename].mDataToSave += data; // this holds a number that should be sum of all accumulated samples } } + + bool data_logger::is_dying() { + if (m_state == data_logger_state::state_dying) { + return true; + } + else { + return false; + } + } void data_logger::saveToFile() { _dbg2_c("dbg/data","saving to files"); @@ -125,10 +135,13 @@ namespace net_utils // the inner class: double data_logger::fileData::get_current_time() { - using namespace boost::chrono; - auto point = steady_clock::now(); + #if defined(__APPLE__) + auto point = std::chrono::system_clock::now(); + #else + auto point = std::chrono::steady_clock::now(); + #endif auto time_from_epoh = point.time_since_epoch(); - auto ms = duration_cast< milliseconds >( time_from_epoh ).count(); + auto ms = std::chrono::duration_cast< std::chrono::milliseconds >( time_from_epoh ).count(); double ms_f = ms; return ms_f / 1000.; } diff --git a/src/p2p/data_logger.hpp b/src/p2p/data_logger.hpp index 215912167..f38dacdcb 100644 --- a/src/p2p/data_logger.hpp +++ b/src/p2p/data_logger.hpp @@ -40,6 +40,7 @@ enum class data_logger_state { state_before_init, state_during_init, state_ready void add_data(std::string filename, unsigned int data); ///< use this to append data here. Use it only the singleton. It locks itself. static std::atomic m_save_graph; ///< global setting flag, should we save all the data or not (can disable logging graphs data) + static bool is_dying(); private: static std::once_flag m_singleton; ///< to guarantee singleton creates the object exactly once diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index f94fedae0..d956b37f0 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -80,13 +80,16 @@ namespace nodetool public: typedef t_payload_net_handler payload_net_handler; - node_server( - t_payload_net_handler& payload_handler - ) - : m_payload_handler(payload_handler) - , m_allow_local_ip(false) - , m_hide_my_port(false) - {} + node_server(t_payload_net_handler& payload_handler) + :m_payload_handler(payload_handler), + m_allow_local_ip(false), + m_no_igd(false), + m_hide_my_port(false) + { + m_current_number_of_out_peers = 0; + m_save_graph = false; + is_closing = false; + } static void init_options(boost::program_options::options_description& desc); @@ -233,12 +236,12 @@ namespace nodetool public: config m_config; // TODO was private, add getters? std::atomic m_current_number_of_out_peers; + void set_save_graph(bool save_graph) { m_save_graph = save_graph; epee::net_utils::connection_basic::set_save_graph(save_graph); } - private: std::string m_config_folder; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ef158d9a1..c7413ec15 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -46,6 +46,7 @@ #include "net/local_ip.h" #include "crypto/crypto.h" #include "storages/levin_abstract_invoke2.h" +#include "data_logger.hpp" #include "daemon/command_line_args.h" // We have to look for miniupnpc headers in different places, dependent on if its compiled or external @@ -93,6 +94,8 @@ namespace nodetool const command_line::arg_descriptor arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", -1}; const command_line::arg_descriptor arg_limit_rate_down = {"limit-rate-down", "set limit-rate-down [kB/s]", -1}; const command_line::arg_descriptor arg_limit_rate = {"limit-rate", "set limit-rate [kB/s]", 128}; + + const command_line::arg_descriptor arg_save_graph = {"save-graph", "Save data for dr monero", false}; } //----------------------------------------------------------------------------------- @@ -114,7 +117,9 @@ namespace nodetool command_line::add_arg(desc, arg_tos_flag); command_line::add_arg(desc, arg_limit_rate_up); command_line::add_arg(desc, arg_limit_rate_down); - command_line::add_arg(desc, arg_limit_rate); } + command_line::add_arg(desc, arg_limit_rate); + command_line::add_arg(desc, arg_save_graph); + } //----------------------------------------------------------------------------------- template bool node_server::init_config() @@ -193,6 +198,11 @@ namespace nodetool m_command_line_peers.push_back(pe); } } + + if(command_line::has_arg(vm, arg_save_graph)) + { + set_save_graph(true); + } if (command_line::has_arg(vm,arg_p2p_add_exclusive_node)) { @@ -294,29 +304,6 @@ namespace nodetool std::vector> dns_results; dns_results.resize(m_seed_nodes_list.size()); - - // creating thread to log number of connections - mPeersLoggerThread.reset(new std::thread([&]() - { - _note("Thread monitor number of peers - start"); - while (!is_closing) - { // main loop of thread - //number_of_peers = m_net_server.get_config_object().get_connections_count(); - unsigned int number_of_peers = 0; - m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) - { - if (!cntxt.m_is_income) ++number_of_peers; - return true; - }); // lambda - - m_current_number_of_out_peers = number_of_peers; - epee::net_utils::data_logger::get_instance().add_data("peers", number_of_peers); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - } // main loop of thread - _note("Thread monitor number of peers - done"); - })); // lambda - std::list dns_threads; uint64_t result_index = 0; @@ -483,6 +470,30 @@ namespace nodetool template bool node_server::run() { + // creating thread to log number of connections + mPeersLoggerThread.reset(new std::thread([&]() + { + _note("Thread monitor number of peers - start"); + while (!is_closing) + { // main loop of thread + //number_of_peers = m_net_server.get_config_object().get_connections_count(); + unsigned int number_of_peers = 0; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if (!cntxt.m_is_income) ++number_of_peers; + return true; + }); // lambda + + m_current_number_of_out_peers = number_of_peers; + if (epee::net_utils::data_logger::is_dying()) + break; + epee::net_utils::data_logger::get_instance().add_data("peers", number_of_peers); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + } // main loop of thread + _note("Thread monitor number of peers - done"); + })); // lambda + //here you can set worker threads count int thrds_count = 10; @@ -516,7 +527,6 @@ namespace nodetool kill(); m_peerlist.deinit(); m_net_server.deinit_server(); - return store_config(); } //----------------------------------------------------------------------------------- diff --git a/src/p2p/network_throttle-detail.cpp b/src/p2p/network_throttle-detail.cpp index 7426e6dc7..6fa27b62a 100644 --- a/src/p2p/network_throttle-detail.cpp +++ b/src/p2p/network_throttle-detail.cpp @@ -330,10 +330,13 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc } double network_throttle::get_time_seconds() const { - using namespace std::chrono; - auto point = steady_clock::now(); + #if defined(__APPLE__) + auto point = std::chrono::system_clock::now(); + #else + auto point = std::chrono::steady_clock::now(); + #endif auto time_from_epoh = point.time_since_epoch(); - auto ms = duration_cast< milliseconds >( time_from_epoh ).count(); + auto ms = std::chrono::duration_cast< std::chrono::milliseconds >( time_from_epoh ).count(); double ms_f = ms; return ms_f / 1000.; } -- cgit v1.2.3 From 618f20ce494ada0ac6ab087b33fc45e4968b3ac8 Mon Sep 17 00:00:00 2001 From: rfree2monero Date: Thu, 2 Apr 2015 16:27:19 +0200 Subject: Network 1.7; Quieted the debug a bit. Really really finall version of this changes I hope. --- src/p2p/data_logger.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/p2p') diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index bbb9fba3e..54fd33e82 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -30,7 +30,7 @@ namespace net_utils } data_logger::data_logger() { - _warn_c("dbg/data","Starting data logger (for graphs data)"); + _note_c("dbg/data","Starting data logger (for graphs data)"); if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw std::runtime_error("data_logger ctor state"); } std::lock_guard lock(mMutex); // lock @@ -55,19 +55,19 @@ namespace net_utils // do NOT modify mFilesMap below this point, since there is no locking for this used (yet) - _note_c("dbg/data","Creating thread for data logger"); // create timer thread + _info_c("dbg/data","Creating thread for data logger"); // create timer thread m_thread_maybe_running=true; std::shared_ptr logger_thread(new std::thread([&]() { - _note_c("dbg/data","Inside thread for data logger"); + _info_c("dbg/data","Inside thread for data logger"); while (m_state == data_logger_state::state_during_init) { // wait for creation to be done (in other thread, in singleton) before actually running std::this_thread::sleep_for(std::chrono::seconds(1)); } - _note_c("dbg/data","Inside thread for data logger - going into main loop"); + _info_c("dbg/data","Inside thread for data logger - going into main loop"); while (m_state == data_logger_state::state_ready_to_use) { // run as long as we are not closing the single object std::this_thread::sleep_for(std::chrono::seconds(1)); saveToFile(); // save all the pending data } - _note_c("dbg/data","Inside thread for data logger - done the main loop"); + _info_c("dbg/data","Inside thread for data logger - done the main loop"); m_thread_maybe_running=false; })); logger_thread->detach(); -- cgit v1.2.3