diff options
author | rfree2monero <rfreemonero@op.pl> | 2015-04-01 18:24:45 +0200 |
---|---|---|
committer | rfree2monero <rfreemonero@op.pl> | 2015-04-01 18:24:45 +0200 |
commit | 3cbdf198f168e113f12fa49d016133c434964ed7 (patch) | |
tree | 050c74077de8e1b6e431f7d0671b57b5afcb01ab /src/daemon | |
parent | fix locking in count-peers thread (2) (diff) | |
parent | Merge pull request #248 (diff) | |
download | monero-3cbdf198f168e113f12fa49d016133c434964ed7.tar.xz |
Merge remote-tracking branch 'monero-official/master' into network-1.6-work1
Diffstat (limited to 'src/daemon')
-rw-r--r-- | src/daemon/CMakeLists.txt | 39 | ||||
-rw-r--r-- | src/daemon/command_line_args.h | 76 | ||||
-rw-r--r-- | src/daemon/command_parser_executor.cpp | 299 | ||||
-rw-r--r-- | src/daemon/command_parser_executor.h | 98 | ||||
-rw-r--r-- | src/daemon/command_server.cpp | 213 | ||||
-rw-r--r-- | src/daemon/command_server.h | 75 | ||||
-rw-r--r-- | src/daemon/core.h | 99 | ||||
-rw-r--r-- | src/daemon/daemon.cpp | 377 | ||||
-rw-r--r-- | src/daemon/daemon.h | 54 | ||||
-rw-r--r-- | src/daemon/daemon_commands_handler.h | 191 | ||||
-rw-r--r-- | src/daemon/executor.cpp | 71 | ||||
-rw-r--r-- | src/daemon/executor.h | 60 | ||||
-rw-r--r-- | src/daemon/main.cpp | 238 | ||||
-rw-r--r-- | src/daemon/p2p.h | 99 | ||||
-rw-r--r-- | src/daemon/protocol.h | 88 | ||||
-rw-r--r-- | src/daemon/rpc.h | 101 | ||||
-rw-r--r-- | src/daemon/rpc_command_executor.cpp | 692 | ||||
-rw-r--r-- | src/daemon/rpc_command_executor.h | 111 |
18 files changed, 2649 insertions, 332 deletions
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index 4a0dcb148..4de8b82b8 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -27,12 +27,43 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. set(daemon_sources - daemon.cpp) + command_parser_executor.cpp + command_server.cpp + daemon.cpp + executor.cpp + main.cpp + rpc_command_executor.cpp +) set(daemon_headers) set(daemon_private_headers - daemon_commands_handler.h) + command_parser_executor.h + command_server.h + core.h + daemon.h + daemon_commands_handler.h + executor.h + p2p.h + protocol.h + rpc.h + rpc_command_executor.h + + # cryptonote_protocol + ../cryptonote_protocol/blobdatatype.h + ../cryptonote_protocol/cryptonote_protocol_defs.h + ../cryptonote_protocol/cryptonote_protocol_handler.h + ../cryptonote_protocol/cryptonote_protocol_handler.inl + ../cryptonote_protocol/cryptonote_protocol_handler_common.h + + # p2p + ../p2p/net_node.h + ../p2p/net_node.inl + ../p2p/net_node_common.h + ../p2p/net_peerlist.h + ../p2p/net_peerlist_boost_serialization.h + ../p2p/p2p_protocol_defs.h + ../p2p/stdafx.h) bitmonero_private_headers(daemon ${daemon_private_headers}) @@ -46,9 +77,7 @@ target_link_libraries(daemon cryptonote_core crypto common - otshell_utils - p2p - cryptonote_protocol + daemonizer ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h new file mode 100644 index 000000000..bcf599128 --- /dev/null +++ b/src/daemon/command_line_args.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef DAEMON_COMMAND_LINE_ARGS_H +#define DAEMON_COMMAND_LINE_ARGS_H + +#include "common/command_line.h" +#include "cryptonote_config.h" +#include <boost/program_options.hpp> + +namespace daemon_args +{ + std::string const WINDOWS_SERVICE_NAME = "Monero Daemon"; + + const command_line::arg_descriptor<std::string> arg_config_file = { + "config-file" + , "Specify configuration file" + , std::string(CRYPTONOTE_NAME ".conf") + }; + const command_line::arg_descriptor<std::string> arg_log_file = { + "log-file" + , "Specify log file" + , "" + }; + const command_line::arg_descriptor<int> arg_log_level = { + "log-level" + , "" + , LOG_LEVEL_0 + }; + const command_line::arg_descriptor<std::vector<std::string>> arg_command = { + "daemon_command" + , "Hidden" + }; + const command_line::arg_descriptor<bool> arg_os_version = { + "os-version" + , "OS for which this executable was compiled" + }; + const command_line::arg_descriptor<bool> arg_testnet_on = { + "testnet" + , "Run on testnet. The wallet must be launched with --testnet flag." + , false + }; + const command_line::arg_descriptor<bool> arg_dns_checkpoints = { + "enforce-dns-checkpointing" + , "checkpoints from DNS server will be enforced" + , false + }; + +} // namespace daemon_args + +#endif // DAEMON_COMMAND_LINE_ARGS_H diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp new file mode 100644 index 000000000..8f023da9a --- /dev/null +++ b/src/daemon/command_parser_executor.cpp @@ -0,0 +1,299 @@ +// 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 "cryptonote_core/cryptonote_basic_impl.h" +#include "daemon/command_parser_executor.h" + +namespace daemonize { + +t_command_parser_executor::t_command_parser_executor( + uint32_t ip + , uint16_t port + , bool is_rpc + , cryptonote::core_rpc_server* rpc_server + ) + : m_executor(ip, port, is_rpc, rpc_server) +{} + +bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.print_peer_list(); +} + +bool t_command_parser_executor::save_blockchain(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.save_blockchain(); +} + +bool t_command_parser_executor::show_hash_rate(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.show_hash_rate(); +} + +bool t_command_parser_executor::hide_hash_rate(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.hide_hash_rate(); +} + +bool t_command_parser_executor::show_difficulty(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.show_difficulty(); +} + +bool t_command_parser_executor::print_connections(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.print_connections(); +} + +bool t_command_parser_executor::print_blockchain_info(const std::vector<std::string>& args) +{ + if(!args.size()) + { + std::cout << "need block index parameter" << std::endl; + return false; + } + uint64_t start_index = 0; + uint64_t end_index = 0; + if(!epee::string_tools::get_xtype_from_string(start_index, args[0])) + { + std::cout << "wrong starter block index parameter" << std::endl; + return false; + } + if(args.size() >1 && !epee::string_tools::get_xtype_from_string(end_index, args[1])) + { + std::cout << "wrong end block index parameter" << std::endl; + return false; + } + + return m_executor.print_blockchain_info(start_index, end_index); +} + +bool t_command_parser_executor::set_log_level(const std::vector<std::string>& args) +{ + if(args.size() != 1) + { + std::cout << "use: set_log <log_level_number_0-4>" << std::endl; + return true; + } + + uint16_t l = 0; + if(!epee::string_tools::get_xtype_from_string(l, args[0])) + { + std::cout << "wrong number format, use: set_log <log_level_number_0-4>" << std::endl; + return true; + } + + if(LOG_LEVEL_4 < l) + { + std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << std::endl; + return true; + } + + return m_executor.set_log_level(l); +} + +bool t_command_parser_executor::print_height(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.print_height(); +} + +bool t_command_parser_executor::print_block(const std::vector<std::string>& args) +{ + if (args.empty()) + { + std::cout << "expected: print_block (<block_hash> | <block_height>)" << std::endl; + return false; + } + + const std::string& arg = args.front(); + try + { + uint64_t height = boost::lexical_cast<uint64_t>(arg); + return m_executor.print_block_by_height(height); + } + catch (boost::bad_lexical_cast&) + { + crypto::hash block_hash; + if (parse_hash256(arg, block_hash)) + { + return m_executor.print_block_by_hash(block_hash); + } + } + + return false; +} + +bool t_command_parser_executor::print_transaction(const std::vector<std::string>& args) +{ + if (args.empty()) + { + std::cout << "expected: print_tx <transaction hash>" << std::endl; + return true; + } + + const std::string& str_hash = args.front(); + crypto::hash tx_hash; + if (parse_hash256(str_hash, tx_hash)) + { + m_executor.print_transaction(tx_hash); + } + + return true; +} + +bool t_command_parser_executor::print_transaction_pool_long(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.print_transaction_pool_long(); +} + +bool t_command_parser_executor::print_transaction_pool_short(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.print_transaction_pool_short(); +} + +bool t_command_parser_executor::start_mining(const std::vector<std::string>& args) +{ + if(!args.size()) + { + std::cout << "Please specify a wallet address to mine for: start_mining <addr> [threads=1]" << std::endl; + return true; + } + + cryptonote::account_public_address adr; + if(!cryptonote::get_account_address_from_str(adr, false, args.front())) + { + if(!cryptonote::get_account_address_from_str(adr, true, args.front())) + { + std::cout << "target account address has wrong format" << std::endl; + return true; + } + std::cout << "Mining to a testnet address, make sure this is intentional!" << std::endl; + } + uint64_t threads_count = 1; + if(args.size() > 2) + { + return false; + } + else if(args.size() == 2) + { + bool ok = epee::string_tools::get_xtype_from_string(threads_count, args[1]); + threads_count = (ok && 0 < threads_count) ? threads_count : 1; + } + + m_executor.start_mining(adr, threads_count); + + return true; +} + +bool t_command_parser_executor::stop_mining(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.stop_mining(); +} + +bool t_command_parser_executor::stop_daemon(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.stop_daemon(); +} + +bool t_command_parser_executor::print_status(const std::vector<std::string>& args) +{ + if (!args.empty()) return false; + + return m_executor.print_status(); +} + +bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) +{ + if(args.size()!=1) return false; + int limit; + try { + limit = std::stoi(args[0]); + } + catch(std::invalid_argument& ex) { + return false; + } + if (limit==-1) limit=128; + limit *= 1024; + + return m_executor.set_limit(limit); +} + +bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& args) +{ + if(args.size()!=1) return false; + int limit; + try { + limit = std::stoi(args[0]); + } + catch(std::invalid_argument& ex) { + return false; + } + if (limit==-1) limit=128; + limit *= 1024; + + return m_executor.set_limit_up(limit); +} + +bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& args) +{ + if(args.size()!=1) return false; + int limit; + try { + limit = std::stoi(args[0]); + } + catch(std::invalid_argument& ex) { + return false; + } + if (limit==-1) limit=128; + limit *= 1024; + + return m_executor.set_limit_down(limit); +} +} // namespace daemonize diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h new file mode 100644 index 000000000..07d2e70a9 --- /dev/null +++ b/src/daemon/command_parser_executor.h @@ -0,0 +1,98 @@ +/** +@file +@details + +@image html images/other/runtime-commands.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. + +#pragma once + +#include "daemon/rpc_command_executor.h" +#include "rpc/core_rpc_server.h" + +namespace daemonize { + +class t_command_parser_executor final +{ +private: + t_rpc_command_executor m_executor; +public: + t_command_parser_executor( + uint32_t ip + , uint16_t port + , bool is_rpc + , cryptonote::core_rpc_server* rpc_server = NULL + ); + + bool print_peer_list(const std::vector<std::string>& args); + + bool save_blockchain(const std::vector<std::string>& args); + + bool show_hash_rate(const std::vector<std::string>& args); + + bool hide_hash_rate(const std::vector<std::string>& args); + + bool show_difficulty(const std::vector<std::string>& args); + + bool print_connections(const std::vector<std::string>& args); + + bool print_blockchain_info(const std::vector<std::string>& args); + + bool set_log_level(const std::vector<std::string>& args); + + bool print_height(const std::vector<std::string>& args); + + bool print_block(const std::vector<std::string>& args); + + bool print_transaction(const std::vector<std::string>& args); + + bool print_transaction_pool_long(const std::vector<std::string>& args); + + bool print_transaction_pool_short(const std::vector<std::string>& args); + + bool start_mining(const std::vector<std::string>& args); + + bool stop_mining(const std::vector<std::string>& args); + + bool stop_daemon(const std::vector<std::string>& args); + + bool print_status(const std::vector<std::string>& args); + + bool set_limit(const std::vector<std::string>& args); + + bool set_limit_up(const std::vector<std::string>& args); + + bool set_limit_down(const std::vector<std::string>& args); + +}; + +} // namespace daemonize diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp new file mode 100644 index 000000000..601b12d57 --- /dev/null +++ b/src/daemon/command_server.cpp @@ -0,0 +1,213 @@ +// 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 "cryptonote_config.h" +#include "version.h" +#include "daemon/command_server.h" + +namespace daemonize { + +namespace p = std::placeholders; + +t_command_server::t_command_server( + uint32_t ip + , uint16_t port + , bool is_rpc + , cryptonote::core_rpc_server* rpc_server + ) + : m_parser(ip, port, is_rpc, rpc_server) + , m_command_lookup() + , m_is_rpc(is_rpc) +{ + m_command_lookup.set_handler( + "q" + , [] (const std::vector<std::string>& args) {return true;} + , "ignored" + ); + m_command_lookup.set_handler( + "help" + , std::bind(&t_command_server::help, this, p::_1) + , "Show this help" + ); + m_command_lookup.set_handler( + "print_height" + , std::bind(&t_command_parser_executor::print_height, &m_parser, p::_1) + , "Print local blockchain height" + ); + m_command_lookup.set_handler( + "print_pl" + , std::bind(&t_command_parser_executor::print_peer_list, &m_parser, p::_1) + , "Print peer list" + ); + m_command_lookup.set_handler( + "print_cn" + , std::bind(&t_command_parser_executor::print_connections, &m_parser, p::_1) + , "Print connections" + ); + m_command_lookup.set_handler( + "print_bc" + , std::bind(&t_command_parser_executor::print_blockchain_info, &m_parser, p::_1) + , "Print blockchain info in a given blocks range, print_bc <begin_height> [<end_height>]" + ); + m_command_lookup.set_handler( + "print_block" + , std::bind(&t_command_parser_executor::print_block, &m_parser, p::_1) + , "Print block, print_block <block_hash> | <block_height>" + ); + m_command_lookup.set_handler( + "print_tx" + , std::bind(&t_command_parser_executor::print_transaction, &m_parser, p::_1) + , "Print transaction, print_tx <transaction_hash>" + ); + m_command_lookup.set_handler( + "start_mining" + , std::bind(&t_command_parser_executor::start_mining, &m_parser, p::_1) + , "Start mining for specified address, start_mining <addr> [threads=1]" + ); + m_command_lookup.set_handler( + "stop_mining" + , std::bind(&t_command_parser_executor::stop_mining, &m_parser, p::_1) + , "Stop mining" + ); + m_command_lookup.set_handler( + "print_pool" + , std::bind(&t_command_parser_executor::print_transaction_pool_long, &m_parser, p::_1) + , "Print transaction pool (long format)" + ); + m_command_lookup.set_handler( + "print_pool_sh" + , std::bind(&t_command_parser_executor::print_transaction_pool_short, &m_parser, p::_1) + , "Print transaction pool (short format)" + ); + m_command_lookup.set_handler( + "show_hr" + , std::bind(&t_command_parser_executor::show_hash_rate, &m_parser, p::_1) + , "Start showing hash rate" + ); + m_command_lookup.set_handler( + "hide_hr" + , std::bind(&t_command_parser_executor::hide_hash_rate, &m_parser, p::_1) + , "Stop showing hash rate" + ); + m_command_lookup.set_handler( + "save" + , std::bind(&t_command_parser_executor::save_blockchain, &m_parser, p::_1) + , "Save blockchain" + ); + m_command_lookup.set_handler( + "set_log" + , std::bind(&t_command_parser_executor::set_log_level, &m_parser, p::_1) + , "set_log <level> - Change current log detalization level, <level> is a number 0-4" + ); + m_command_lookup.set_handler( + "diff" + , std::bind(&t_command_parser_executor::show_difficulty, &m_parser, p::_1) + , "Show difficulty" + ); + m_command_lookup.set_handler( + "stop_daemon" + , std::bind(&t_command_parser_executor::stop_daemon, &m_parser, p::_1) + , "Stop the daemon" + ); + m_command_lookup.set_handler( + "exit" + , std::bind(&t_command_parser_executor::stop_daemon, &m_parser, p::_1) + , "Stop the daemon" + ); + m_command_lookup.set_handler( + "print_status" + , std::bind(&t_command_parser_executor::print_status, &m_parser, p::_1) + , "Prints daemon status" + ); + m_command_lookup.set_handler( + "limit" + , std::bind(&t_command_parser_executor::set_limit, &m_parser, p::_1) + , "limit <kB/s> - Set download and upload limit" + ); + m_command_lookup.set_handler( + "limit-up" + , std::bind(&t_command_parser_executor::set_limit_up, &m_parser, p::_1) + , "limit <kB/s> - Set upload limit" + ); + m_command_lookup.set_handler( + "limit-down" + , std::bind(&t_command_parser_executor::set_limit_down, &m_parser, p::_1) + , "limit <kB/s> - Set download limit" + ); +} + +bool t_command_server::process_command_str(const std::string& cmd) +{ + return m_command_lookup.process_command_str(cmd); +} + +bool t_command_server::process_command_vec(const std::vector<std::string>& cmd) +{ + bool result = m_command_lookup.process_command_vec(cmd); + if (!result) + { + help(std::vector<std::string>()); + } + return result; +} + +bool t_command_server::start_handling() +{ + if (m_is_rpc) return false; + + m_command_lookup.start_handling("", get_commands_str()); + + return true; +} + +void t_command_server::stop_handling() +{ + if (m_is_rpc) return; + + m_command_lookup.stop_handling(); +} + +bool t_command_server::help(const std::vector<std::string>& args) +{ + std::cout << get_commands_str() << std::endl; + return true; +} + +std::string t_command_server::get_commands_str() +{ + std::stringstream ss; + ss << CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL << std::endl; + ss << "Commands: " << std::endl; + std::string usage = m_command_lookup.get_usage(); + boost::replace_all(usage, "\n", "\n "); + usage.insert(0, " "); + ss << usage << std::endl; + return ss.str(); +} + +} // namespace daemonize diff --git a/src/daemon/command_server.h b/src/daemon/command_server.h new file mode 100644 index 000000000..494f44d8b --- /dev/null +++ b/src/daemon/command_server.h @@ -0,0 +1,75 @@ +/** +@file +@details + + +Passing RPC commands: + +@image html images/other/runtime-commands.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. + +#pragma once + +#include "console_handler.h" +#include "daemon/command_parser_executor.h" + +namespace daemonize { + +class t_command_server { +private: + t_command_parser_executor m_parser; + epee::console_handlers_binder m_command_lookup; + bool m_is_rpc; + +public: + t_command_server( + uint32_t ip + , uint16_t port + , bool is_rpc = true + , cryptonote::core_rpc_server* rpc_server = NULL + ); + + bool process_command_str(const std::string& cmd); + + bool process_command_vec(const std::vector<std::string>& cmd); + + bool start_handling(); + + void stop_handling(); + +private: + bool help(const std::vector<std::string>& args); + + std::string get_commands_str(); +}; + +} // namespace daemonize diff --git a/src/daemon/core.h b/src/daemon/core.h new file mode 100644 index 000000000..6564e5314 --- /dev/null +++ b/src/daemon/core.h @@ -0,0 +1,99 @@ +// 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. + +#pragma once + +#include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/cryptonote_core.h" +#include "cryptonote_protocol/cryptonote_protocol_handler.h" +#include "misc_log_ex.h" +#include <stdexcept> +#include <boost/program_options.hpp> +#include "daemon/command_line_args.h" + +namespace daemonize +{ + +class t_core final +{ +public: + static void init_options(boost::program_options::options_description & option_spec) + { + cryptonote::core::init_options(option_spec); + cryptonote::miner::init_options(option_spec); + } +private: + typedef cryptonote::t_cryptonote_protocol_handler<cryptonote::core> t_protocol_raw; + cryptonote::core m_core; + // TEMPORARY HACK - Yes, this creates a copy, but otherwise the original + // variable map could go out of scope before the run method is called + boost::program_options::variables_map const m_vm_HACK; +public: + t_core( + boost::program_options::variables_map const & vm + ) + : m_core{nullptr} + , m_vm_HACK{vm} + { + } + + // TODO - get rid of circular dependencies in internals + void set_protocol(t_protocol_raw & protocol) + { + m_core.set_cryptonote_protocol(&protocol); + } + + void run() + { + //initialize core here + LOG_PRINT_L0("Initializing core..."); + if (!m_core.init(m_vm_HACK)) + { + throw std::runtime_error("Failed to initialize core"); + } + LOG_PRINT_L0("Core initialized OK"); + } + + cryptonote::core & get() + { + return m_core; + } + + ~t_core() + { + LOG_PRINT_L0("Deinitializing core..."); + try { + m_core.deinit(); + m_core.set_cryptonote_protocol(nullptr); + } catch (...) { + LOG_PRINT_L0("Failed to deinitialize core..."); + } + } +}; + +} diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 4a93a0db8..ec12c281c 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -1,21 +1,21 @@ -// Copyright (c) 2014-2015, The Monero Project -// +// 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 @@ -25,305 +25,136 @@ // 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. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -// node.cpp : Defines the entry point for the console application. -// Does this file exist? +#include "daemon/daemon.h" - -#include "include_base_utils.h" +#include "common/util.h" +#include "daemon/core.h" +#include "daemon/p2p.h" +#include "daemon/protocol.h" +#include "daemon/rpc.h" +#include "daemon/command_server.h" +#include "misc_log_ex.h" #include "version.h" -#include "../../contrib/epee/include/syncobj.h" - -using namespace epee; - #include <boost/program_options.hpp> +#include <functional> +#include <memory> + +namespace daemonize { + +struct t_internals { +private: + t_protocol protocol; +public: + t_core core; + t_p2p p2p; + t_rpc rpc; + + t_internals( + boost::program_options::variables_map const & vm + ) + : core{vm} + , protocol{vm, core} + , p2p{vm, protocol} + , rpc{vm, core, p2p} + { + // Handle circular dependencies + protocol.set_p2p_endpoint(p2p.get()); + core.set_protocol(protocol.get()); + } +}; -#include "crypto/hash.h" -#include "console_handler.h" -#include "p2p/net_node.h" -#include "cryptonote_config.h" -#include "cryptonote_core/checkpoints_create.h" -#include "cryptonote_core/checkpoints.h" -#include "cryptonote_core/cryptonote_core.h" -#include "rpc/core_rpc_server.h" -#include "cryptonote_protocol/cryptonote_protocol_handler.h" -#include "daemon_commands_handler.h" -#include "version.h" - -#if defined(WIN32) -#include <crtdbg.h> -#endif +void t_daemon::init_options(boost::program_options::options_description & option_spec) +{ + t_core::init_options(option_spec); + t_p2p::init_options(option_spec); + t_rpc::init_options(option_spec); +} -namespace po = boost::program_options; +t_daemon::t_daemon( + boost::program_options::variables_map const & vm + ) + : mp_internals{new t_internals{vm}} +{} -unsigned int epee::g_test_dbg_lock_sleep = 0; +t_daemon::~t_daemon() = default; -namespace +// MSVC is brain-dead and can't default this... +t_daemon::t_daemon(t_daemon && other) { - const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", "Specify configuration file", std::string(CRYPTONOTE_NAME ".conf")}; - const command_line::arg_descriptor<bool> arg_os_version = {"os-version", ""}; - const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", "", ""}; - const command_line::arg_descriptor<int> arg_log_level = {"log-level", "", LOG_LEVEL_0}; - const command_line::arg_descriptor<bool> arg_console = {"no-console", "Disable daemon console commands"}; - const command_line::arg_descriptor<bool> arg_testnet_on = { - "testnet" - , "Run on testnet. The wallet must be launched with --testnet flag." - , false - }; - const command_line::arg_descriptor<bool> arg_dns_checkpoints = {"enforce-dns-checkpointing", "checkpoints from DNS server will be enforced", false}; - const command_line::arg_descriptor<bool> arg_test_drop_download = {"test-drop-download", "For net tests: in download, discard ALL blocks instead checking/saving them (very fast)"}; - const command_line::arg_descriptor<uint64_t> arg_test_drop_download_height = {"test-drop-download-height", "Like test-drop-download but disards only after around certain height", 0}; - const command_line::arg_descriptor<bool> arg_save_graph = {"save-graph", "Save data for dr monero", false}; - const command_line::arg_descriptor<int> test_dbg_lock_sleep = {"test-dbg-lock-sleep", "Sleep time in ms, defaults to 0 (off), used to debug before/after locking mutex. Values 100 to 1000 are good for tests.", 0}; + if (this != &other) + { + mp_internals = std::move(other.mp_internals); + other.mp_internals.reset(nullptr); + } } -bool command_line_preprocessor(const boost::program_options::variables_map& vm) +// or this +t_daemon & t_daemon::operator=(t_daemon && other) { - bool exit = false; - if (command_line::get_arg(vm, command_line::arg_version)) - { - std::cout << CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL << ENDL; - exit = true; - } - if (command_line::get_arg(vm, arg_os_version)) + if (this != &other) { - std::cout << "OS: " << tools::get_os_version_string() << ENDL; - exit = true; + mp_internals = std::move(other.mp_internals); + other.mp_internals.reset(nullptr); } + return *this; +} - if (exit) +bool t_daemon::run(bool interactive) +{ + if (nullptr == mp_internals) { - return true; + throw std::runtime_error{"Can't run stopped daemon"}; } + tools::signal_handler::install(std::bind(&daemonize::t_daemon::stop, this)); - int new_log_level = command_line::get_arg(vm, arg_log_level); - if(new_log_level < LOG_LEVEL_MIN || new_log_level > LOG_LEVEL_MAX) + try { - LOG_PRINT_L0("Wrong log level value: "); - } - else if (log_space::get_set_log_detalisation_level(false) != new_log_level) - { - log_space::get_set_log_detalisation_level(true, new_log_level); - int otshell_utils_log_level = 100 - (new_log_level * 25); - gCurrentLogger.setDebugLevel(otshell_utils_log_level); - LOG_PRINT_L0("LOG_LEVEL set to " << new_log_level); - } - - return false; -} - -int main(int argc, char* argv[]) -{ - string_tools::set_module_name_and_folder(argv[0]); -#ifdef WIN32 - _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); -#endif - log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); - log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); - LOG_PRINT_L0("Starting..."); - - nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); - _warn_c("test","Starting program (a test message)"); - _warn_c("main/program","Starting program"); - - TRY_ENTRY(); + mp_internals->core.run(); + mp_internals->rpc.run(); - boost::filesystem::path default_data_path {tools::get_default_data_dir()}; - boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"}; + daemonize::t_command_server* rpc_commands; - po::options_description desc_cmd_only("Command line options"); - po::options_description desc_cmd_sett("Command line options and settings options"); + if (interactive) + { + rpc_commands = new daemonize::t_command_server(0, 0, false, mp_internals->rpc.get_server()); + rpc_commands->start_handling(); + } - command_line::add_arg(desc_cmd_only, command_line::arg_help); - command_line::add_arg(desc_cmd_only, command_line::arg_version); - command_line::add_arg(desc_cmd_only, arg_os_version); - // tools::get_default_data_dir() can't be called during static initialization - command_line::add_arg(desc_cmd_only, command_line::arg_data_dir, default_data_path.string()); - command_line::add_arg(desc_cmd_only, command_line::arg_testnet_data_dir, default_testnet_data_path.string()); - command_line::add_arg(desc_cmd_only, arg_config_file); + mp_internals->p2p.run(); // blocks until p2p goes down - command_line::add_arg(desc_cmd_sett, arg_log_file); - command_line::add_arg(desc_cmd_sett, arg_log_level); - command_line::add_arg(desc_cmd_sett, arg_console); - command_line::add_arg(desc_cmd_sett, arg_testnet_on); - command_line::add_arg(desc_cmd_sett, arg_dns_checkpoints); - command_line::add_arg(desc_cmd_sett, arg_test_drop_download); - command_line::add_arg(desc_cmd_sett, arg_test_drop_download_height); - command_line::add_arg(desc_cmd_sett, arg_save_graph); - command_line::add_arg(desc_cmd_sett, test_dbg_lock_sleep); - - cryptonote::core::init_options(desc_cmd_sett); - cryptonote::core_rpc_server::init_options(desc_cmd_sett); - nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >::init_options(desc_cmd_sett); - cryptonote::miner::init_options(desc_cmd_sett); - - po::options_description desc_options("Allowed options"); - desc_options.add(desc_cmd_only).add(desc_cmd_sett); - - po::variables_map vm; - bool r = command_line::handle_error_helper(desc_options, [&]() - { - po::store(po::parse_command_line(argc, argv, desc_options), vm); - po::notify(vm); + if (interactive) + { + rpc_commands->stop_handling(); + } + mp_internals->rpc.stop(); + LOG_PRINT("Node stopped.", LOG_LEVEL_0); return true; - }); - if (!r) - return 1; - - if (command_line::get_arg(vm, command_line::arg_help)) - { - std::cout << CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL << ENDL << ENDL; - std::cout << desc_options << std::endl; - return false; } - - bool testnet_mode = command_line::get_arg(vm, arg_testnet_on); - - auto data_dir_arg = testnet_mode ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; - - std::string data_dir = command_line::get_arg(vm, data_dir_arg); - tools::create_directories_if_necessary(data_dir); - std::string config = command_line::get_arg(vm, arg_config_file); - - boost::filesystem::path data_dir_path(data_dir); - boost::filesystem::path config_path(config); - if (!config_path.has_parent_path()) - { - config_path = data_dir_path / config_path; - } - - boost::system::error_code ec; - if (boost::filesystem::exists(config_path, ec)) + catch (std::exception const & ex) { - po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), desc_cmd_sett), vm); + LOG_ERROR("Uncaught exception! " << ex.what()); + return false; } - - //set up logging options - boost::filesystem::path log_file_path(command_line::get_arg(vm, arg_log_file)); - if (log_file_path.empty()) - log_file_path = log_space::log_singletone::get_default_log_file(); - std::string log_dir; - log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder(); - - log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str()); - LOG_PRINT_L0(CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL); - - if (command_line_preprocessor(vm)) + catch (...) { - return 0; - } - - LOG_PRINT("Module folder: " << argv[0], LOG_LEVEL_0); - - bool res = true; - cryptonote::checkpoints checkpoints; - res = cryptonote::create_checkpoints(checkpoints); - CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints"); - boost::filesystem::path json(JSON_HASH_FILE_NAME); - boost::filesystem::path checkpoint_json_hashfile_fullpath = data_dir / json; - - //create objects and link them - cryptonote::core ccore(NULL); - - // tell core if we're enforcing dns checkpoints - bool enforce_dns = command_line::get_arg(vm, arg_dns_checkpoints); - ccore.set_enforce_dns_checkpoints(enforce_dns); - - if (testnet_mode) { - LOG_PRINT_L0("Starting in testnet mode!"); - } else { - ccore.set_checkpoints(std::move(checkpoints)); - ccore.set_checkpoints_file_path(checkpoint_json_hashfile_fullpath.string()); + LOG_ERROR("Uncaught exception!"); + return false; } +} - cryptonote::t_cryptonote_protocol_handler<cryptonote::core> cprotocol(ccore, NULL); - nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > p2psrv { - cprotocol - , testnet_mode ? std::move(config::testnet::NETWORK_ID) : std::move(config::NETWORK_ID) - }; - cryptonote::core_rpc_server rpc_server {ccore, p2psrv, testnet_mode}; - cprotocol.set_p2p_endpoint(&p2psrv); - ccore.set_cryptonote_protocol(&cprotocol); - std::shared_ptr<daemon_cmmands_handler> dch(new daemon_cmmands_handler(p2psrv, testnet_mode)); - if(command_line::has_arg(vm, arg_save_graph)) - p2psrv.set_save_graph(true); - - epee::g_test_dbg_lock_sleep = command_line::get_arg(vm, test_dbg_lock_sleep); - - //initialize core here - LOG_PRINT_L0("Initializing core..."); - res = ccore.init(vm, testnet_mode); - CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); - if (command_line::get_arg(vm, arg_test_drop_download)) - ccore.test_drop_download(); - - ccore.test_drop_download_height(command_line::get_arg(vm, arg_test_drop_download_height)); - LOG_PRINT_L0("Core initialized OK"); - - //initialize objects - LOG_PRINT_L0("Initializing P2P server..."); - res = p2psrv.init(vm, testnet_mode); - CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize P2P server."); - LOG_PRINT_L0("P2P server initialized OK"); - - LOG_PRINT_L0("Initializing protocol..."); - res = cprotocol.init(vm); - CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize protocol."); - LOG_PRINT_L0("Protocol initialized OK"); - - LOG_PRINT_L0("Initializing core RPC server..."); - res = rpc_server.init(vm); - CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core RPC server."); - LOG_PRINT_GREEN("Core RPC server initialized OK on port: " << rpc_server.get_binded_port(), LOG_LEVEL_0); - - // start components - if(!command_line::has_arg(vm, arg_console)) +void t_daemon::stop() +{ + if (nullptr == mp_internals) { - dch->start_handling(); + throw std::runtime_error{"Can't stop stopped daemon"}; } - - LOG_PRINT_L0("Starting core RPC server..."); - res = rpc_server.run(2, false); - CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core RPC server."); - LOG_PRINT_L0("Core RPC server started ok"); - - tools::signal_handler::install([&dch, &p2psrv] { - dch->stop_handling(); - p2psrv.send_stop_signal(); - }); - - LOG_PRINT_L0("Starting P2P net loop..."); - p2psrv.run(); - LOG_PRINT_L0("P2P net loop stopped"); - - //stop components - dch->stop_handling(); - dch.reset(); - LOG_PRINT_L0("Stopping core rpc server..."); - rpc_server.send_stop_signal(); - rpc_server.timed_wait_server_stop(5000); - - //deinitialize components - LOG_PRINT_L0("Deinitializing core..."); - ccore.deinit(); - LOG_PRINT_L0("Deinitializing RPC server ..."); - rpc_server.deinit(); - LOG_PRINT_L0("Deinitializing protocol..."); - cprotocol.deinit(); - LOG_PRINT_L0("Deinitializing P2P..."); - p2psrv.deinit(); - - - ccore.set_cryptonote_protocol(NULL); - cprotocol.set_p2p_endpoint(NULL); - - epee::net_utils::data_logger::kill_instance(); - LOG_PRINT("Node stopped.", LOG_LEVEL_0); - return 0; - - CATCH_ENTRY_L0("main", 1); + mp_internals->p2p.stop(); + mp_internals->rpc.stop(); + mp_internals.reset(nullptr); // Ensure resources are cleaned up before we return } +} // namespace daemonize diff --git a/src/daemon/daemon.h b/src/daemon/daemon.h new file mode 100644 index 000000000..b0869b25b --- /dev/null +++ b/src/daemon/daemon.h @@ -0,0 +1,54 @@ +// 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. + +#pragma once + +#include <memory> +#include <boost/program_options.hpp> + +namespace daemonize { + +class t_internals; + +class t_daemon final { +public: + static void init_options(boost::program_options::options_description & option_spec); +private: + std::unique_ptr<t_internals> mp_internals; +public: + t_daemon( + boost::program_options::variables_map const & vm + ); + t_daemon(t_daemon && other); + t_daemon & operator=(t_daemon && other); + ~t_daemon(); + + bool run(bool interactive = false); + void stop(); +}; +} diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index c23df0443..7baca596d 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -1,35 +1,7 @@ -// Copyright (c) 2014-2015, 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. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - - -/* This isn't a header file, may want to refactor this... */ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include <boost/lexical_cast.hpp> @@ -42,21 +14,18 @@ #include "version.h" #include "../../contrib/otshell_utils/utils.hpp" -/*! - * \brief I don't really know right now - * - * - */ +//#include "net/net_helper.h" +//#include "../p2p/p2p_protocol_defs.h" +//#include "../p2p/net_peerlist_boost_serialization.h" +//#include "net/local_ip.h" +//#include "crypto/crypto.h" +//#include "storages/levin_abstract_invoke2.h" + class daemon_cmmands_handler { nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_srv; public: - daemon_cmmands_handler( - nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& srv - , bool testnet - ) - : m_srv(srv) - , m_testnet(testnet) + daemon_cmmands_handler(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& srv):m_srv(srv) { m_cmd_binder.set_handler("help", boost::bind(&daemon_cmmands_handler::help, this, _1), "Show this help"); m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_cmmands_handler::print_pl, this, _1), "Print peer list"); @@ -75,14 +44,10 @@ public: m_cmd_binder.set_handler("save", boost::bind(&daemon_cmmands_handler::save, this, _1), "Save blockchain"); m_cmd_binder.set_handler("set_log", boost::bind(&daemon_cmmands_handler::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4"); m_cmd_binder.set_handler("diff", boost::bind(&daemon_cmmands_handler::diff, this, _1), "Show difficulty"); + m_cmd_binder.set_handler("limit-up", boost::bind(&daemon_cmmands_handler::limit_up, this, _1), "Set upload limit"); + m_cmd_binder.set_handler("limit-down", boost::bind(&daemon_cmmands_handler::limit_down, this, _1), "Set download limit"); + m_cmd_binder.set_handler("limit", boost::bind(&daemon_cmmands_handler::limit, this, _1), "Set download and upload limit"); m_cmd_binder.set_handler("out_peers", boost::bind(&daemon_cmmands_handler::out_peers_limit, this, _1), "Set max limit of out peers"); - m_cmd_binder.set_handler("limit_up", boost::bind(&daemon_cmmands_handler::limit_up, this, _1), "Set upload limit [kB/s]"); - m_cmd_binder.set_handler("limit_down", boost::bind(&daemon_cmmands_handler::limit_down, this, _1), "Set download limit [kB/s]"); - m_cmd_binder.set_handler("limit", boost::bind(&daemon_cmmands_handler::limit, this, _1), "Set download and upload limit [kB/s]"); - m_cmd_binder.set_handler("fast_exit", boost::bind(&daemon_cmmands_handler::fast_exit, this, _1), "Exit"); - m_cmd_binder.set_handler("test_drop_download", boost::bind(&daemon_cmmands_handler::test_drop_download, this, _1), "For network testing, drop downloaded blocks instead checking/adding them to blockchain. Can fake-download blocks very fast."); - m_cmd_binder.set_handler("start_save_graph", boost::bind(&daemon_cmmands_handler::start_save_graph, this, _1), ""); - m_cmd_binder.set_handler("stop_save_graph", boost::bind(&daemon_cmmands_handler::stop_save_graph, this, _1), ""); } bool start_handling() @@ -98,7 +63,7 @@ public: private: epee::srv_console_handlers_binder<nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > > m_cmd_binder; - bool m_testnet; + //-------------------------------------------------------------------------------- std::string get_commands_str() @@ -131,6 +96,122 @@ private: 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 out_peers_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; + } + + LOG_PRINT_RED_L0("connections_count: " << limit); + m_srv.m_config.m_net_config.connections_count = limit; + return true; + } + //-------------------------------------------------------------------------------- bool show_hr(const std::vector<std::string>& args) { if(!m_srv.get_payload_object().get_core().get_miner().is_mining()) @@ -243,9 +324,11 @@ private: return true; } + // TODO what the hell causes compilation warning in following code line +PUSH_WARNINGS +DISABLE_GCC_WARNING(maybe-uninitialized) log_space::log_singletone::get_set_log_detalisation_level(true, l); - int otshell_utils_log_level = 100 - (l * 25); - gCurrentLogger.setDebugLevel(otshell_utils_log_level); +POP_WARNINGS return true; } @@ -385,7 +468,7 @@ private: } cryptonote::account_public_address adr; - if(!cryptonote::get_account_address_from_str(adr, m_testnet, args.front())) + if(!cryptonote::get_account_address_from_str(adr, args.front())) { std::cout << "target account address has wrong format" << std::endl; return true; diff --git a/src/daemon/executor.cpp b/src/daemon/executor.cpp new file mode 100644 index 000000000..bb188c174 --- /dev/null +++ b/src/daemon/executor.cpp @@ -0,0 +1,71 @@ +// 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 "daemon/executor.h" + +#include "misc_log_ex.h" + +#include "common/command_line.h" +#include "cryptonote_config.h" +#include "version.h" + +#include <string> + +namespace daemonize +{ + std::string const t_executor::NAME = "Monero Daemon"; + + void t_executor::init_options( + boost::program_options::options_description & configurable_options + ) + { + t_daemon::init_options(configurable_options); + } + + std::string const & t_executor::name() + { + return NAME; + } + + t_daemon t_executor::create_daemon( + boost::program_options::variables_map const & vm + ) + { + LOG_PRINT_L0(CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL); + return t_daemon{vm}; + } + + bool t_executor::run_interactive( + boost::program_options::variables_map const & vm + ) + { + epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + return t_daemon{vm}.run(true); + } +} + diff --git a/src/daemon/executor.h b/src/daemon/executor.h new file mode 100644 index 000000000..553896875 --- /dev/null +++ b/src/daemon/executor.h @@ -0,0 +1,60 @@ +// 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. + +#pragma once + +#include "daemon/daemon.h" +#include <boost/program_options/options_description.hpp> +#include <boost/program_options/variables_map.hpp> +#include <string> +#include <vector> + +namespace daemonize +{ + class t_executor final + { + public: + typedef ::daemonize::t_daemon t_daemon; + + static std::string const NAME; + + static void init_options( + boost::program_options::options_description & configurable_options + ); + + std::string const & name(); + + t_daemon create_daemon( + boost::program_options::variables_map const & vm + ); + + bool run_interactive( + boost::program_options::variables_map const & vm + ); + }; +} diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp new file mode 100644 index 000000000..5d8baf497 --- /dev/null +++ b/src/daemon/main.cpp @@ -0,0 +1,238 @@ +// 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "common/command_line.h" +#include "common/scoped_message_writer.h" +#include "common/util.h" +#include "cryptonote_core/cryptonote_core.h" +#include "cryptonote_core/miner.h" +#include "daemon/command_server.h" +#include "daemon/daemon.h" +#include "daemon/executor.h" +#include "daemonizer/daemonizer.h" +#include "misc_log_ex.h" +#include "p2p/net_node.h" +#include "rpc/core_rpc_server.h" +#include <boost/program_options.hpp> +#include "daemon/command_line_args.h" + +namespace po = boost::program_options; +namespace bf = boost::filesystem; + +int main(int argc, char const * argv[]) +{ + try { + + epee::string_tools::set_module_name_and_folder(argv[0]); + + // Build argument description + po::options_description all_options("All"); + po::options_description hidden_options("Hidden"); + po::options_description visible_options("Options"); + po::options_description core_settings("Settings"); + po::positional_options_description positional_options; + { + bf::path default_data_dir = daemonizer::get_default_data_dir(); + bf::path default_testnet_data_dir = {default_data_dir / "testnet"}; + + // Misc Options + + command_line::add_arg(visible_options, command_line::arg_help); + command_line::add_arg(visible_options, command_line::arg_version); + command_line::add_arg(visible_options, daemon_args::arg_os_version); + command_line::add_arg(visible_options, command_line::arg_data_dir, default_data_dir.string()); + command_line::add_arg(visible_options, command_line::arg_testnet_data_dir, default_testnet_data_dir.string()); + bf::path default_conf = default_data_dir / std::string(CRYPTONOTE_NAME ".conf"); + command_line::add_arg(visible_options, daemon_args::arg_config_file, default_conf.string()); + + // Settings + bf::path default_log = default_data_dir / std::string(CRYPTONOTE_NAME ".log"); + command_line::add_arg(core_settings, daemon_args::arg_log_file, default_log.string()); + command_line::add_arg(core_settings, daemon_args::arg_log_level); + command_line::add_arg(core_settings, daemon_args::arg_testnet_on); + command_line::add_arg(core_settings, daemon_args::arg_dns_checkpoints); + daemonizer::init_options(hidden_options, visible_options); + daemonize::t_executor::init_options(core_settings); + + // Hidden options + command_line::add_arg(hidden_options, daemon_args::arg_command); + + visible_options.add(core_settings); + all_options.add(visible_options); + all_options.add(hidden_options); + + // Positional + positional_options.add(daemon_args::arg_command.name, -1); // -1 for unlimited arguments + } + + // Do command line parsing + po::variables_map vm; + bool ok = command_line::handle_error_helper(visible_options, [&]() + { + boost::program_options::store( + boost::program_options::command_line_parser(argc, argv) + .options(all_options).positional(positional_options).run() + , vm + ); + + return true; + }); + if (!ok) return 1; + + if (command_line::get_arg(vm, command_line::arg_help)) + { + std::cout << CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL << ENDL << ENDL; + std::cout << "Usage: " + std::string{argv[0]} + " [options|settings] [daemon_command...]" << std::endl << std::endl; + std::cout << visible_options << std::endl; + return 0; + } + + // Monero Version + if (command_line::get_arg(vm, command_line::arg_version)) + { + std::cout << CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL << ENDL; + return 0; + } + + // OS + if (command_line::get_arg(vm, daemon_args::arg_os_version)) + { + std::cout << "OS: " << tools::get_os_version_string() << ENDL; + return 0; + } + + bool testnet_mode = command_line::get_arg(vm, daemon_args::arg_testnet_on); + + auto data_dir_arg = testnet_mode ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; + + // Create data dir if it doesn't exist + boost::filesystem::path data_dir = boost::filesystem::absolute( + command_line::get_arg(vm, data_dir_arg)); + tools::create_directories_if_necessary(data_dir.string()); + + // FIXME: not sure on windows implementation default, needs further review + //bf::path relative_path_base = daemonizer::get_relative_path_base(vm); + bf::path relative_path_base = data_dir; + + std::string config = command_line::get_arg(vm, daemon_args::arg_config_file); + + boost::filesystem::path data_dir_path(data_dir); + boost::filesystem::path config_path(config); + if (!config_path.has_parent_path()) + { + config_path = data_dir / config_path; + } + + boost::system::error_code ec; + if (bf::exists(config_path, ec)) + { + po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), core_settings), vm); + } + po::notify(vm); + + // If there are positional options, we're running a daemon command + { + auto command = command_line::get_arg(vm, daemon_args::arg_command); + + if (command.size()) + { + auto rpc_ip_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_ip); + auto rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port); + if (testnet_mode) + { + rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_testnet_rpc_bind_port); + } + + uint32_t rpc_ip; + uint16_t rpc_port; + if (!epee::string_tools::get_ip_int32_from_string(rpc_ip, rpc_ip_str)) + { + std::cerr << "Invalid IP: " << rpc_ip_str << std::endl; + return 1; + } + if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str)) + { + std::cerr << "Invalid port: " << rpc_port_str << std::endl; + return 1; + } + + daemonize::t_command_server rpc_commands{rpc_ip, rpc_port}; + if (rpc_commands.process_command_vec(command)) + { + return 0; + } + else + { + std::cerr << "Unknown command" << std::endl; + return 1; + } + } + } + + // Start with log level 0 + epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); + + // Set log level + { + int new_log_level = command_line::get_arg(vm, daemon_args::arg_log_level); + if(new_log_level < LOG_LEVEL_MIN || new_log_level > LOG_LEVEL_MAX) + { + LOG_PRINT_L0("Wrong log level value: " << new_log_level); + } + else if (epee::log_space::get_set_log_detalisation_level(false) != new_log_level) + { + epee::log_space::get_set_log_detalisation_level(true, new_log_level); + LOG_PRINT_L0("LOG_LEVEL set to " << new_log_level); + } + } + + // Set log file + { + bf::path log_file_path{bf::absolute(command_line::get_arg(vm, daemon_args::arg_log_file), relative_path_base)}; + + epee::log_space::log_singletone::add_logger( + LOGGER_FILE + , log_file_path.filename().string().c_str() + , log_file_path.parent_path().string().c_str() + ); + } + + return daemonizer::daemonize(argc, argv, daemonize::t_executor{}, vm); + } + catch (std::exception const & ex) + { + LOG_ERROR("Exception in main! " << ex.what()); + } + catch (...) + { + LOG_ERROR("Exception in main!"); + } + return 1; +} diff --git a/src/daemon/p2p.h b/src/daemon/p2p.h new file mode 100644 index 000000000..355a784b1 --- /dev/null +++ b/src/daemon/p2p.h @@ -0,0 +1,99 @@ +// 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include "cryptonote_protocol/cryptonote_protocol_handler.h" +#include "daemon/protocol.h" +#include "misc_log_ex.h" +#include "p2p/net_node.h" +#include <stdexcept> +#include <boost/program_options.hpp> + +namespace daemonize +{ + +class t_p2p final +{ +private: + typedef cryptonote::t_cryptonote_protocol_handler<cryptonote::core> t_protocol_raw; + typedef nodetool::node_server<t_protocol_raw> t_node_server; +public: + static void init_options(boost::program_options::options_description & option_spec) + { + t_node_server::init_options(option_spec); + } +private: + t_node_server m_server; +public: + t_p2p( + boost::program_options::variables_map const & vm + , t_protocol & protocol + ) + : m_server{protocol.get()} + { + //initialize objects + LOG_PRINT_L0("Initializing p2p server..."); + if (!m_server.init(vm)) + { + throw std::runtime_error("Failed to initialize p2p server."); + } + LOG_PRINT_L0("P2p server initialized OK"); + } + + t_node_server & get() + { + return m_server; + } + + void run() + { + LOG_PRINT_L0("Starting p2p net loop..."); + m_server.run(); + LOG_PRINT_L0("p2p net loop stopped"); + } + + void stop() + { + m_server.send_stop_signal(); + } + + ~t_p2p() + { + LOG_PRINT_L0("Deinitializing p2p..."); + try { + m_server.deinit(); + } catch (...) { + LOG_PRINT_L0("Failed to deinitialize p2p..."); + } + } +}; + +} diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h new file mode 100644 index 000000000..2f6a66f49 --- /dev/null +++ b/src/daemon/protocol.h @@ -0,0 +1,88 @@ +// 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include "cryptonote_protocol/cryptonote_protocol_handler.h" +#include "misc_log_ex.h" +#include "p2p/net_node.h" +#include <stdexcept> +#include <boost/program_options.hpp> + +namespace daemonize +{ + +class t_protocol final +{ +private: + typedef cryptonote::t_cryptonote_protocol_handler<cryptonote::core> t_protocol_raw; + typedef nodetool::node_server<t_protocol_raw> t_node_server; + + t_protocol_raw m_protocol; +public: + t_protocol( + boost::program_options::variables_map const & vm + , t_core & core + ) + : m_protocol{core.get(), nullptr} + { + LOG_PRINT_L0("Initializing cryptonote protocol..."); + if (!m_protocol.init(vm)) + { + throw std::runtime_error("Failed to initialize cryptonote protocol."); + } + LOG_PRINT_L0("Cryptonote protocol initialized OK"); + } + + t_protocol_raw & get() + { + return m_protocol; + } + + void set_p2p_endpoint( + t_node_server & server + ) + { + m_protocol.set_p2p_endpoint(&server); + } + + ~t_protocol() + { + LOG_PRINT_L0("Deinitializing cryptonote_protocol..."); + try { + m_protocol.deinit(); + m_protocol.set_p2p_endpoint(nullptr); + } catch (...) { + LOG_PRINT_L0("Failed to deinitialize protocol..."); + } + } +}; + +} diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h new file mode 100644 index 000000000..6477f440e --- /dev/null +++ b/src/daemon/rpc.h @@ -0,0 +1,101 @@ +// 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include "daemon/core.h" +#include "daemon/p2p.h" +#include "misc_log_ex.h" +#include "rpc/core_rpc_server.h" +#include <boost/program_options.hpp> +#include <stdexcept> + +namespace daemonize +{ + +class t_rpc final +{ +public: + static void init_options(boost::program_options::options_description & option_spec) + { + cryptonote::core_rpc_server::init_options(option_spec); + } +private: + cryptonote::core_rpc_server m_server; +public: + t_rpc( + boost::program_options::variables_map const & vm + , t_core & core + , t_p2p & p2p + ) + : m_server{core.get(), p2p.get()} + { + LOG_PRINT_L0("Initializing core rpc server..."); + if (!m_server.init(vm)) + { + throw std::runtime_error("Failed to initialize core rpc server."); + } + LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_server.get_binded_port(), LOG_LEVEL_0); + } + + void run() + { + LOG_PRINT_L0("Starting core rpc server..."); + if (!m_server.run(2, false)) + { + throw std::runtime_error("Failed to start core rpc server."); + } + LOG_PRINT_L0("Core rpc server started ok"); + } + + void stop() + { + LOG_PRINT_L0("Stopping core rpc server..."); + m_server.send_stop_signal(); + m_server.timed_wait_server_stop(5000); + } + + cryptonote::core_rpc_server* get_server() + { + return &m_server; + } + + ~t_rpc() + { + LOG_PRINT_L0("Deinitializing rpc server..."); + try { + m_server.deinit(); + } catch (...) { + LOG_PRINT_L0("Failed to deinitialize rpc server..."); + } + } +}; + +} diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp new file mode 100644 index 000000000..f06f48544 --- /dev/null +++ b/src/daemon/rpc_command_executor.cpp @@ -0,0 +1,692 @@ +// 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "string_tools.h" +#include "common/scoped_message_writer.h" +#include "daemon/rpc_command_executor.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include <boost/format.hpp> +#include <ctime> + +namespace daemonize { + +namespace { + void print_peer(std::string const & prefix, cryptonote::peer const & peer) + { + time_t now; + time(&now); + time_t last_seen = static_cast<time_t>(peer.last_seen); + + std::string id_str; + std::string port_str; + std::string elapsed = epee::misc_utils::get_time_interval_string(now - last_seen); + std::string ip_str = epee::string_tools::get_ip_string_from_int32(peer.ip); + epee::string_tools::xtype_to_string(peer.id, id_str); + epee::string_tools::xtype_to_string(peer.port, port_str); + std::string addr_str = ip_str + ":" + port_str; + tools::msg_writer() << boost::format("%-10s %-25s %-25s %s") % prefix % id_str % addr_str % elapsed; + } + + void print_block_header(cryptonote::block_header_responce const & header) + { + tools::success_msg_writer() + << "timestamp: " << boost::lexical_cast<std::string>(header.timestamp) << std::endl + << "previous hash: " << header.prev_hash << std::endl + << "nonce: " << boost::lexical_cast<std::string>(header.nonce) << std::endl + << "is orphan: " << header.orphan_status << std::endl + << "height: " << boost::lexical_cast<std::string>(header.height) << std::endl + << "depth: " << boost::lexical_cast<std::string>(header.depth) << std::endl + << "hash: " << header.hash + << "difficulty: " << boost::lexical_cast<std::string>(header.difficulty) << std::endl + << "reward: " << boost::lexical_cast<std::string>(header.reward); + } +} + +t_rpc_command_executor::t_rpc_command_executor( + uint32_t ip + , uint16_t port + , bool is_rpc + , cryptonote::core_rpc_server* rpc_server + ) + : m_rpc_client(NULL), m_rpc_server(rpc_server) +{ + if (is_rpc) + { + m_rpc_client = new tools::t_rpc_client(ip, port); + } + else + { + if (rpc_server == NULL) + { + throw std::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null"); + } + } + + m_is_rpc = is_rpc; +} + +t_rpc_command_executor::~t_rpc_command_executor() +{ + if (m_rpc_client != NULL) + { + delete m_rpc_client; + } +} + +bool t_rpc_command_executor::print_peer_list() { + cryptonote::COMMAND_RPC_GET_PEER_LIST::request req; + cryptonote::COMMAND_RPC_GET_PEER_LIST::response res; + + std::string failure_message = "Couldn't retrieve peer list"; + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_peer_list", failure_message.c_str())) + { + return false; + } + } + else + { + if (!m_rpc_server->on_get_peer_list(req, res)) + { + tools::fail_msg_writer() << failure_message; + return false; + } + } + + for (auto & peer : res.white_list) + { + print_peer("white", peer); + } + + for (auto & peer : res.gray_list) + { + print_peer("gray", peer); + } + + return true; +} + +bool t_rpc_command_executor::save_blockchain() { + cryptonote::COMMAND_RPC_SAVE_BC::request req; + cryptonote::COMMAND_RPC_SAVE_BC::response res; + + std::string fail_message = "Couldn't save blockchain"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/save_bc", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_save_bc(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + } + } + + tools::success_msg_writer() << "Blockchain saved"; + + return true; +} + +bool t_rpc_command_executor::show_hash_rate() { + cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::request req; + cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::response res; + req.visible = true; + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/set_log_hash_rate", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_set_log_hash_rate(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + } + } + + tools::success_msg_writer() << "Hash rate logging is on"; + + return true; +} + +bool t_rpc_command_executor::hide_hash_rate() { + cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::request req; + cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::response res; + req.visible = false; + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/set_log_hash_rate", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_set_log_hash_rate(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + tools::success_msg_writer() << "Hash rate logging is off"; + + return true; +} + +bool t_rpc_command_executor::show_difficulty() { + cryptonote::COMMAND_RPC_GET_INFO::request req; + cryptonote::COMMAND_RPC_GET_INFO::response res; + + std::string fail_message = "Problem fetching info"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/getinfo", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_info(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + tools::success_msg_writer() << "BH: " << res.height + << ", DIFF: " << res.difficulty + << ", HR: " << (int) res.difficulty / 60L << " H/s"; + + return true; +} + +bool t_rpc_command_executor::print_connections() { + cryptonote::COMMAND_RPC_GET_CONNECTIONS::request req; + cryptonote::COMMAND_RPC_GET_CONNECTIONS::response res; + epee::json_rpc::error error_resp; + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "/get_connections", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_connections(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + for (auto & info : res.connections) + { + std::string address = info.ip + ":" + info.port; + std::string in_out = info.incoming ? "INC" : "OUT"; + tools::msg_writer() << boost::format("%-25s peer_id: %-25s %s") % address % info.peer_id % in_out; + } + + return true; +} + +bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index) { + +// this function appears to not exist in the json rpc api, and so is commented +// until such a time as it does. + +/* + cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request req; + cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response res; + epee::json_rpc::error error_resp; + + req.start_height = start_block_index; + req.end_height = end_block_index; + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "getblockheadersrange", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_getblockheadersrange(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + for (auto & header : res.headers) + { + std::cout + << "major version: " << header.major_version << std::endl + << "minor version: " << header.minor_version << std::endl + << "height: " << header.height << ", timestamp: " << header.timestamp << ", difficulty: " << header.difficulty << std::endl + << "block id: " << header.hash << std::endl + << "previous block id: " << header.prev_hash << std::endl + << "difficulty: " << header.difficulty << ", nonce " << header.nonce << std::endl; + } + +*/ + return true; +} + +bool t_rpc_command_executor::set_log_level(int8_t level) { + cryptonote::COMMAND_RPC_SET_LOG_LEVEL::request req; + cryptonote::COMMAND_RPC_SET_LOG_LEVEL::response res; + req.level = level; + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/set_log_level", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_set_log_level(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + tools::success_msg_writer() << "Log level is now " << boost::lexical_cast<std::string>(level); + + return true; +} + +bool t_rpc_command_executor::print_height() { + cryptonote::COMMAND_RPC_GET_HEIGHT::request req; + cryptonote::COMMAND_RPC_GET_HEIGHT::response res; + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/getheight", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_height(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + tools::success_msg_writer() << boost::lexical_cast<std::string>(res.height); + + return true; +} + +bool t_rpc_command_executor::print_block_by_hash(crypto::hash block_hash) { + cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request req; + cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response res; + epee::json_rpc::error error_resp; + + req.hash = epee::string_tools::pod_to_hex(block_hash); + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "getblockheaderbyhash", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_block_header_by_hash(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + print_block_header(res.block_header); + + return true; +} + +bool t_rpc_command_executor::print_block_by_height(uint64_t height) { + cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request req; + cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response res; + epee::json_rpc::error error_resp; + + req.height = height; + + std::string fail_message = "Unsuccessful"; + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "getblockheaderbyheight", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_block_header_by_height(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + print_block_header(res.block_header); + + return true; +} + +bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { + cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req; + cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res; + + std::string fail_message = "Problem fetching transaction"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/gettransactions", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_transactions(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + if (1 == res.txs_as_hex.size()) + { + tools::success_msg_writer() << res.txs_as_hex.front(); + } + else + { + tools::fail_msg_writer() << "transaction wasn't found: <" << transaction_hash << '>' << std::endl; + } + + return true; +} + +bool t_rpc_command_executor::print_transaction_pool_long() { + cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req; + cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res; + + std::string fail_message = "Problem fetching transaction pool"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_transaction_pool", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_transaction_pool(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + if (res.transactions.empty()) + { + tools::msg_writer() << "Pool is empty" << std::endl; + } + for (auto & tx_info : res.transactions) + { + tools::msg_writer() << "id: " << tx_info.id_hash << std::endl + << "blob_size: " << tx_info.blob_size << std::endl + << "fee: " << tx_info.fee << std::endl + << "kept_by_block: " << tx_info.kept_by_block << std::endl + << "max_used_block_height: " << tx_info.max_used_block_height << std::endl + << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl + << "last_failed_height: " << tx_info.last_failed_height << std::endl + << "last_failed_id: " << tx_info.last_failed_id_hash << std::endl; + } + + return true; +} + +bool t_rpc_command_executor::print_transaction_pool_short() { + cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req; + cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res; + + std::string fail_message = "Problem fetching transaction pool"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_transaction_pool", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_transaction_pool(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + if (res.transactions.empty()) + { + tools::msg_writer() << "Pool is empty" << std::endl; + } + for (auto & tx_info : res.transactions) + { + tools::msg_writer() << "id: " << tx_info.id_hash << std::endl + << tx_info.tx_json << std::endl + << "blob_size: " << tx_info.blob_size << std::endl + << "fee: " << tx_info.fee << std::endl + << "kept_by_block: " << tx_info.kept_by_block << std::endl + << "max_used_block_height: " << tx_info.max_used_block_height << std::endl + << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl + << "last_failed_height: " << tx_info.last_failed_height << std::endl + << "last_failed_id: " << tx_info.last_failed_id_hash << std::endl; + } + + return true; +} + +// TODO: update this for testnet +bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads) { + cryptonote::COMMAND_RPC_START_MINING::request req; + cryptonote::COMMAND_RPC_START_MINING::response res; + req.miner_address = cryptonote::get_account_address_as_str(false, address); + req.threads_count = num_threads; + + if (m_rpc_client->rpc_request(req, res, "/start_mining", "Mining did not start")) + { + tools::success_msg_writer() << "Mining started"; + } + return true; +} + +bool t_rpc_command_executor::stop_mining() { + cryptonote::COMMAND_RPC_STOP_MINING::request req; + cryptonote::COMMAND_RPC_STOP_MINING::response res; + + std::string fail_message = "Mining did not stop"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/stop_mining", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_stop_mining(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + tools::success_msg_writer() << "Mining stopped"; + return true; +} + +bool t_rpc_command_executor::stop_daemon() +{ + cryptonote::COMMAND_RPC_STOP_DAEMON::request req; + cryptonote::COMMAND_RPC_STOP_DAEMON::response res; + +//# ifdef WIN32 +// // Stop via service API +// // TODO - this is only temporary! Get rid of hard-coded constants! +// bool ok = windows::stop_service("BitMonero Daemon"); +// ok = windows::uninstall_service("BitMonero Daemon"); +// //bool ok = windows::stop_service(SERVICE_NAME); +// //ok = windows::uninstall_service(SERVICE_NAME); +// if (ok) +// { +// return true; +// } +//# endif + + // Stop via RPC + std::string fail_message = "Daemon did not stop"; + + if (m_is_rpc) + { + if(!m_rpc_client->rpc_request(req, res, "/stop_daemon", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_stop_daemon(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + tools::success_msg_writer() << "Stop signal sent"; + + return true; +} + +bool t_rpc_command_executor::print_status() +{ + if (!m_is_rpc) + { + tools::success_msg_writer() << "print_status makes no sense in interactive mode"; + return true; + } + + bool daemon_is_alive = m_rpc_client->check_connection(); + + if(daemon_is_alive) { + tools::success_msg_writer() << "bitmonerod is running"; + } + else { + tools::fail_msg_writer() << "bitmonerod is NOT running"; + } + + return true; +} + +bool t_rpc_command_executor::set_limit(int 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 t_rpc_command_executor::set_limit_up(int 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 t_rpc_command_executor::set_limit_down(int 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; +} + +}// namespace daemonize diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h new file mode 100644 index 000000000..fe0181e62 --- /dev/null +++ b/src/daemon/rpc_command_executor.h @@ -0,0 +1,111 @@ +/** +@file +@details + +@image html images/other/runtime-commands.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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include "common/rpc_client.h" +#include "misc_log_ex.h" +#include "cryptonote_core/cryptonote_core.h" +#include "cryptonote_protocol/cryptonote_protocol_handler.h" +#include "p2p/net_node.h" +#include "rpc/core_rpc_server.h" + +namespace daemonize { + +class t_rpc_command_executor final { +private: + tools::t_rpc_client* m_rpc_client; + cryptonote::core_rpc_server* m_rpc_server; + bool m_is_rpc; + +public: + t_rpc_command_executor( + uint32_t ip + , uint16_t port + , bool is_rpc = true + , cryptonote::core_rpc_server* rpc_server = NULL + ); + + ~t_rpc_command_executor(); + + bool print_peer_list(); + + bool save_blockchain(); + + bool show_hash_rate(); + + bool hide_hash_rate(); + + bool show_difficulty(); + + bool print_connections(); + + bool print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index); + + bool set_log_level(int8_t level); + + bool print_height(); + + bool print_block_by_hash(crypto::hash block_hash); + + bool print_block_by_height(uint64_t height); + + bool print_transaction(crypto::hash transaction_hash); + + bool print_transaction_pool_long(); + + bool print_transaction_pool_short(); + + bool start_mining(cryptonote::account_public_address address, uint64_t num_threads); + + bool stop_mining(); + + bool stop_daemon(); + + bool print_status(); + + bool set_limit(int limit); + + bool set_limit_up(int limit); + + bool set_limit_down(int limit); + + +}; + +} // namespace daemonize |