aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/connectivity_tool/conn_tool.cpp2
-rw-r--r--src/cryptonote_core/CMakeLists.txt1
-rw-r--r--src/cryptonote_core/blockchain_storage.cpp29
-rw-r--r--src/cryptonote_core/blockchain_storage.h1
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp47
-rw-r--r--src/cryptonote_core/cryptonote_core.h10
-rw-r--r--src/cryptonote_protocol/CMakeLists.txt46
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp176
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h39
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl275
-rw-r--r--src/daemon/daemon_commands_handler.h157
-rw-r--r--src/miner/simpleminer.cpp1
-rw-r--r--src/p2p/CMakeLists.txt46
-rw-r--r--src/p2p/connection_basic.cpp287
-rw-r--r--src/p2p/connection_basic.hpp132
-rw-r--r--src/p2p/data_logger.cpp160
-rw-r--r--src/p2p/data_logger.hpp75
-rw-r--r--src/p2p/net_node.h34
-rw-r--r--src/p2p/net_node.inl232
-rw-r--r--src/p2p/network_throttle-detail.cpp379
-rw-r--r--src/p2p/network_throttle-detail.hpp131
-rw-r--r--src/p2p/network_throttle.cpp120
-rw-r--r--src/p2p/network_throttle.hpp185
-rw-r--r--src/serialization/binary_archive.h4
-rw-r--r--src/simplewallet/CMakeLists.txt1
26 files changed, 2467 insertions, 105 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 294c6c0f6..efc9c02f6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -92,6 +92,8 @@ add_subdirectory(cryptonote_core)
add_subdirectory(mnemonics)
add_subdirectory(rpc)
add_subdirectory(wallet)
+add_subdirectory(p2p)
+add_subdirectory(cryptonote_protocol)
add_subdirectory(connectivity_tool)
add_subdirectory(miner)
diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp
index e658d2706..7506dba6f 100644
--- a/src/connectivity_tool/conn_tool.cpp
+++ b/src/connectivity_tool/conn_tool.cpp
@@ -49,6 +49,8 @@ namespace po = boost::program_options;
using namespace cryptonote;
using namespace nodetool;
+unsigned int epee::g_test_dbg_lock_sleep = 0;
+
namespace
{
const command_line::arg_descriptor<std::string, true> arg_ip = {"ip", "set ip"};
diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt
index 3abf93f3c..9eed11874 100644
--- a/src/cryptonote_core/CMakeLists.txt
+++ b/src/cryptonote_core/CMakeLists.txt
@@ -70,6 +70,7 @@ target_link_libraries(cryptonote_core
LINK_PUBLIC
common
crypto
+ otshell_utils
${Boost_DATE_TIME_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp
index 232a7c426..136d4f1d1 100644
--- a/src/cryptonote_core/blockchain_storage.cpp
+++ b/src/cryptonote_core/blockchain_storage.cpp
@@ -49,6 +49,8 @@
#include "crypto/hash.h"
#include "cryptonote_core/checkpoints_create.h"
//#include "serialization/json_archive.h"
+#include "../../contrib/otshell_utils/utils.hpp"
+#include "../../src/p2p/data_logger.hpp"
using namespace cryptonote;
@@ -1154,6 +1156,31 @@ uint64_t blockchain_storage::block_difficulty(size_t i)
return m_blocks[i].cumulative_difficulty - m_blocks[i-1].cumulative_difficulty;
}
//------------------------------------------------------------------
+double blockchain_storage::get_avg_block_size( size_t count)
+{
+ if (count > get_current_blockchain_height()) return 500;
+
+ double average = 0;
+ _dbg1_c("net/blksize", "HEIGHT: " << get_current_blockchain_height());
+ _dbg1_c("net/blksize", "BLOCK ID BY HEIGHT: " << get_block_id_by_height(get_current_blockchain_height()) );
+ _dbg1_c("net/blksize", "BLOCK TAIL ID: " << get_tail_id() );
+ std::vector<size_t> size_vector;
+
+ get_backward_blocks_sizes(get_current_blockchain_height() - count, size_vector, count);
+
+ std::vector<size_t>::iterator it;
+ it = size_vector.begin();
+ while (it != size_vector.end()) {
+ average += *it;
+ _dbg2_c("net/blksize", "VECTOR ELEMENT: " << (*it) );
+ it++;
+ }
+ average = average / count;
+ _dbg1_c("net/blksize", "VECTOR SIZE: " << size_vector.size() << " average=" << average);
+
+ return average;
+}
+//------------------------------------------------------------------
void blockchain_storage::print_blockchain(uint64_t start_index, uint64_t end_index)
{
std::stringstream ss;
@@ -1745,6 +1772,8 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
<< "), coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size
<< ", " << block_processing_time << "("<< target_calculating_time << "/" << longhash_calculating_time << ")ms");
+ epee::net_utils::data_logger::get_instance().add_data("blockchain_processing_time", block_processing_time);
+
bvc.m_added_to_main_chain = true;
/*if(!m_orphanes_reorganize_in_work)
review_orphaned_blocks_with_new_block_id(id, true);*/
diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h
index a74d492d7..505ed4574 100644
--- a/src/cryptonote_core/blockchain_storage.h
+++ b/src/cryptonote_core/blockchain_storage.h
@@ -134,6 +134,7 @@ namespace cryptonote
uint64_t get_current_comulative_blocksize_limit();
bool is_storing_blockchain(){return m_is_blockchain_storing;}
uint64_t block_difficulty(size_t i);
+ double get_avg_block_size( size_t count);
template<class t_ids_container, class t_blocks_container, class t_missed_container>
bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs)
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 11127290e..505feb563 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -216,12 +216,51 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::deinit()
{
- m_miner.stop();
- m_mempool.deinit();
- m_blockchain_storage.deinit();
+ m_miner.stop();
+ m_mempool.deinit();
+ if (!m_fast_exit)
+ {
+ m_blockchain_storage.deinit();
+ }
return true;
}
//-----------------------------------------------------------------------------------------------
+ void core::set_fast_exit()
+ {
+ m_fast_exit = true;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool core::get_fast_exit()
+ {
+ return m_fast_exit;
+ }
+ //-----------------------------------------------------------------------------------------------
+ void core::test_drop_download()
+ {
+ m_test_drop_download = false;
+ }
+ //-----------------------------------------------------------------------------------------------
+ void core::test_drop_download_height(uint64_t height)
+ {
+ m_test_drop_download_height = height;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool core::get_test_drop_download()
+ {
+ return m_test_drop_download;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool core::get_test_drop_download_height()
+ {
+ if (m_test_drop_download_height == 0)
+ return true;
+
+ if (get_blockchain_storage().get_current_blockchain_height() <= m_test_drop_download_height)
+ return true;
+
+ return false;
+ }
+ //-----------------------------------------------------------------------------------------------
bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block)
{
tvc = boost::value_initialized<tx_verification_context>();
@@ -624,4 +663,6 @@ namespace cryptonote
{
raise(SIGTERM);
}
+
+ std::atomic<bool> core::m_fast_exit(false);
}
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 1921ef14d..bb53ecb81 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -75,6 +75,12 @@ namespace cryptonote
bool init(const boost::program_options::variables_map& vm);
bool set_genesis_block(const block& b);
bool deinit();
+ static void set_fast_exit();
+ static bool get_fast_exit();
+ void test_drop_download();
+ void test_drop_download_height(uint64_t height);
+ bool get_test_drop_download();
+ bool get_test_drop_download_height();
uint64_t get_current_blockchain_height();
bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id);
bool get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks, std::list<transaction>& txs);
@@ -148,7 +154,9 @@ namespace cryptonote
bool on_update_blocktemplate_interval();
bool check_tx_inputs_keyimages_diff(const transaction& tx);
void graceful_exit();
-
+ static std::atomic<bool> m_fast_exit;
+ bool m_test_drop_download = true;
+ uint64_t m_test_drop_download_height = 0;
tx_memory_pool m_mempool;
blockchain_storage m_blockchain_storage;
diff --git a/src/cryptonote_protocol/CMakeLists.txt b/src/cryptonote_protocol/CMakeLists.txt
new file mode 100644
index 000000000..2ea5662a1
--- /dev/null
+++ b/src/cryptonote_protocol/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 CRYPTONOTE_PROTOCOL *)
+source_group(cryptonote_protocol FILES ${CRYPTONOTE_PROTOCOL})
+
+#add_library(p2p ${P2P})
+
+#bitmonero_private_headers(p2p ${CRYPTONOTE_PROTOCOL})
+bitmonero_add_library(cryptonote_protocol ${CRYPTONOTE_PROTOCOL})
+#target_link_libraries(p2p)
+# LINK_PRIVATE
+# ${Boost_CHRONO_LIBRARY}
+# ${Boost_REGEX_LIBRARY}
+# ${Boost_SYSTEM_LIBRARY}
+# ${Boost_THREAD_LIBRARY}
+# ${EXTRA_LIBRARIES})
+add_dependencies(cryptonote_protocol
+ version)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp
new file mode 100644
index 000000000..614ee8fab
--- /dev/null
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp
@@ -0,0 +1,176 @@
+/// @file
+/// @author rfree (current maintainer in monero.cc project)
+/// @brief This is the place to implement our handlers for protocol network actions, e.g. for ratelimit for download-requests
+
+// 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 <boost/asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <atomic>
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <memory>
+
+#include "syncobj.h"
+
+#include "../../contrib/epee/include/net/net_utils_base.h"
+#include "../../contrib/epee/include/misc_log_ex.h"
+#include <boost/lambda/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/uuid/random_generator.hpp>
+#include <boost/chrono.hpp>
+#include <boost/utility/value_init.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread.hpp>
+#include "misc_language.h"
+#include "pragma_comp_defs.h"
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+
+
+#include <boost/asio/basic_socket.hpp>
+#include <boost/asio/ip/unicast.hpp>
+
+#include "../../src/cryptonote_protocol/cryptonote_protocol_handler.h"
+#include "../../src/p2p/network_throttle.hpp"
+
+#include "../../contrib/otshell_utils/utils.hpp"
+using namespace nOT::nUtils;
+
+#include "../../../src/cryptonote_core/cryptonote_core.h" // e.g. for the send_stop_signal()
+
+// ################################################################################################
+// ################################################################################################
+// 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)
+// ################################################################################################
+// ################################################################################################
+
+namespace cryptonote {
+
+class cryptonote_protocol_handler_base_pimpl { // placeholer if needed
+ public:
+
+};
+
+} // namespace
+
+// ################################################################################################
+// ################################################################################################
+// ################################################################################################
+// ################################################################################################
+
+namespace cryptonote {
+
+double cryptonote_protocol_handler_base::estimate_one_block_size() noexcept { // for estimating size of blocks to downloa
+ const double size_min = 500; // XXX 500
+ //const int history_len = 20; // how many blocks to average over
+
+ double avg=0;
+ try {
+ avg = get_avg_block_size(/*history_len*/);
+ } catch (...) { }
+ avg = std::max( size_min , avg);
+ return avg;
+}
+
+cryptonote_protocol_handler_base::cryptonote_protocol_handler_base() {
+}
+
+cryptonote_protocol_handler_base::~cryptonote_protocol_handler_base() {
+}
+
+void cryptonote_protocol_handler_base::handler_request_blocks_history(std::list<crypto::hash>& ids) {
+ using namespace epee::net_utils;
+ LOG_PRINT_L0("### ~~~RRRR~~~~ ### sending request (type 2), limit = " << ids.size());
+ LOG_PRINT_RED("RATE LIMIT NOT IMPLEMENTED HERE YET (download at unlimited speed?)" , LOG_LEVEL_0);
+ _note_c("net/req2", "### ~~~RRRR~~~~ ### sending request (type 2), limit = " << ids.size());
+ // TODO
+}
+
+void cryptonote_protocol_handler_base::handler_response_blocks_now(size_t packet_size) { _scope_dbg1("");
+ using namespace epee::net_utils;
+ double delay=0; // will be calculated
+ _dbg1("Packet size: " << packet_size);
+ do
+ { // rate limiting
+ //XXX
+ /*if (::cryptonote::core::get_is_stopping()) {
+ _dbg1("We are stopping - so abort sleep");
+ return;
+ }*/
+ /*if (m_was_shutdown) {
+ _dbg2_c("net/netuse/sleep","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="<<packet_size); // XXX debug sleep
+ _dbg1_c("net/sleep/", "sleep in sleep_before_packet");
+ _dbg2("Sleep for " << ms);
+ boost::this_thread::sleep(boost::posix_time::milliseconds( ms ) ); // TODO randomize sleeps
+ }
+ } while(delay > 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<decltype(m_throttle_global_lock)> guard(m_throttle_global_lock); // *** critical ***
+ //m_throttle_global.m_out.handle_trafic_tcp( packet_size ); // increase counter - global
+ }
+}
+
+} // namespace
+
+
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index a3b79856e..571c36dc1 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -1,3 +1,7 @@
+/// @file
+/// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote)
+/// @brief This is the orginal cryptonote protocol network-events handler, modified by us
+
// Copyright (c) 2014-2015, The Monero Project
//
// All rights reserved.
@@ -41,15 +45,36 @@
#include "cryptonote_core/connection_context.h"
#include "cryptonote_core/cryptonote_stat_info.h"
#include "cryptonote_core/verification_context.h"
+// #include <netinet/in.h>
+#include <boost/circular_buffer.hpp>
PUSH_WARNINGS
DISABLE_VS_WARNINGS(4355)
+#define LOCALHOST_INT 2130706433
+
namespace cryptonote
{
+ class cryptonote_protocol_handler_base_pimpl;
+ class cryptonote_protocol_handler_base {
+ private:
+ std::unique_ptr<cryptonote_protocol_handler_base_pimpl> mI;
+
+ public:
+ cryptonote_protocol_handler_base();
+ virtual ~cryptonote_protocol_handler_base();
+ void handler_request_blocks_history(std::list<crypto::hash>& ids); // before asking for list of objects, we can change the list still
+ void handler_response_blocks_now(size_t packet_size);
+
+ virtual double get_avg_block_size() = 0;
+ virtual double estimate_one_block_size() noexcept; // for estimating size of blocks to download
+
+ virtual std::ofstream& get_logreq() const =0;
+ };
+
template<class t_core>
- class t_cryptonote_protocol_handler: public i_cryptonote_protocol
+ class t_cryptonote_protocol_handler: public i_cryptonote_protocol, cryptonote_protocol_handler_base
{
public:
typedef cryptonote_connection_context connection_context;
@@ -106,6 +131,12 @@ namespace cryptonote
nodetool::i_p2p_endpoint<connection_context>* m_p2p;
std::atomic<uint32_t> m_syncronized_connections_count;
std::atomic<bool> m_synchronized;
+ bool m_one_request = true;
+
+ // static std::ofstream m_logreq;
+ std::mutex m_buffer_mutex;
+ double get_avg_block_size();
+ boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
template<class t_parametr>
bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context)
@@ -113,6 +144,7 @@ namespace cryptonote
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(context) << "] post " << typeid(t_parametr).name() << " -->");
std::string blob;
epee::serialization::store_t_to_binary(arg, blob);
+ //handler_response_blocks_now(blob.size()); // XXX
return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context);
}
@@ -124,8 +156,11 @@ namespace cryptonote
epee::serialization::store_t_to_binary(arg, arg_buff);
return m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context);
}
+
+ virtual std::ofstream& get_logreq() const ;
};
-}
+
+} // namespace
#include "cryptonote_protocol_handler.inl"
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 2754eb73c..023dd03a6 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -1,3 +1,7 @@
+/// @file
+/// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote)
+/// @brief This is the orginal cryptonote protocol network-events handler, modified by us
+
// Copyright (c) 2014-2015, The Monero Project
//
// All rights reserved.
@@ -28,14 +32,28 @@
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+// (may contain code and/or modifications by other developers)
+// developer rfree: this code is caller of our new network code, and is modded; e.g. for rate limiting
+
#include <boost/interprocess/detail/atomic.hpp>
#include <list>
#include "cryptonote_core/cryptonote_format_utils.h"
#include "profile_tools.h"
+#include "../../contrib/otshell_utils/utils.hpp"
+#include "../../src/p2p/network_throttle-detail.hpp"
+#include "../../src/p2p/data_logger.hpp"
+using namespace nOT::nUtils;
+
namespace cryptonote
{
+
+// static
+// template<class t_core> std::ofstream t_cryptonote_protocol_handler<t_core>::m_logreq("logreq.txt"); // static
+
+
+
//-----------------------------------------------------------------------------------------------------------------------
template<class t_core>
t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
@@ -99,24 +117,66 @@ namespace cryptonote
void t_cryptonote_protocol_handler<t_core>::log_connections()
{
std::stringstream ss;
+ ss.precision(1);
+
+ double down_sum = 0.0;
+ double down_curr_sum = 0.0;
+ double up_sum = 0.0;
+ double up_curr_sum = 0.0;
- ss << std::setw(25) << std::left << "Remote Host"
+ ss << std::setw(30) << std::left << "Remote Host"
<< std::setw(20) << "Peer id"
- << std::setw(25) << "Recv/Sent (inactive,sec)"
+ << std::setw(30) << "Recv/Sent (inactive,sec)"
<< std::setw(25) << "State"
- << std::setw(20) << "Livetime(seconds)" << ENDL;
-
+ << std::setw(20) << "Livetime(sec)"
+ << std::setw(12) << "Down (kB/s)"
+ << std::setw(14) << "Down(now)"
+ << std::setw(10) << "Up (kB/s)"
+ << std::setw(13) << "Up(now)"
+ << ENDL;
+
+ uint32_t ip;
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
{
- ss << std::setw(25) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
- epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
+ bool local_ip = false;
+ ip = ntohl(cntxt.m_remote_ip);
+ // TODO: local ip in calss A, B
+ if (ip > 3232235520 && ip < 3232301055) // 192.168.x.x
+ local_ip = true;
+ auto connection_time = time(NULL) - cntxt.m_started;
+ ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
+ epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
<< std::setw(20) << std::hex << peer_id
- << std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
+ << std::setw(30) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
- << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started) << ENDL;
+ << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
+ << std::setw(12) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_recv_cnt / connection_time / 1024)
+ << std::setw(14) << std::fixed << cntxt.m_current_speed_down / 1024
+ << std::setw(10) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_send_cnt / connection_time / 1024)
+ << std::setw(13) << std::fixed << cntxt.m_current_speed_up / 1024
+ << (local_ip ? "[LAN]" : "")
+ << std::left << (ip == LOCALHOST_INT ? "[LOCALHOST]" : "") // 127.0.0.1
+ << ENDL;
+
+ if (connection_time > 1)
+ {
+ down_sum += (cntxt.m_recv_cnt / connection_time / 1024);
+ up_sum += (cntxt.m_send_cnt / connection_time / 1024);
+ }
+
+ down_curr_sum += (cntxt.m_current_speed_down / 1024);
+ up_curr_sum += (cntxt.m_current_speed_up / 1024);
+
return true;
});
- LOG_PRINT_L0("Connections: " << ENDL << ss.str());
+ ss << ENDL
+ << std::setw(125) << " "
+ << std::setw(12) << down_sum
+ << std::setw(14) << down_curr_sum
+ << std::setw(10) << up_sum
+ << std::setw(13) << up_curr_sum
+ << ENDL;
+ LOG_PRINT_L0("Connections: " << ENDL << ss.str());
}
//------------------------------------------------------------------------------------------------------------------------
// Returns a list of connection_info objects describing each open p2p connection
@@ -234,11 +294,11 @@ namespace cryptonote
block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.pause_mine();
- m_core.handle_incoming_block(arg.b.block, bvc);
+ m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
m_core.resume_mine();
if(bvc.m_verifivation_failed)
{
- LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
+ LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
m_p2p->drop_connection(context);
return 1;
}
@@ -304,13 +364,70 @@ namespace cryptonote
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size()
<< ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height << ", missed_ids.size()=" << rsp.missed_ids.size());
post_notify<NOTIFY_RESPONSE_GET_OBJECTS>(rsp, context);
+ //handler_response_blocks_now(sizeof(rsp)); // XXX
+ //handler_response_blocks_now(200);
return 1;
}
//------------------------------------------------------------------------------------------------------------------------
+
+
+ template<class t_core>
+ double t_cryptonote_protocol_handler<t_core>::get_avg_block_size() {
+ // return m_core.get_blockchain_storage().get_avg_block_size(count); // this does not count too well the actuall network-size of data we need to download
+
+ CRITICAL_REGION_LOCAL(m_buffer_mutex);
+ double avg = 0;
+ if (m_avg_buffer.size() == 0) {
+ _warn("m_avg_buffer.size() == 0");
+ return 500;
+ }
+
+ const bool dbg_poke_lock = 0; // debug: try to trigger an error by poking around with locks. TODO: configure option
+ long int dbg_repeat=0;
+ do {
+ for (auto element : m_avg_buffer) avg += element;
+ } while(dbg_poke_lock && (dbg_repeat++)<100000); // in debug/poke mode, repeat this calculation to trigger hidden locking error if there is one
+ return avg / m_avg_buffer.size();
+ }
+
+
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
LOG_PRINT_CCONTEXT_L2("NOTIFY_RESPONSE_GET_OBJECTS");
+
+ // calculate size of request - mainly for logging/debug
+ size_t size = 0;
+ for (auto element : arg.txs) size += element.size();
+
+ for (auto element : arg.blocks) {
+ size += element.block.size();
+ for (auto tx : element.txs)
+ size += tx.size();
+ }
+
+ for (auto element : arg.missed_ids)
+ size += sizeof(element.data);
+
+ size += sizeof(arg.current_blockchain_height);
+ {
+ CRITICAL_REGION_LOCAL(m_buffer_mutex);
+ m_avg_buffer.push_back(size);
+
+ const bool dbg_poke_lock = 0; // debug: try to trigger an error by poking around with locks. TODO: configure option
+ long int dbg_repeat=0;
+ do {
+ m_avg_buffer.push_back(666); // a test value
+ m_avg_buffer.erase_end(1);
+ } while(dbg_poke_lock && (dbg_repeat++)<100000); // in debug/poke mode, repeat this calculation to trigger hidden locking error if there is one
+ }
+ /*using namespace boost::chrono;
+ auto point = steady_clock::now();
+ auto time_from_epoh = point.time_since_epoch();
+ auto sec = duration_cast< seconds >( time_from_epoh ).count();*/
+
+ //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
+
if(context.m_last_response_height > arg.current_blockchain_height)
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
@@ -373,53 +490,66 @@ namespace cryptonote
return 1;
}
+
{
m_core.pause_mine();
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler(
boost::bind(&t_core::resume_mine, &m_core));
- BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
- {
- //process transactions
- TIME_MEASURE_START(transactions_process_time);
- BOOST_FOREACH(auto& tx_blob, block_entry.txs)
- {
- tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(tx_blob, tvc, true);
- if(tvc.m_verifivation_failed)
- {
- LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
- << epee::string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
- m_p2p->drop_connection(context);
- return 1;
- }
- }
- TIME_MEASURE_FINISH(transactions_process_time);
-
- //process block
- TIME_MEASURE_START(block_process_time);
- block_verification_context bvc = boost::value_initialized<block_verification_context>();
-
- m_core.handle_incoming_block(block_entry.block, bvc, false);
-
- if(bvc.m_verifivation_failed)
- {
- LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- return 1;
- }
- if(bvc.m_marked_as_orphaned)
- {
- LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
- m_p2p->drop_connection(context);
- return 1;
- }
-
- TIME_MEASURE_FINISH(block_process_time);
- LOG_PRINT_CCONTEXT_L2("Block process time: " << block_process_time + transactions_process_time << "(" << transactions_process_time << "/" << block_process_time << ")ms");
- }
+ LOG_PRINT_CCONTEXT_YELLOW( "Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size() , LOG_LEVEL_0);
+
+ if (m_core.get_test_drop_download() && m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
+
+
+ BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
+ {
+ // process transactions
+ TIME_MEASURE_START(transactions_process_time);
+ BOOST_FOREACH(auto& tx_blob, block_entry.txs)
+ {
+ tx_verification_context tvc = AUTO_VAL_INIT(tvc);
+ m_core.handle_incoming_tx(tx_blob, tvc, true);
+ if(tvc.m_verifivation_failed)
+ {
+ LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
+ << epee::string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ }
+ TIME_MEASURE_FINISH(transactions_process_time);
+
+ // process block
+
+ TIME_MEASURE_START(block_process_time);
+ block_verification_context bvc = boost::value_initialized<block_verification_context>();
+
+ m_core.handle_incoming_block(block_entry.block, bvc, false); // <--- process block
+
+ if(bvc.m_verifivation_failed)
+ {
+ LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ if(bvc.m_marked_as_orphaned)
+ {
+ LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ TIME_MEASURE_FINISH(block_process_time);
+ LOG_PRINT_CCONTEXT_L2("Block process time: " << block_process_time + transactions_process_time << "(" << transactions_process_time << "/" << block_process_time << ")ms");
+
+ epee::net_utils::data_logger::get_instance().add_data("calc_time", block_process_time + transactions_process_time);
+
+ } // each download block
+
+ } // if not DISCARD BLOCK
+
+
}
-
request_missing_objects(context, true);
return 1;
}
@@ -448,6 +578,15 @@ namespace cryptonote
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks)
{
+ //if (!m_one_request == false)
+ //return true;
+ m_one_request = false;
+ // save request size to log (dr monero)
+ /*using namespace boost::chrono;
+ auto point = steady_clock::now();
+ auto time_from_epoh = point.time_since_epoch();
+ auto sec = duration_cast< seconds >( time_from_epoh ).count();*/
+
if(context.m_needed_objects.size())
{
//we know objects that we need, request this objects
@@ -455,6 +594,8 @@ namespace cryptonote
size_t count = 0;
auto it = context.m_needed_objects.begin();
+ size_t count_limit = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT;
+ _note_c("net/req-calc" , "Setting count_limit: " << count_limit);
while(it != context.m_needed_objects.end() && count < BLOCKS_SYNCHRONIZING_DEFAULT_COUNT)
{
if( !(check_having_blocks && m_core.have_block(*it)))
@@ -465,14 +606,24 @@ namespace cryptonote
}
context.m_needed_objects.erase(it++);
}
- LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size() << ", txs.size()=" << req.txs.size());
+ LOG_PRINT_CCONTEXT_L0("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size() << ", txs.size()=" << req.txs.size()
+ << "requested blocks count=" << count << " / " << count_limit);
+ //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
+
post_notify<NOTIFY_REQUEST_GET_OBJECTS>(req, context);
}else if(context.m_last_response_height < context.m_remote_blockchain_height-1)
{//we have to fetch more objects ids, request blockchain entry
NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
m_core.get_short_chain_history(r.block_ids);
- LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
+ handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
+
+ //std::string blob; // for calculate size of request
+ //epee::serialization::store_t_to_binary(r, blob);
+ //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
+ LOG_PRINT_CCONTEXT_L0("r = " << 200);
+
+ LOG_PRINT_CCONTEXT_L0("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
}else
{
@@ -575,4 +726,18 @@ namespace cryptonote
{
return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context);
}
-}
+
+ /// @deprecated
+ template<class t_core> std::ofstream& t_cryptonote_protocol_handler<t_core>::get_logreq() const {
+ static std::ofstream * logreq=NULL;
+ if (!logreq) {
+ LOG_PRINT_RED("LOG OPENED",LOG_LEVEL_0);
+ logreq = new std::ofstream("logreq.txt"); // leak mem (singleton)
+ *logreq << "Opened log" << std::endl;
+ }
+ LOG_PRINT_YELLOW("LOG USED",LOG_LEVEL_0);
+ (*logreq) << "log used" << std::endl;
+ return *logreq;
+ }
+
+} // namespace
diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h
index 7416af9c5..7baca596d 100644
--- a/src/daemon/daemon_commands_handler.h
+++ b/src/daemon/daemon_commands_handler.h
@@ -12,6 +12,7 @@
#include "common/util.h"
#include "crypto/hash.h"
#include "version.h"
+#include "../../contrib/otshell_utils/utils.hpp"
//#include "net/net_helper.h"
//#include "../p2p/p2p_protocol_defs.h"
@@ -491,4 +492,160 @@ POP_WARNINGS
m_srv.get_payload_object().get_core().get_miner().stop();
return true;
}
+ //--------------------------------------------------------------------------------
+ bool out_peers_limit(const std::vector<std::string>& args) {
+ if(args.size()!=1) {
+ std::cout << "Usage: out_peers <number_of_peers>" << ENDL;
+ return true;
+ }
+
+ unsigned int limit;
+ try {
+ limit = std::stoi(args[0]);
+ }
+
+ catch(std::invalid_argument& ex) {
+ _erro("stoi exception");
+ return false;
+ }
+
+ if (m_srv.m_config.m_net_config.connections_count > limit)
+ {
+ m_srv.m_config.m_net_config.connections_count = limit;
+ epee::net_utils::data_logger::get_instance().add_data("peers_limit", m_srv.m_config.m_net_config.connections_count);
+ if (m_srv.m_current_number_of_out_peers > limit)
+ {
+ int count = m_srv.m_current_number_of_out_peers - limit;
+ m_srv.delete_connections(count);
+ }
+ }
+ else
+ {
+ m_srv.m_config.m_net_config.connections_count = limit;
+ epee::net_utils::data_logger::get_instance().add_data("peers_limit", m_srv.m_config.m_net_config.connections_count);
+ }
+
+ return true;
+ }
+ //--------------------------------------------------------------------------------
+ bool limit_up(const std::vector<std::string>& args)
+ {
+ if(args.size()!=1) {
+ std::cout << "Usage: limit_up <speed>" << ENDL;
+ return false;
+ }
+
+ int limit;
+ try {
+ limit = std::stoi(args[0]);
+ }
+ catch(std::invalid_argument& ex) {
+ return false;
+ }
+
+ if (limit==-1) {
+ limit=128;
+ //this->islimitup=false;
+ }
+
+ limit *= 1024;
+
+
+ //nodetool::epee::net_utils::connection<epee::levin::async_protocol_handler<nodetool::p2p_connection_context> >::set_rate_up_limit( limit );
+ epee::net_utils::connection_basic::set_rate_up_limit( limit );
+ std::cout << "Set limit-up to " << limit/1024 << " kB/s" << std::endl;
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------------------
+ bool limit_down(const std::vector<std::string>& args)
+ {
+
+ if(args.size()!=1) {
+ std::cout << "Usage: limit_down <speed>" << ENDL;
+ return true;
+ }
+
+ int limit;
+ try {
+ limit = std::stoi(args[0]);
+ }
+
+ catch(std::invalid_argument& ex) {
+ return false;
+ }
+
+ if (limit==-1) {
+ limit=128;
+ //this->islimitup=false;
+ }
+
+ limit *= 1024;
+
+
+ //nodetool::epee::net_utils::connection<epee::levin::async_protocol_handler<nodetool::p2p_connection_context> >::set_rate_up_limit( limit );
+ epee::net_utils::connection_basic::set_rate_down_limit( limit );
+ std::cout << "Set limit-down to " << limit/1024 << " kB/s" << std::endl;
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------------------
+ bool limit(const std::vector<std::string>& args)
+ {
+ if(args.size()!=1) {
+ std::cout << "Usage: limit_down <speed>" << ENDL;
+ return true;
+ }
+
+ int limit;
+ try {
+ limit = std::stoi(args[0]);
+ }
+ catch(std::invalid_argument& ex) {
+ return false;
+ }
+
+ if (limit==-1) {
+ limit=128;
+ //this->islimitup=false;
+ }
+
+ limit *= 1024;
+
+
+ //nodetool::epee::net_utils::connection<epee::levin::async_protocol_handler<nodetool::p2p_connection_context> >::set_rate_up_limit( limit );
+ epee::net_utils::connection_basic::set_rate_down_limit( limit );
+ epee::net_utils::connection_basic::set_rate_up_limit( limit );
+ std::cout << "Set limit-down to " << limit/1024 << " kB/s" << std::endl;
+ std::cout << "Set limit-up to " << limit/1024 << " kB/s" << std::endl;
+
+ return true;
+ }
+ //--------------------------------------------------------------------------------
+ bool fast_exit(const std::vector<std::string>& args)
+ {
+ m_srv.get_payload_object().get_core().set_fast_exit();
+ m_srv.send_stop_signal();
+ return true;
+ }
+ //--------------------------------------------------------------------------------
+ bool test_drop_download(const std::vector<std::string>& args)
+ {
+ m_srv.get_payload_object().get_core().test_drop_download();
+ return true;
+ }
+ //--------------------------------------------------------------------------------
+ bool start_save_graph(const std::vector<std::string>& args)
+ {
+ m_srv.set_save_graph(true);
+ return true;
+ }
+ //--------------------------------------------------------------------------------
+ bool stop_save_graph(const std::vector<std::string>& args)
+ {
+ m_srv.set_save_graph(false);
+ return true;
+ }
};
diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp
index fafe6b3f3..6212f88f5 100644
--- a/src/miner/simpleminer.cpp
+++ b/src/miner/simpleminer.cpp
@@ -41,6 +41,7 @@
using namespace epee;
namespace po = boost::program_options;
+unsigned int epee::g_test_dbg_lock_sleep = 0;
int main(int argc, char** argv)
{
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..ed15c0986
--- /dev/null
+++ b/src/p2p/connection_basic.cpp
@@ -0,0 +1,287 @@
+/// @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 <boost/asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <atomic>
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <memory>
+
+#include "syncobj.h"
+
+#include "../../contrib/epee/include/net/net_utils_base.h"
+#include "../../contrib/epee/include/misc_log_ex.h"
+#include <boost/lambda/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/uuid/random_generator.hpp>
+#include <boost/chrono.hpp>
+#include <boost/utility/value_init.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/filesystem.hpp>
+#include "misc_language.h"
+#include "pragma_comp_defs.h"
+#include <fstream>
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+#include <mutex>
+
+#include <boost/asio/basic_socket.hpp>
+#include <boost/asio/ip/unicast.hpp>
+#include "../../contrib/epee/include/net/abstract_tcp_server2.h"
+
+#include "../../contrib/otshell_utils/utils.hpp"
+#include "data_logger.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<long> &ref_sock_count, std::atomic<long> &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
+
+ string remote_addr_str = "?";
+ try { remote_addr_str = socket_.remote_endpoint().address().to_string(); } catch(...){} ;
+
+ _note("Spawned connection p2p#"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_ref_sock_count);
+ //boost::filesystem::create_directories("log/dr-monero/net/");
+}
+
+connection_basic::~connection_basic() {
+ string remote_addr_str = "?";
+ try { remote_addr_str = socket_.remote_endpoint().address().to_string(); } catch(...){} ;
+ _note("Destructing connection p2p#"<<mI->m_peer_number << " to " << remote_addr_str);
+}
+
+void connection_basic::set_rate_up_limit(uint64_t limit) {
+
+ // TODO remove __SCALING_FACTOR...
+ const double SCALING_FACTOR = 2.1; // 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);
+ }
+ save_limit_to_file(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::save_limit_to_file(int limit) {
+ // saving limit to file
+ if (!epee::net_utils::data_logger::m_save_graph)
+ return;
+
+ {
+ CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out );
+ 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 );
+ epee::net_utils::data_logger::get_instance().add_data("download_limit", network_throttle_manager::get_global_throttle_in().get_terget_speed() / 1024);
+ }
+}
+
+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
+ 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;
+ if (delay > 0) {
+ long int ms = (long int)(delay * 1000);
+ _info_c("net/sleep", "Sleeping in " << __FUNCTION__ << " for " << ms << " ms before packet_size="<<packet_size); // debug sleep
+ _dbg1("sleep in sleep_before_packet");
+ epee::net_utils::data_logger::get_instance().add_data("sleep_up", ms);
+ boost::this_thread::sleep(boost::posix_time::milliseconds( ms ) );
+ }
+ } while(delay > 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_exact( packet_size * 700); // 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_write(const void* ptr , size_t cb ) {
+ sleep_before_packet(cb,1,-1);
+ _info_c("net/out/size", "handler_write (direct) - before ASIO write, for packet="<<cb<<" B (after sleep)");
+ set_start_time();
+}
+
+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="<<q_len<<") - before ASIO write, for packet="<<cb<<" B (after sleep)");
+
+ set_start_time();
+}
+
+void connection_basic::logger_handle_net_read(size_t size) { // network data read
+ size /= 1024;
+ epee::net_utils::data_logger::get_instance().add_data("download", size);
+}
+
+void connection_basic::logger_handle_net_write(size_t size) {
+ size /= 1024;
+ epee::net_utils::data_logger::get_instance().add_data("upload", 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;
+}
+
+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
new file mode 100644
index 000000000..e9fdc3add
--- /dev/null
+++ b/src/p2p/connection_basic.hpp
@@ -0,0 +1,132 @@
+/// @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 <boost/asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <atomic>
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <memory>
+
+#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<bool> m_was_shutdown;
+ critical_section m_send_que_lock;
+ std::list<std::string> 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<long> &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<long> &ref_sock_count, std::atomic<long> &sock_number);
+
+ virtual ~connection_basic();
+
+ // various handlers to be called from connection class:
+ void do_send_handler_write(const void * ptr , size_t cb);
+ 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 logger_handle_net_write(size_t size); // network data written
+ void logger_handle_net_read(size_t size); // network data read
+
+ 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);
+
+ // 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);
+
+ static void set_save_graph(bool save_graph);
+};
+
+} // nameserver
+} // nameserver
+
+#endif
+
+
diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp
new file mode 100644
index 000000000..69e50141a
--- /dev/null
+++ b/src/p2p/data_logger.cpp
@@ -0,0 +1,160 @@
+#include "data_logger.hpp"
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/filesystem.hpp>
+#include <chrono>
+#include "../../contrib/otshell_utils/utils.hpp"
+
+namespace epee
+{
+namespace net_utils
+{
+ 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;
+ }
+ );
+
+ 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;
+ }
+
+ 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<std::mutex> 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");
+ 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;
+
+ // 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<std::thread> 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<std::mutex> 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 = data_logger_state::state_dying;
+ m_obj.reset();
+ }
+
+ void data_logger::add_data(std::string filename, unsigned int data) {
+ std::lock_guard<std::mutex> 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="<<filename);
+ _erro_c("dbg/data","Disabling saving of graphs due to error");
+ m_save_graph=false; // <--- disabling saving graphs
+ return;
+ }
+
+ 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; // 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<std::mutex> 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() {
+ 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) {
+ _dbg3_c("dbg/data","opening data file named pFile="<<pFile<<" for this="<<this);
+ mFile = std::make_shared<std::ofstream> (pFile);
+ _dbg1_c("dbg/data","opened data file named pFile="<<pFile<<" in mFile="<<mFile<<" for this="<<this);
+ mPath = pFile;
+ }
+
+ void data_logger::fileData::save() {
+ if (!data_logger::m_save_graph) return; // <--- disabled
+ _dbg2_c("dbg/data","saving to the file now, mFile="<<mFile);
+ mFile->open(mPath, std::ios::app);
+ *mFile << static_cast<int>(get_current_time()) << " " << mDataToSave << std::endl;
+ mFile->close();
+ }
+
+
+data_logger_state data_logger::m_state(data_logger_state::state_before_init); ///< (static) state of the singleton object
+std::atomic<bool> data_logger::m_save_graph(false); // (static)
+std::atomic<bool> data_logger::m_thread_maybe_running(false); // (static)
+std::once_flag data_logger::m_singleton; // (static)
+std::unique_ptr<data_logger> data_logger::m_obj; // (static)
+
+} // namespace
+} // namespace
+
diff --git a/src/p2p/data_logger.hpp b/src/p2p/data_logger.hpp
new file mode 100644
index 000000000..215912167
--- /dev/null
+++ b/src/p2p/data_logger.hpp
@@ -0,0 +1,75 @@
+#ifndef INCLUDED_p2p_data_logger_hpp
+#define INCLUDED_p2p_data_logger_hpp
+
+#include <string>
+#include <map>
+#include <fstream>
+#include <memory>
+#include <thread>
+#include <mutex>
+#include <atomic>
+
+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(); ///< 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;
+ 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<bool> m_save_graph; ///< global setting flag, should we save all the data or not (can disable logging graphs data)
+
+ private:
+ 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<bool> m_thread_maybe_running; ///< is the background thread (more or less) running, or is it fully finished
+ static std::unique_ptr<data_logger> 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() = default;
+ fileData(const fileData &ob) = delete;
+ fileData(std::string pFile);
+
+ std::shared_ptr<std::ofstream> mFile;
+ 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; ///< this holds a number (that is not additive) - e.g. the limit setting
+ };
+
+ std::map<std::string, fileData> mFilesMap;
+ std::mutex mMutex;
+ void saveToFile(); ///< write data to the target files. do not use this directly
+ };
+
+} // namespace
+} // namespace
+
+#endif
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index a778cd9e8..f94fedae0 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -109,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<std::string> m_seed_nodes_list =
{ "seeds.moneroseeds.se"
@@ -116,6 +117,9 @@ namespace nodetool
, "seeds.moneroseeds.ch"
, "seeds.moneroseeds.li"
};
+
+ bool islimitup=false;
+ bool islimitdown=false;
typedef COMMAND_REQUEST_STAT_INFO_T<typename t_payload_net_handler::stat_info> COMMAND_REQUEST_STAT_INFO;
@@ -195,6 +199,20 @@ namespace nodetool
template <class Container>
bool parse_peers_and_add_to_container(const boost::program_options::variables_map& vm, const command_line::arg_descriptor<std::vector<std::string> > & 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);
+
+ 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();
@@ -212,7 +230,16 @@ namespace nodetool
END_KV_SERIALIZE_MAP()
};
- config m_config;
+ public:
+ config m_config; // TODO was private, add getters?
+ std::atomic<unsigned int> 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;
bool m_have_address;
@@ -222,7 +249,10 @@ namespace nodetool
uint32_t m_ip_address;
bool m_allow_local_ip;
bool m_hide_my_port;
-
+ bool m_no_igd;
+ std::atomic<bool> m_save_graph;
+ std::atomic<bool> is_closing;
+ std::unique_ptr<std::thread> 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 6ed861e10..ef158d9a1 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -85,6 +85,14 @@ namespace nodetool
" If this option is given the options add-priority-node and seed-node are ignored"};
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
+
+ const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
+ const command_line::arg_descriptor<int64_t> arg_out_peers = {"out-peers", "set max limit of out peers", -1};
+ const command_line::arg_descriptor<int> arg_tos_flag = {"tos-flag", "set TOS flag", -1};
+
+ const command_line::arg_descriptor<int64_t> arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", -1};
+ const command_line::arg_descriptor<int64_t> arg_limit_rate_down = {"limit-rate-down", "set limit-rate-down [kB/s]", -1};
+ const command_line::arg_descriptor<uint64_t> arg_limit_rate = {"limit-rate", "set limit-rate [kB/s]", 128};
}
//-----------------------------------------------------------------------------------
@@ -100,7 +108,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<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::init_config()
@@ -121,7 +135,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;
@@ -166,6 +179,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))
{
@@ -185,11 +199,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))
@@ -198,6 +214,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;
}
@@ -263,6 +294,29 @@ namespace nodetool
std::vector<std::vector<std::string>> 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<boost::thread*> dns_threads;
uint64_t result_index = 0;
@@ -380,42 +434,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;
}
//-----------------------------------------------------------------------------------
@@ -458,8 +513,10 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::deinit()
{
+ kill();
m_peerlist.deinit();
m_net_server.deinit_server();
+
return store_config();
}
//-----------------------------------------------------------------------------------
@@ -670,6 +727,16 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white)
{
+ if (m_current_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit
+ {
+ return false;
+ }
+ 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_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) << ":"
<< 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")
@@ -757,16 +824,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<std::string>(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<std::string>(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;
}
@@ -1305,4 +1378,83 @@ namespace nodetool
return true;
}
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::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;
+ 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;
+ return true;
+ }
+
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::delete_connections(size_t count)
+ {
+ m_net_server.get_config_object().del_out_connections(count);
+ }
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::set_tos_flag(const boost::program_options::variables_map& vm, int flag)
+ {
+ if(flag==-1){
+ return true;
+ }
+ epee::net_utils::connection<epee::levin::async_protocol_handler<p2p_connection_context> >::set_tos_flag(flag);
+ _dbg1("Set ToS flag " << flag);
+ return true;
+ }
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::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<epee::levin::async_protocol_handler<p2p_connection_context> >::set_rate_up_limit( limit );
+ LOG_PRINT_L0("Set limit-up to " << limit/1024 << " kB/s");
+ return true;
+ }
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::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<epee::levin::async_protocol_handler<p2p_connection_context> >::set_rate_down_limit( limit );
+ LOG_PRINT_L0("Set limit-down to " << limit/1024 << " kB/s");
+ return true;
+ }
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::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<epee::levin::async_protocol_handler<p2p_connection_context> >::set_rate_up_limit( limit );
+ epee::net_utils::connection<epee::levin::async_protocol_handler<p2p_connection_context> >::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<epee::levin::async_protocol_handler<p2p_connection_context> >::set_rate_down_limit( limit );
+ }
+ else if(this->islimitdown==true && this->islimitup==false ) {
+ epee::net_utils::connection<epee::levin::async_protocol_handler<p2p_connection_context> >::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..7426e6dc7
--- /dev/null
+++ b/src/p2p/network_throttle-detail.cpp
@@ -0,0 +1,379 @@
+/// @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 <boost/asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <atomic>
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <memory>
+
+#include "syncobj.h"
+
+#include "../../contrib/epee/include/net/net_utils_base.h"
+#include "../../contrib/epee/include/misc_log_ex.h"
+#include <boost/lambda/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/uuid/random_generator.hpp>
+#include <boost/chrono.hpp>
+#include <boost/utility/value_init.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread.hpp>
+#include "misc_language.h"
+#include "pragma_comp_defs.h"
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+
+
+
+#include <boost/asio/basic_socket.hpp>
+#include <boost/asio/ip/unicast.hpp>
+#include "../../contrib/epee/include/net/abstract_tcp_server2.h"
+
+// TODO:
+#include "../../src/p2p/network_throttle-detail.hpp"
+
+#include "../../contrib/otshell_utils/utils.hpp"
+#include "data_logger.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
+}
+
+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 * 1024;
+ _note_c("net/"+m_nameshort, "Setting LIMIT: " << target << " kbps");
+ set_real_target_speed(target);
+}
+
+void network_throttle::set_real_target_speed( network_speed_kbps real_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()
+{
+ 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))
+ {
+ _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();
+ 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();
+
+ _dbg2_c( "net/" + m_nameshort , "Throttle " << m_name << ": packet of ~"<<packet_size<<"b " << " (from "<<orginal_size<<" b)"
+ << " Speed AVG=" << std::setw(4) << ((long int)(cts .average/1024)) <<"[w="<<cts .window<<"]"
+ << " " << std::setw(4) << ((long int)(cts2.average/1024)) <<"[w="<<cts2.window<<"]"
+ <<" / " << " Limit="<< ((long int)(m_target_speed/1024)) <<" KiB/sec "
+ << " " << history_str
+ );
+}
+
+void network_throttle::handle_trafic_tcp(size_t packet_size)
+{
+ size_t all_size = packet_size + m_network_add_cost;
+ all_size = std::max( m_network_minimal_segment , all_size);
+ _handle_trafic_exact( all_size , packet_size );
+}
+
+network_time_seconds network_throttle::get_sleep_time_after_tick(size_t packet_size) {
+ tick();
+ return get_sleep_time(packet_size);
+}
+
+void network_throttle::logger_handle_net(const std::string &filename, double time, size_t size) {
+ if (! epee::net_utils::data_logger::m_save_graph)
+ return;
+ std::mutex mutex;
+ mutex.lock(); {
+ std::fstream file;
+ file.open(filename.c_str(), std::ios::app | std::ios::out );
+ file.precision(6);
+ if(!file.is_open())
+ _warn("Can't open file " << filename);
+ file << static_cast<int>(time) << " " << static_cast<double>(size/1024) << "\n";
+ file.close();
+ } mutex.unlock();
+}
+
+// fine tune this to decide about sending speed:
+network_time_seconds network_throttle::get_sleep_time(size_t packet_size) const
+{
+ double D2=0;
+ calculate_times_struct cts = { 0, 0, 0, 0};
+ calculate_times(packet_size, cts, true, m_window_size); D2=cts.delay;
+ return D2;
+}
+
+// MAIN LOGIC:
+void network_throttle::calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const
+{
+ const double the_window_size = std::max( (double)m_window_size ,
+ ((force_window>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)
+
+ 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)
+
+ 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" ,
+ (cts.delay > 0 ? "SLEEP" : "")
+ << "dbg " << m_name << ": "
+ << "speed is A=" << std::setw(8) <<cts.average<<" vs "
+ << "Max=" << std::setw(8) <<M<<" "
+ << " so sleep: "
+ << "D=" << std::setw(8) <<cts.delay<<" sec "
+ << "E="<< std::setw(8) << E << " (Enow="<<std::setw(8)<<Enow<<") "
+ << "M=" << std::setw(8) << M <<" W="<< std::setw(8) << cts.window << " "
+ << "R=" << std::setw(8) << cts.recomendetDataSize << " Wgood" << std::setw(8) << Wgood << " "
+ << "History: " << std::setw(8) << history_str << " "
+ << "m_last_sample_time=" << std::setw(8) << m_last_sample_time
+ );
+
+ }
+}
+
+double network_throttle::get_time_seconds() const {
+ 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;
+ return ms_f / 1000.;
+}
+
+size_t network_throttle::get_recommended_size_of_planned_transport_window(double force_window) const {
+ calculate_times_struct cts = { 0, 0, 0, 0};
+ network_throttle::calculate_times(0, cts, true, force_window);
+ cts.recomendetDataSize += m_network_add_cost;
+ if (cts.recomendetDataSize<0) cts.recomendetDataSize=0;
+ if (cts.recomendetDataSize>m_network_max_segment) cts.recomendetDataSize=m_network_max_segment;
+ size_t RI = (long int)cts.recomendetDataSize;
+ return RI;
+}
+
+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( 5 );
+ auto RM = std::min(R1, std::min(R2,R3));
+
+ 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
new file mode 100644
index 000000000..063dac850
--- /dev/null
+++ b/src/p2p/network_throttle-detail.hpp
@@ -0,0 +1,131 @@
+/// @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: throttle details, implementing rate limiting */
+
+
+#ifndef INCLUDED_src_p2p_throttle_detail_hpp
+#define INCLUDED_src_p2p_throttle_detail_hpp
+
+#include "../../src/p2p/network_throttle.hpp"
+
+namespace epee
+{
+namespace net_utils
+{
+
+
+class network_throttle : public i_network_throttle {
+ private:
+ struct packet_info {
+ size_t m_size; // octets sent. Summary for given small-window (e.g. for all packaged in 1 second)
+ packet_info();
+ };
+
+
+ network_speed_kbps m_target_speed;
+ 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
+
+ const size_t m_window_size; // the number of samples to average over
+ network_time_seconds m_slot_size; // the size of one slot. TODO: now hardcoded for 1 second e.g. in time_to_slot()
+ // TODO for big window size, for performance better the substract on change of m_last_sample_time instead of recalculating average of eg >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_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 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
+
+ // 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 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
+ 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..7bc89881d
--- /dev/null
+++ b/src/p2p/network_throttle.cpp
@@ -0,0 +1,120 @@
+/**
+@file
+@author rfree (current maintainer in monero.cc project)
+@brief interface for throttling of connection (count and rate-limit speed etc)
+@details <PRE>
+
+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
+
+</PRE>
+
+@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<i_network_throttle> 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<i_network_throttle> 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<i_network_throttle> 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..add4daa86
--- /dev/null
+++ b/src/p2p/network_throttle.hpp
@@ -0,0 +1,185 @@
+/// @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 <boost/asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <atomic>
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/thread/thread.hpp>
+
+#include "syncobj.h"
+
+#include "../../contrib/epee/include/net/net_utils_base.h"
+#include "../../contrib/epee/include/misc_log_ex.h"
+#include <boost/lambda/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/uuid/random_generator.hpp>
+#include <boost/chrono.hpp>
+#include <boost/utility/value_init.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread.hpp>
+#include "misc_language.h"
+#include "pragma_comp_defs.h"
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+
+#include <memory>
+#include <mutex>
+#include <fstream>
+
+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<i_network_throttle> m_obj_get_global_throttle_in;
+ static std::unique_ptr<i_network_throttle> m_obj_get_global_throttle_inreq;
+ static std::unique_ptr<i_network_throttle> 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_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 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 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
+
+
+
diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h
index 6e00ad664..5cd4988e4 100644
--- a/src/serialization/binary_archive.h
+++ b/src/serialization/binary_archive.h
@@ -42,8 +42,8 @@
#include "warnings.h"
/* I have no clue what these lines means */
-PUSH_WARNINGS;
-DISABLE_VS_WARNINGS(4244);
+PUSH_WARNINGS
+DISABLE_VS_WARNINGS(4244)
//TODO: fix size_t warning in x32 platform
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt
index 84acbf295..a33ed0f32 100644
--- a/src/simplewallet/CMakeLists.txt
+++ b/src/simplewallet/CMakeLists.txt
@@ -50,6 +50,7 @@ target_link_libraries(simplewallet
crypto
common
mnemonics
+ p2p
${UNBOUND_LIBRARY}
${UPNP_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}