/// @file /// @author rfree (current maintainer in monero.cc project) /// @brief base for connection, contains e.g. the ratelimit hooks // Copyright (c) 2014-2016, The Monero Project // // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* rfree: implementation for the non-template base, can be used by connection<> template class in abstract_tcp_server2 file */ #include "connection_basic.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "syncobj.h" #include "../../contrib/epee/include/net/net_utils_base.h" #include "../../contrib/epee/include/misc_log_ex.h" #include #include #include #include #include #include #include #include #include #include #include "misc_language.h" #include "pragma_comp_defs.h" #include #include #include #include #include #include #include #include "../../contrib/epee/include/net/abstract_tcp_server2.h" #include "../../contrib/otshell_utils/utils.hpp" #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 { std::string to_string(t_connection_type type) { if (type == e_connection_type_NET) return std::string("NET"); else if (type == e_connection_type_RPC) return std::string("RPC"); else if (type == e_connection_type_P2P) return std::string("P2P"); return std::string("UNKNOWN"); } /* ============================================================================ */ class connection_basic_pimpl { public: connection_basic_pimpl(const std::string &name); static int m_default_tos; network_throttle_bw m_throttle; // per-perr critical_section m_throttle_lock; int m_peer_number; // e.g. for debug/stats }; } // namespace } // namespace // ################################################################################################ // The implementation part // ################################################################################################ namespace epee { namespace net_utils { // ================================================================================================ // connection_basic_pimpl // ================================================================================================ connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_throttle(name) { } // ================================================================================================ // connection_basic // ================================================================================================ // static variables: int connection_basic_pimpl::m_default_tos; // methods: connection_basic::connection_basic(boost::asio::io_service& io_service, std::atomic &ref_sock_count, std::atomic &sock_number) : mI( new connection_basic_pimpl("peer") ), strand_(io_service), socket_(io_service), m_want_close_connection(false), m_was_shutdown(false), m_ref_sock_count(ref_sock_count) { ++ref_sock_count; // increase the global counter mI->m_peer_number = sock_number.fetch_add(1); // use, and increase the generated number string remote_addr_str = "?"; try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ; _note("Spawned connection p2p#"<m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_ref_sock_count); //boost::filesystem::create_directories("log/dr-monero/net/"); } connection_basic::~connection_basic() { string remote_addr_str = "?"; m_ref_sock_count--; try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ; _note("Destructing connection p2p#"<m_peer_number << " to " << remote_addr_str); } void connection_basic::set_rate_up_limit(uint64_t limit) { // 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); } uint64_t connection_basic::get_rate_up_limit() { uint64_t limit; { CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); limit = network_throttle_manager::get_global_throttle_out().get_target_speed(); } return limit; } uint64_t connection_basic::get_rate_down_limit() { uint64_t limit; { CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_in ); limit = network_throttle_manager::get_global_throttle_in().get_target_speed(); } return 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_target_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_target_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="< 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="<