aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/util.cpp36
-rw-r--r--src/common/util.h2
-rw-r--r--src/daemon/command_parser_executor.cpp7
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp5
-rw-r--r--src/daemon/rpc_command_executor.cpp60
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/rpc/core_rpc_server.cpp17
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h33
10 files changed, 166 insertions, 0 deletions
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 80b8a9e81..728efc294 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -80,6 +80,7 @@ using namespace epee;
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
+#include <boost/format.hpp>
#include <openssl/sha.h>
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -1063,4 +1064,39 @@ std::string get_nix_version_display_string()
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
return std::string(buffer);
}
+
+ std::string get_human_readable_bytes(uint64_t bytes)
+ {
+ // Use 1024 for "kilo", 1024*1024 for "mega" and so on instead of the more modern and standard-conforming
+ // 1000, 1000*1000 and so on, to be consistent with other Monero code that also uses base 2 units
+ struct byte_map
+ {
+ const char* const format;
+ const std::uint64_t bytes;
+ };
+
+ static constexpr const byte_map sizes[] =
+ {
+ {"%.0f B", 1024},
+ {"%.2f KB", 1024 * 1024},
+ {"%.2f MB", std::uint64_t(1024) * 1024 * 1024},
+ {"%.2f GB", std::uint64_t(1024) * 1024 * 1024 * 1024},
+ {"%.2f TB", std::uint64_t(1024) * 1024 * 1024 * 1024 * 1024}
+ };
+
+ struct bytes_less
+ {
+ bool operator()(const byte_map& lhs, const byte_map& rhs) const noexcept
+ {
+ return lhs.bytes < rhs.bytes;
+ }
+ };
+
+ const auto size = std::upper_bound(
+ std::begin(sizes), std::end(sizes) - 1, byte_map{"", bytes}, bytes_less{}
+ );
+ const std::uint64_t divisor = size->bytes / 1024;
+ return (boost::format(size->format) % (double(bytes) / divisor)).str();
+ }
+
}
diff --git a/src/common/util.h b/src/common/util.h
index ef2305bf4..77a5a9af6 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -244,4 +244,6 @@ namespace tools
void closefrom(int fd);
std::string get_human_readable_timestamp(uint64_t ts);
+
+ std::string get_human_readable_bytes(uint64_t bytes);
}
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index b324ab99d..17b945c9a 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -127,6 +127,13 @@ bool t_command_parser_executor::print_connections(const std::vector<std::string>
return m_executor.print_connections();
}
+bool t_command_parser_executor::print_net_stats(const std::vector<std::string>& args)
+{
+ if (!args.empty()) return false;
+
+ return m_executor.print_net_stats();
+}
+
bool t_command_parser_executor::print_blockchain_info(const std::vector<std::string>& args)
{
if(!args.size())
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index bec6e4522..098018642 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -148,6 +148,8 @@ public:
bool prune_blockchain(const std::vector<std::string>& args);
bool check_blockchain_pruning(const std::vector<std::string>& args);
+
+ bool print_net_stats(const std::vector<std::string>& args);
};
} // namespace daemonize
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 94e4a8bf1..69ad6ff10 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -78,6 +78,11 @@ t_command_server::t_command_server(
, "Print the current connections."
);
m_command_lookup.set_handler(
+ "print_net_stats"
+ , std::bind(&t_command_parser_executor::print_net_stats, &m_parser, p::_1)
+ , "Print network statistics."
+ );
+ m_command_lookup.set_handler(
"print_bc"
, std::bind(&t_command_parser_executor::print_blockchain_info, &m_parser, p::_1)
, "print_bc <begin_height> [<end_height>]"
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 4ee67f571..c9ec5109e 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -627,6 +627,66 @@ bool t_rpc_command_executor::print_connections() {
return true;
}
+bool t_rpc_command_executor::print_net_stats()
+{
+ cryptonote::COMMAND_RPC_GET_NET_STATS::request net_stats_req;
+ cryptonote::COMMAND_RPC_GET_NET_STATS::response net_stats_res;
+ cryptonote::COMMAND_RPC_GET_LIMIT::request limit_req;
+ cryptonote::COMMAND_RPC_GET_LIMIT::response limit_res;
+
+ std::string fail_message = "Unsuccessful";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->json_rpc_request(net_stats_req, net_stats_res, "get_net_stats", fail_message.c_str()))
+ {
+ return true;
+ }
+ if (!m_rpc_client->json_rpc_request(limit_req, limit_res, "get_limit", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_net_stats(net_stats_req, net_stats_res) || net_stats_res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, net_stats_res.status);
+ return true;
+ }
+ if (!m_rpc_server->on_get_limit(limit_req, limit_res) || limit_res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, limit_res.status);
+ return true;
+ }
+ }
+
+ uint64_t seconds = (uint64_t)time(NULL) - net_stats_res.start_time;
+ uint64_t average = seconds > 0 ? net_stats_res.total_bytes_in / seconds : 0;
+ uint64_t limit = limit_res.limit_down * 1024; // convert to bytes, as limits are always kB/s
+ double percent = (double)average / (double)limit * 100.0;
+ tools::success_msg_writer() << boost::format("Received %u bytes (%s) in %u packets, average %s/s = %.2f%% of the limit of %s/s")
+ % net_stats_res.total_bytes_in
+ % tools::get_human_readable_bytes(net_stats_res.total_bytes_in)
+ % net_stats_res.total_packets_in
+ % tools::get_human_readable_bytes(average)
+ % percent
+ % tools::get_human_readable_bytes(limit);
+
+ average = seconds > 0 ? net_stats_res.total_bytes_out / seconds : 0;
+ limit = limit_res.limit_up * 1024;
+ percent = (double)average / (double)limit * 100.0;
+ tools::success_msg_writer() << boost::format("Sent %u bytes (%s) in %u packets, average %s/s = %.2f%% of the limit of %s/s")
+ % net_stats_res.total_bytes_out
+ % tools::get_human_readable_bytes(net_stats_res.total_bytes_out)
+ % net_stats_res.total_packets_out
+ % tools::get_human_readable_bytes(average)
+ % percent
+ % tools::get_human_readable_bytes(limit);
+
+ return true;
+}
+
bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index) {
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request req;
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response res;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 423132b79..3c2686b3f 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -160,6 +160,8 @@ public:
bool prune_blockchain();
bool check_blockchain_pruning();
+
+ bool print_net_stats();
};
} // namespace daemonize
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 7af62bfe0..f5f1a2f9a 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -268,6 +268,23 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_get_net_stats(const COMMAND_RPC_GET_NET_STATS::request& req, COMMAND_RPC_GET_NET_STATS::response& res, const connection_context *ctx)
+ {
+ PERF_TIMER(on_get_net_stats);
+ // No bootstrap daemon check: Only ever get stats about local server
+ res.start_time = (uint64_t)m_core.get_start_time();
+ {
+ CRITICAL_REGION_LOCAL(epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_in);
+ epee::net_utils::network_throttle_manager::get_global_throttle_in().get_stats(res.total_packets_in, res.total_bytes_in);
+ }
+ {
+ CRITICAL_REGION_LOCAL(epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_out);
+ epee::net_utils::network_throttle_manager::get_global_throttle_out().get_stats(res.total_packets_out, res.total_bytes_out);
+ }
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
class pruned_transaction {
transaction& tx;
public:
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index fe066b31b..8f5d83f1b 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -115,6 +115,7 @@ namespace cryptonote
MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted)
MAP_URI_AUTO_JON2("/get_info", on_get_info, COMMAND_RPC_GET_INFO)
MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO)
+ MAP_URI_AUTO_JON2_IF("/get_net_stats", on_get_net_stats, COMMAND_RPC_GET_NET_STATS, !m_restricted)
MAP_URI_AUTO_JON2("/get_limit", on_get_limit, COMMAND_RPC_GET_LIMIT)
MAP_URI_AUTO_JON2_IF("/set_limit", on_set_limit, COMMAND_RPC_SET_LIMIT, !m_restricted)
MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted)
@@ -179,6 +180,7 @@ namespace cryptonote
bool on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res, const connection_context *ctx = NULL);
bool on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res, const connection_context *ctx = NULL);
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, const connection_context *ctx = NULL);
+ bool on_get_net_stats(const COMMAND_RPC_GET_NET_STATS::request& req, COMMAND_RPC_GET_NET_STATS::response& res, const connection_context *ctx = NULL);
bool on_save_bc(const COMMAND_RPC_SAVE_BC::request& req, COMMAND_RPC_SAVE_BC::response& res, const connection_context *ctx = NULL);
bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res, const connection_context *ctx = NULL);
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res, const connection_context *ctx = NULL);
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index e65790cae..1f14267f6 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -739,6 +739,39 @@ namespace cryptonote
//-----------------------------------------------
+ struct COMMAND_RPC_GET_NET_STATS
+ {
+ struct request_t
+ {
+
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+
+ struct response_t
+ {
+ std::string status;
+ uint64_t start_time;
+ uint64_t total_packets_in;
+ uint64_t total_bytes_in;
+ uint64_t total_packets_out;
+ uint64_t total_bytes_out;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(start_time)
+ KV_SERIALIZE(total_packets_in)
+ KV_SERIALIZE(total_bytes_in)
+ KV_SERIALIZE(total_packets_out)
+ KV_SERIALIZE(total_bytes_out)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ //-----------------------------------------------
struct COMMAND_RPC_STOP_MINING
{
struct request_t