Daemonize changes pulled in -- daemon builds

many RPC functions added by the daemonize changes
(and related changes on the upstream dev branch that were not merged)
were commented out (apart from return).  Other than that, this *should*
work...at any rate, it builds, and that's something.
This commit is contained in:
Thomas Winget 2015-01-29 17:10:53 -05:00
parent 6e5797dc11
commit 9193d6fb5b
No known key found for this signature in database
GPG key ID: 58131A160789E630
39 changed files with 3672 additions and 387 deletions

View file

@ -26,11 +26,13 @@
#pragma once #pragma once
#include "misc_log_ex.h"
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <iostream>
namespace epee namespace epee
{ {
@ -290,7 +292,7 @@ namespace epee
private: private:
async_stdin_reader m_stdin_reader; async_stdin_reader m_stdin_reader;
bool m_running = true; std::atomic<bool> m_running = {true};
}; };
@ -350,17 +352,11 @@ namespace epee
return true; return true;
}*/ }*/
/************************************************************************/ class command_handler {
/* */
/************************************************************************/
class console_handlers_binder
{
typedef boost::function<bool (const std::vector<std::string> &)> console_command_handler;
typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map;
std::unique_ptr<boost::thread> m_console_thread;
command_handlers_map m_command_handlers;
async_console_handler m_console_handler;
public: public:
typedef boost::function<bool (const std::vector<std::string> &)> callback;
typedef std::map<std::string, std::pair<callback, std::string> > lookup;
std::string get_usage() std::string get_usage()
{ {
std::stringstream ss; std::stringstream ss;
@ -376,12 +372,14 @@ namespace epee
} }
return ss.str(); return ss.str();
} }
void set_handler(const std::string& cmd, const console_command_handler& hndlr, const std::string& usage = "")
void set_handler(const std::string& cmd, const callback& hndlr, const std::string& usage = "")
{ {
command_handlers_map::mapped_type & vt = m_command_handlers[cmd]; lookup::mapped_type & vt = m_command_handlers[cmd];
vt.first = hndlr; vt.first = hndlr;
vt.second = usage; vt.second = usage;
} }
bool process_command_vec(const std::vector<std::string>& cmd) bool process_command_vec(const std::vector<std::string>& cmd)
{ {
if(!cmd.size()) if(!cmd.size())
@ -399,14 +397,20 @@ namespace epee
boost::split(cmd_v,cmd,boost::is_any_of(" "), boost::token_compress_on); boost::split(cmd_v,cmd,boost::is_any_of(" "), boost::token_compress_on);
return process_command_vec(cmd_v); return process_command_vec(cmd_v);
} }
private:
lookup m_command_handlers;
};
/*template<class t_srv> /************************************************************************/
bool start_handling(t_srv& srv, const std::string& usage_string = "") /* */
{ /************************************************************************/
start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1)); class console_handlers_binder : public command_handler
return true; {
}*/ typedef command_handler::callback console_command_handler;
typedef command_handler::lookup command_handlers_map;
std::unique_ptr<boost::thread> m_console_thread;
async_console_handler m_console_handler;
public:
bool start_handling(const std::string& prompt, const std::string& usage_string = "") bool start_handling(const std::string& prompt, const std::string& usage_string = "")
{ {
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string))); m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string)));
@ -423,40 +427,33 @@ namespace epee
{ {
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string); return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string);
} }
/*template<class t_srv>
bool run_handling(t_srv& srv, const std::string& usage_string)
{
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
}*/
}; };
/* work around because of broken boost bind */ ///* work around because of broken boost bind */
template<class t_server> //template<class t_server>
class srv_console_handlers_binder: public console_handlers_binder //class srv_console_handlers_binder: public command_handler
{ //{
bool process_command_str(t_server* /*psrv*/, const std::string& cmd) // async_console_handler m_console_handler;
{ //public:
return console_handlers_binder::process_command_str(cmd); // bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "")
} // {
public: // boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "") // return true;
{ // }
boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
return true;
}
bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string) // bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string)
{ // {
return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string); // return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string);
} // }
void stop_handling() // void stop_handling()
{ // {
m_console_handler.stop(); // m_console_handler.stop();
} // }
//private:
private: // bool process_command_str(t_server* /*psrv*/, const std::string& cmd)
async_console_handler m_console_handler; // {
}; // return console_handlers_binder::process_command_str(cmd);
// }
//};
} }

View file

@ -96,4 +96,5 @@ add_subdirectory(wallet)
add_subdirectory(connectivity_tool) add_subdirectory(connectivity_tool)
add_subdirectory(miner) add_subdirectory(miner)
add_subdirectory(simplewallet) add_subdirectory(simplewallet)
add_subdirectory(daemonizer)
add_subdirectory(daemon) add_subdirectory(daemon)

View file

@ -39,8 +39,11 @@ set(common_private_headers
boost_serialization_helper.h boost_serialization_helper.h
command_line.h command_line.h
dns_utils.h dns_utils.h
http_connection.h
int-util.h int-util.h
pod-class.h pod-class.h
rpc_client.h
scoped_message_writer.h
unordered_containers_boost_serialization.h unordered_containers_boost_serialization.h
util.h util.h
varint.h) varint.h)

View file

@ -0,0 +1,42 @@
#pragma once
#include "string_tools.h"
#include "net/http_client.h"
namespace tools {
class t_http_connection {
private:
epee::net_utils::http::http_simple_client * mp_http_client;
bool m_ok;
public:
static unsigned int const TIMEOUT = 200000;
t_http_connection(
epee::net_utils::http::http_simple_client * p_http_client
, uint32_t ip
, uint16_t port
)
: mp_http_client(p_http_client)
{
// TODO fix http client so that it accepts properly typed arguments
std::string ip_str = epee::string_tools::get_ip_string_from_int32(ip);
std::string port_str = boost::lexical_cast<std::string>(port);
m_ok = mp_http_client->connect(ip_str, port_str, TIMEOUT);
}
~t_http_connection()
{
if (m_ok)
{
mp_http_client->disconnect();
}
}
bool is_open()
{
return m_ok;
}
}; // class t_http_connection
} // namespace tools

132
src/common/rpc_client.h Normal file
View file

@ -0,0 +1,132 @@
#pragma once
#include "common/http_connection.h"
#include "common/scoped_message_writer.h"
#include "rpc/core_rpc_server_commands_defs.h"
#include "storages/http_abstract_invoke.h"
#include "net/http_client.h"
#include "string_tools.h"
#include <boost/lexical_cast.hpp>
namespace tools
{
class t_rpc_client final
{
private:
epee::net_utils::http::http_simple_client m_http_client;
uint32_t m_ip;
uint16_t m_port;
public:
t_rpc_client(
uint32_t ip
, uint16_t port
)
: m_http_client{}
, m_ip{ip}
, m_port{port}
{}
std::string build_url(std::string const & relative_url)
{
std::string result =
"http://"
+ epee::string_tools::get_ip_string_from_int32(m_ip)
+ ":"
+ boost::lexical_cast<std::string>(m_port)
+ relative_url;
return result;
}
template <typename T_req, typename T_res>
bool basic_json_rpc_request(
T_req & req
, T_res & res
, std::string const & method_name
)
{
std::string rpc_url = build_url("/json_rpc");
t_http_connection connection(&m_http_client, m_ip, m_port);
bool ok = connection.is_open();
if (!ok)
{
fail_msg_writer() << "Couldn't connect to daemon";
return false;
}
ok = ok && epee::net_utils::invoke_http_json_rpc(rpc_url, method_name, req, res, m_http_client);
if (!ok)
{
fail_msg_writer() << "Daemon request failed";
return false;
}
else
{
return true;
}
}
template <typename T_req, typename T_res>
bool json_rpc_request(
T_req & req
, T_res & res
, std::string const & method_name
, std::string const & fail_msg
)
{
std::string rpc_url = build_url("/json_rpc");
t_http_connection connection(&m_http_client, m_ip, m_port);
bool ok = connection.is_open();
ok = ok && epee::net_utils::invoke_http_json_rpc(rpc_url, method_name, req, res, m_http_client);
if (!ok)
{
fail_msg_writer() << "Couldn't connect to daemon";
return false;
}
else if (res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
{
fail_msg_writer() << fail_msg << " -- " << res.status;
return false;
}
else
{
return true;
}
}
template <typename T_req, typename T_res>
bool rpc_request(
T_req & req
, T_res & res
, std::string const & relative_url
, std::string const & fail_msg
)
{
std::string rpc_url = build_url(relative_url);
t_http_connection connection(&m_http_client, m_ip, m_port);
bool ok = connection.is_open();
ok = ok && epee::net_utils::invoke_http_json_remote_command2(rpc_url, req, res, m_http_client);
if (!ok)
{
fail_msg_writer() << "Couldn't connect to daemon";
return false;
}
else if (res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
{
fail_msg_writer() << fail_msg << " -- " << res.status;
return false;
}
else
{
return true;
}
}
bool check_connection()
{
t_http_connection connection(&m_http_client, m_ip, m_port);
return connection.is_open();
}
};
}

View file

@ -0,0 +1,95 @@
#pragma once
#include "misc_log_ex.h"
#include <iostream>
namespace tools
{
class scoped_message_writer
{
private:
bool m_flush;
std::stringstream m_oss;
epee::log_space::console_colors m_color;
bool m_bright;
int m_log_level;
public:
scoped_message_writer(
epee::log_space::console_colors color = epee::log_space::console_color_default
, bool bright = false
, std::string&& prefix = std::string()
, int log_level = LOG_LEVEL_2
)
: m_flush(true)
, m_color(color)
, m_bright(bright)
, m_log_level(log_level)
{
m_oss << prefix;
}
scoped_message_writer(scoped_message_writer&& rhs)
: m_flush(std::move(rhs.m_flush))
#if defined(_MSC_VER)
, m_oss(std::move(rhs.m_oss))
#else
// GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
, m_oss(rhs.m_oss.str(), std::ios_base::out | std::ios_base::ate)
#endif
, m_color(std::move(rhs.m_color))
, m_log_level(std::move(rhs.m_log_level))
{
rhs.m_flush = false;
}
scoped_message_writer(scoped_message_writer& rhs) = delete;
scoped_message_writer& operator=(scoped_message_writer& rhs) = delete;
scoped_message_writer& operator=(scoped_message_writer&& rhs) = delete;
template<typename T>
std::ostream& operator<<(const T& val)
{
m_oss << val;
return m_oss;
}
~scoped_message_writer()
{
if (m_flush)
{
m_flush = false;
LOG_PRINT(m_oss.str(), m_log_level)
if (epee::log_space::console_color_default == m_color)
{
std::cout << m_oss.str();
}
else
{
epee::log_space::set_console_color(m_color, m_bright);
std::cout << m_oss.str();
epee::log_space::reset_console_color();
}
std::cout << std::endl;
}
}
};
inline scoped_message_writer success_msg_writer()
{
return scoped_message_writer(epee::log_space::console_color_green, false, std::string(), LOG_LEVEL_2);
}
inline scoped_message_writer msg_writer(epee::log_space::console_colors color = epee::log_space::console_color_default)
{
return scoped_message_writer(color, false, std::string(), LOG_LEVEL_2);
}
inline scoped_message_writer fail_msg_writer()
{
return scoped_message_writer(epee::log_space::console_color_red, true, "Error: ", LOG_LEVEL_0);
}
} // namespace tools

View file

@ -42,6 +42,8 @@ using namespace epee;
#include "cryptonote_format_utils.h" #include "cryptonote_format_utils.h"
#include "misc_language.h" #include "misc_language.h"
#include <csignal> #include <csignal>
#include "daemon/command_line_args.h"
#include "cryptonote_core/checkpoints_create.h"
DISABLE_VS_WARNINGS(4355) DISABLE_VS_WARNINGS(4355)
@ -112,10 +114,32 @@ namespace cryptonote
{ {
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::handle_command_line(const boost::program_options::variables_map& vm, bool testnet) bool core::handle_command_line(const boost::program_options::variables_map& vm)
{ {
auto data_dir_arg = testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; m_testnet = command_line::get_arg(vm, daemon_args::arg_testnet_on);
auto data_dir_arg = m_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir;
m_config_folder = command_line::get_arg(vm, data_dir_arg); m_config_folder = command_line::get_arg(vm, data_dir_arg);
auto data_dir = boost::filesystem::path(m_config_folder);
if (!m_testnet)
{
cryptonote::checkpoints checkpoints;
if (!cryptonote::create_checkpoints(checkpoints))
{
throw std::runtime_error("Failed to initialize checkpoints");
}
set_checkpoints(std::move(checkpoints));
boost::filesystem::path json(JSON_HASH_FILE_NAME);
boost::filesystem::path checkpoint_json_hashfile_fullpath = data_dir / json;
set_checkpoints_file_path(checkpoint_json_hashfile_fullpath.string());
}
set_enforce_dns_checkpoints(command_line::get_arg(vm, daemon_args::arg_dns_checkpoints));
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
@ -154,21 +178,21 @@ namespace cryptonote
return m_blockchain_storage.get_alternative_blocks_count(); return m_blockchain_storage.get_alternative_blocks_count();
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::init(const boost::program_options::variables_map& vm, bool testnet) bool core::init(const boost::program_options::variables_map& vm)
{ {
bool r = handle_command_line(vm, testnet); bool r = handle_command_line(vm);
r = m_mempool.init(m_config_folder); r = m_mempool.init(m_config_folder);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool"); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
r = m_blockchain_storage.init(m_config_folder, testnet); r = m_blockchain_storage.init(m_config_folder, m_testnet);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
// load json & DNS checkpoints, and verify them // load json & DNS checkpoints, and verify them
// with respect to what blocks we already have // with respect to what blocks we already have
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints."); CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
r = m_miner.init(vm, testnet); r = m_miner.init(vm, m_testnet);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
return load_state_data(); return load_state_data();

View file

@ -72,7 +72,7 @@ namespace cryptonote
miner& get_miner(){return m_miner;} miner& get_miner(){return m_miner;}
static void init_options(boost::program_options::options_description& desc); static void init_options(boost::program_options::options_description& desc);
bool init(const boost::program_options::variables_map& vm, bool testnet); bool init(const boost::program_options::variables_map& vm);
bool set_genesis_block(const block& b); bool set_genesis_block(const block& b);
bool deinit(); bool deinit();
uint64_t get_current_blockchain_height(); uint64_t get_current_blockchain_height();
@ -142,7 +142,7 @@ namespace cryptonote
bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig); bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig);
bool is_tx_spendtime_unlocked(uint64_t unlock_time); bool is_tx_spendtime_unlocked(uint64_t unlock_time);
bool update_miner_block_template(); bool update_miner_block_template();
bool handle_command_line(const boost::program_options::variables_map& vm, bool testnet); bool handle_command_line(const boost::program_options::variables_map& vm);
bool on_update_blocktemplate_interval(); bool on_update_blocktemplate_interval();
bool check_tx_inputs_keyimages_diff(const transaction& tx); bool check_tx_inputs_keyimages_diff(const transaction& tx);
void graceful_exit(); void graceful_exit();
@ -163,6 +163,7 @@ namespace cryptonote
uint64_t m_target_blockchain_height; uint64_t m_target_blockchain_height;
bool m_testnet;
std::string m_checkpoints_path; std::string m_checkpoints_path;
time_t m_last_dns_checkpoints_update; time_t m_last_dns_checkpoints_update;
time_t m_last_json_checkpoints_update; time_t m_last_json_checkpoints_update;

View file

@ -27,12 +27,27 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set(daemon_sources 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_headers)
set(daemon_private_headers set(daemon_private_headers
command_parser_executor.h
command_server.h
core.h
daemon.h
daemon_commands_handler.h daemon_commands_handler.h
executor.h
p2p.h
protocol.h
rpc.h
rpc_command_executor.h
# cryptonote_protocol # cryptonote_protocol
../cryptonote_protocol/blobdatatype.h ../cryptonote_protocol/blobdatatype.h
@ -62,6 +77,7 @@ target_link_libraries(daemon
cryptonote_core cryptonote_core
crypto crypto
common common
daemonizer
${Boost_CHRONO_LIBRARY} ${Boost_CHRONO_LIBRARY}
${Boost_FILESYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}

View file

@ -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

View file

@ -0,0 +1,297 @@
// 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
)
: m_executor(ip, port)
{}
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

View file

@ -0,0 +1,95 @@
/**
@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"
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 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

View file

@ -0,0 +1,179 @@
// 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
)
: m_parser(ip, port)
, m_command_lookup()
{
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(
"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)
{
return m_command_lookup.process_command_vec(cmd);
}
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

View file

@ -0,0 +1,67 @@
/**
@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::command_handler m_command_lookup;
public:
t_command_server(
uint32_t ip
, uint16_t port
);
bool process_command_str(const std::string& cmd);
bool process_command_vec(const std::vector<std::string>& cmd);
private:
bool help(const std::vector<std::string>& args);
std::string get_commands_str();
};
} // namespace daemonize

98
src/daemon/core.h Normal file
View file

@ -0,0 +1,98 @@
// 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>
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...");
}
}
};
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2015, The Monero Project // Copyright (c) 2014, The Monero Project
// //
// All rights reserved. // All rights reserved.
// //
@ -28,275 +28,117 @@
// //
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
// node.cpp : Defines the entry point for the console application. #include "daemon/daemon.h"
// Does this file exist?
#include "common/util.h"
#include "include_base_utils.h" #include "daemon/core.h"
#include "daemon/p2p.h"
#include "daemon/protocol.h"
#include "daemon/rpc.h"
#include "misc_log_ex.h"
#include "version.h" #include "version.h"
using namespace epee;
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <functional>
#include <memory>
#include "crypto/hash.h" namespace daemonize {
#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) struct t_internals {
#include <crtdbg.h> private:
#endif t_protocol protocol;
public:
t_core core;
t_p2p p2p;
t_rpc rpc;
namespace po = boost::program_options; 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());
}
};
namespace void t_daemon::init_options(boost::program_options::options_description & option_spec)
{ {
const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", "Specify configuration file", std::string(CRYPTONOTE_NAME ".conf")}; t_core::init_options(option_spec);
const command_line::arg_descriptor<bool> arg_os_version = {"os-version", ""}; t_p2p::init_options(option_spec);
const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", "", ""}; t_rpc::init_options(option_spec);
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};
} }
bool command_line_preprocessor(const boost::program_options::variables_map& vm) t_daemon::t_daemon(
boost::program_options::variables_map const & vm
)
: mp_internals{new t_internals{vm}}
{}
t_daemon::~t_daemon() = default;
// MSVC is brain-dead and can't default this...
t_daemon::t_daemon(t_daemon && other)
{ {
bool exit = false; if (this != &other)
if (command_line::get_arg(vm, command_line::arg_version))
{ {
std::cout << CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL << ENDL; mp_internals = std::move(other.mp_internals);
exit = true; other.mp_internals.reset(nullptr);
} }
if (command_line::get_arg(vm, arg_os_version))
{
std::cout << "OS: " << tools::get_os_version_string() << ENDL;
exit = true;
}
if (exit)
{
return true;
}
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)
{
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);
LOG_PRINT_L0("LOG_LEVEL set to " << new_log_level);
}
return false;
} }
int main(int argc, char* argv[]) // or this
t_daemon & t_daemon::operator=(t_daemon && other)
{ {
if (this != &other)
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...");
TRY_ENTRY();
boost::filesystem::path default_data_path {tools::get_default_data_dir()};
boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"};
po::options_description desc_cmd_only("Command line options");
po::options_description desc_cmd_sett("Command line options and settings options");
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);
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);
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); mp_internals = std::move(other.mp_internals);
po::notify(vm); other.mp_internals.reset(nullptr);
}
return *this;
}
bool t_daemon::run()
{
if (nullptr == mp_internals)
{
throw std::runtime_error{"Can't run stopped daemon"};
}
tools::signal_handler::install(std::bind(&daemonize::t_daemon::stop, this));
try
{
mp_internals->core.run();
mp_internals->rpc.run();
mp_internals->p2p.run();
mp_internals->rpc.stop();
LOG_PRINT("Node stopped.", LOG_LEVEL_0);
return true; return true;
}); }
if (!r) catch (std::exception const & ex)
return 1;
if (command_line::get_arg(vm, command_line::arg_help))
{ {
std::cout << CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL << ENDL << ENDL; LOG_ERROR("Uncaught exception! " << ex.what());
std::cout << desc_options << std::endl;
return false; return false;
} }
catch (...)
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; LOG_ERROR("Uncaught exception!");
return false;
} }
boost::system::error_code ec;
if (boost::filesystem::exists(config_path, ec))
{
po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), desc_cmd_sett), vm);
}
//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))
{
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());
}
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);
daemon_cmmands_handler dch(p2psrv, testnet_mode);
//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);
//initialize core here
LOG_PRINT_L0("Initializing core...");
res = ccore.init(vm, testnet_mode);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
LOG_PRINT_L0("Core initialized OK");
// start components
if(!command_line::has_arg(vm, arg_console))
{
dch.start_handling();
}
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
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);
LOG_PRINT("Node stopped.", LOG_LEVEL_0);
return 0;
CATCH_ENTRY_L0("main", 1);
} }
void t_daemon::stop()
{
if (nullptr == mp_internals)
{
throw std::runtime_error{"Can't stop stopped daemon"};
}
mp_internals->p2p.stop();
mp_internals->rpc.stop();
mp_internals.reset(nullptr); // Ensure resources are cleaned up before we return
}
} // namespace daemonize

54
src/daemon/daemon.h Normal file
View file

@ -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();
void stop();
};
}

View file

@ -1,35 +1,7 @@
// Copyright (c) 2014-2015, The Monero Project // Copyright (c) 2012-2013 The Cryptonote developers
// // Distributed under the MIT/X11 software license, see the accompanying
// All rights reserved. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// 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... */
#pragma once #pragma once
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -41,21 +13,18 @@
#include "crypto/hash.h" #include "crypto/hash.h"
#include "version.h" #include "version.h"
/*! //#include "net/net_helper.h"
* \brief I don't really know right now //#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 class daemon_cmmands_handler
{ {
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_srv; nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_srv;
public: public:
daemon_cmmands_handler( daemon_cmmands_handler(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& srv):m_srv(srv)
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& srv
, bool testnet
)
: m_srv(srv)
, m_testnet(testnet)
{ {
m_cmd_binder.set_handler("help", boost::bind(&daemon_cmmands_handler::help, this, _1), "Show this help"); 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"); m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_cmmands_handler::print_pl, this, _1), "Print peer list");
@ -74,6 +43,10 @@ public:
m_cmd_binder.set_handler("save", boost::bind(&daemon_cmmands_handler::save, this, _1), "Save blockchain"); 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("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("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");
} }
bool start_handling() bool start_handling()
@ -89,7 +62,7 @@ public:
private: private:
epee::srv_console_handlers_binder<nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > > m_cmd_binder; 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() std::string get_commands_str()
@ -122,6 +95,122 @@ private:
return true; 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) bool show_hr(const std::vector<std::string>& args)
{ {
if(!m_srv.get_payload_object().get_core().get_miner().is_mining()) if(!m_srv.get_payload_object().get_core().get_miner().is_mining())
@ -234,7 +323,11 @@ private:
return true; 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); log_space::log_singletone::get_set_log_detalisation_level(true, l);
POP_WARNINGS
return true; return true;
} }
@ -374,7 +467,7 @@ private:
} }
cryptonote::account_public_address adr; 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; std::cout << "target account address has wrong format" << std::endl;
return true; return true;

71
src/daemon/executor.cpp Normal file
View file

@ -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();
}
}

60
src/daemon/executor.h Normal file
View file

@ -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
);
};
}

229
src/daemon/main.cpp Normal file
View file

@ -0,0 +1,229 @@
// 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();
// 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());
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
if (command_line::has_arg(vm, daemon_args::arg_command))
{
auto command = command_line::get_arg(vm, daemon_args::arg_command);
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);
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;
}

99
src/daemon/p2p.h Normal file
View file

@ -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...");
}
}
};
}

88
src/daemon/protocol.h Normal file
View file

@ -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...");
}
}
};
}

96
src/daemon/rpc.h Normal file
View file

@ -0,0 +1,96 @@
// 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);
}
~t_rpc()
{
LOG_PRINT_L0("Deinitializing rpc server...");
try {
m_server.deinit();
} catch (...) {
LOG_PRINT_L0("Failed to deinitialize rpc server...");
}
}
};
}

View file

@ -0,0 +1,435 @@
// 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
)
: m_rpc_client{ip, port}
{}
bool t_rpc_command_executor::print_peer_list() {
/*
cryptonote::COMMAND_RPC_GET_PEER_LIST::request req;
cryptonote::COMMAND_RPC_GET_PEER_LIST::response res;
bool ok = m_rpc_client.rpc_request(req, res, "/get_peer_list", "Couldn't retrieve peer list");
if (!ok) 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;
if (m_rpc_client.rpc_request(req, res, "/save_bc", "Couldn't save blockchain"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/set_log_hash_rate", "Unsuccessful"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/set_log_hash_rate", "Unsuccessful"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/getinfo", "Problem fetching info"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/get_connections", "Unsuccessful"))
{
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) {
/*
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request req;
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response res;
req.start_height = start_block_index;
req.end_height = end_block_index;
if (m_rpc_client.json_rpc_request(req, res, "getblockheadersrange", "Unsuccessful"))
{
for (auto & header : res.headers)
{
std::cout << "height " << header.height
<< ", timestamp " << header.timestamp
<< ", cumul_dif " << header.cumulative_difficulty
<< ", cumul_size " << header.cumulative_size << std::endl
<< "id " << header.hash << std::endl
<< "difficulty " << header.difficulty
<< ", nonce " << header.nonce
<< ", tx_count " << header.tx_count << 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;
if (m_rpc_client.rpc_request(req, res, "/set_log_level", "Unsuccessful"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/getheight", "Unsuccessful"))
{
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;
req.hash = epee::string_tools::pod_to_hex(block_hash);
if (m_rpc_client.json_rpc_request(req, res, "getblockheaderbyhash", "Unsuccessful"))
{
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;
req.height = height;
if (m_rpc_client.json_rpc_request(req, res, "getblockheaderbyheight", "Unsuccessful"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/gettransactions", "Problem fetching transaction"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/get_transaction_pool", "Problem fetching transaction pool"))
{
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;
if (m_rpc_client.rpc_request(req, res, "/get_transaction_pool", "Problem fetching transaction pool"))
{
for (auto & tx_info : res.transactions)
{
if (res.transactions.empty())
{
tools::msg_writer() << "Pool is empty" << std::endl;
}
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;
if (m_rpc_client.rpc_request(req, res, "/stop_mining", "Mining did not stop"))
{
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
if(m_rpc_client.rpc_request(req, res, "/stop_daemon", "Daemon did not stop"))
{
tools::success_msg_writer() << "Stop signal sent";
}
*/
return true;
}
bool t_rpc_command_executor::print_status()
{
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

View file

@ -0,0 +1,103 @@
/**
@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"
namespace daemonize {
class t_rpc_command_executor final {
private:
tools::t_rpc_client m_rpc_client;
public:
t_rpc_command_executor(
uint32_t ip
, uint16_t port
);
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

View file

@ -0,0 +1,74 @@
# 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.
if(MSVC OR MINGW)
set(daemonizer_sources
windows_service.cpp
windows_daemonizer.inl
)
else()
set(daemonizer_sources
posix_fork.cpp
posix_daemonizer.inl
)
endif()
set(daemonizer_headers
)
if(MSVC OR MINGW)
set(daemonizer_private_headers
daemonizer.h
windows_service.h
windows_service_runner.h
)
else()
set(daemonizer_private_headers
daemonizer.h
posix_fork.h
)
endif()
bitmonero_private_headers(daemonizer
${daemonizer_private_headers})
bitmonero_add_library(daemonizer
${daemonizer_sources}
${daemonizer_headers}
${daemonizer_private_headers})
target_link_libraries(daemonizer
LINK_PRIVATE
common
${Boost_CHRONO_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_REGEX_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${UPNP_LIBRARIES}
${EXTRA_LIBRARIES})

View file

@ -0,0 +1,38 @@
#pragma once
#include <boost/filesystem/path.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
namespace daemonizer
{
void init_options(
boost::program_options::options_description & hidden_options
, boost::program_options::options_description & normal_options
);
boost::filesystem::path get_default_data_dir();
boost::filesystem::path get_relative_path_base(
boost::program_options::variables_map const & vm
);
/**
* @arg create_before_detach - this indicates that the daemon should be
* created before the fork, giving it a chance to report initialization
* errors. At the time of this writing, this is not possible in the primary
* daemon (likely due to the size of the blockchain in memory).
*/
template <typename T_executor>
bool daemonize(
int argc, char const * argv[]
, T_executor && executor // universal ref
, boost::program_options::variables_map const & vm
);
}
#ifdef WIN32
# include "daemonizer/windows_daemonizer.inl"
#else
# include "daemonizer/posix_daemonizer.inl"
#endif

View file

@ -0,0 +1,60 @@
#pragma once
#include "common/scoped_message_writer.h"
#include "common/util.h"
#include "daemonizer/posix_fork.h"
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
namespace daemonizer
{
namespace
{
const command_line::arg_descriptor<bool> arg_detach = {
"detach"
, "Run as daemon"
};
}
inline void init_options(
boost::program_options::options_description & hidden_options
, boost::program_options::options_description & normal_options
)
{
command_line::add_arg(normal_options, arg_detach);
}
inline boost::filesystem::path get_default_data_dir()
{
return boost::filesystem::absolute(tools::get_default_data_dir());
}
inline boost::filesystem::path get_relative_path_base(
boost::program_options::variables_map const & vm
)
{
return boost::filesystem::current_path();
}
template <typename T_executor>
inline bool daemonize(
int argc, char const * argv[]
, T_executor && executor // universal ref
, boost::program_options::variables_map const & vm
)
{
if (command_line::has_arg(vm, arg_detach))
{
auto daemon = executor.create_daemon(vm);
tools::success_msg_writer() << "Forking to background...";
posix::fork();
return daemon.run();
}
else
{
//LOG_PRINT_L0(CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL);
return executor.run_interactive(vm);
}
}
}

View file

@ -0,0 +1,108 @@
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "daemonizer/posix_fork.h"
#include "misc_log_ex.h"
#include <cstdlib>
#include <fcntl.h>
#include <unistd.h>
#include <stdexcept>
#include <string>
#include <sys/stat.h>
namespace posix {
namespace {
void quit(std::string const & message)
{
LOG_ERROR(message);
throw std::runtime_error(message);
}
}
void fork()
{
// Fork the process and have the parent exit. If the process was started
// from a shell, this returns control to the user. Forking a new process is
// also a prerequisite for the subsequent call to setsid().
if (pid_t pid = ::fork())
{
if (pid > 0)
{
// We're in the parent process and need to exit.
//
// When the exit() function is used, the program terminates without
// invoking local variables' destructors. Only global variables are
// destroyed.
exit(0);
}
else
{
quit("First fork failed");
}
}
// Make the process a new session leader. This detaches it from the
// terminal.
setsid();
// A process inherits its working directory from its parent. This could be
// on a mounted filesystem, which means that the running daemon would
// prevent this filesystem from being unmounted. Changing to the root
// directory avoids this problem.
if (chdir("/") < 0)
{
quit("Unable to change working directory to root");
}
// The file mode creation mask is also inherited from the parent process.
// We don't want to restrict the permissions on files created by the
// daemon, so the mask is cleared.
umask(0);
// A second fork ensures the process cannot acquire a controlling terminal.
if (pid_t pid = ::fork())
{
if (pid > 0)
{
exit(0);
}
else
{
quit("Second fork failed");
}
}
// Close the standard streams. This decouples the daemon from the terminal
// that started it.
close(0);
close(1);
close(2);
// We don't want the daemon to have any standard input.
if (open("/dev/null", O_RDONLY) < 0)
{
quit("Unable to open /dev/null");
}
// Send standard output to a log file.
const char* output = "/tmp/bitmonero.daemon.stdout.stderr";
const int flags = O_WRONLY | O_CREAT | O_APPEND;
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (open(output, flags, mode) < 0)
{
quit("Unable to open output file: " + std::string(output));
}
// Also send standard error to the same log file.
if (dup(1) < 0)
{
quit("Unable to dup output descriptor");
}
}
} // namespace posix

View file

@ -0,0 +1,11 @@
#pragma once
#ifndef WIN32
namespace posix {
void fork();
}
#endif

View file

@ -0,0 +1,156 @@
#pragma once
#include "common/util.h"
#include "daemonizer/windows_service.h"
#include "daemonizer/windows_service_runner.h"
#include <shlobj.h>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
namespace daemonizer
{
namespace
{
const command_line::arg_descriptor<bool> arg_install_service = {
"install-service"
, "Install Windows service"
};
const command_line::arg_descriptor<bool> arg_uninstall_service = {
"uninstall-service"
, "Uninstall Windows service"
};
const command_line::arg_descriptor<bool> arg_start_service = {
"start-service"
, "Start Windows service"
};
const command_line::arg_descriptor<bool> arg_stop_service = {
"stop-service"
, "Stop Windows service"
};
const command_line::arg_descriptor<bool> arg_is_service = {
"run-as-service"
, "Hidden -- true if running as windows service"
};
std::string get_argument_string(int argc, char const * argv[])
{
std::string result = "";
for (int i = 1; i < argc; ++i)
{
result += " " + std::string{argv[i]};
}
return result;
}
}
inline void init_options(
boost::program_options::options_description & hidden_options
, boost::program_options::options_description & normal_options
)
{
command_line::add_arg(normal_options, arg_install_service);
command_line::add_arg(normal_options, arg_uninstall_service);
command_line::add_arg(normal_options, arg_start_service);
command_line::add_arg(normal_options, arg_stop_service);
command_line::add_arg(hidden_options, arg_is_service);
}
inline boost::filesystem::path get_default_data_dir()
{
bool admin;
if (!windows::check_admin(admin))
{
admin = false;
}
if (admin)
{
return boost::filesystem::absolute(
tools::get_special_folder_path(CSIDL_COMMON_APPDATA, true) + "\\" + CRYPTONOTE_NAME
);
}
else
{
return boost::filesystem::absolute(
tools::get_special_folder_path(CSIDL_APPDATA, true) + "\\" + CRYPTONOTE_NAME
);
}
}
inline boost::filesystem::path get_relative_path_base(
boost::program_options::variables_map const & vm
)
{
if (command_line::arg_present(vm, arg_is_service))
{
if (command_line::arg_present(vm, command_line::arg_data_dir))
{
return command_line::get_arg(vm, command_line::arg_data_dir);
}
else
{
return tools::get_default_data_dir();
}
}
else
{
return boost::filesystem::current_path();
}
}
template <typename T_executor>
inline bool daemonize(
int argc, char const * argv[]
, T_executor && executor // universal ref
, boost::program_options::variables_map const & vm
)
{
std::string arguments = get_argument_string(argc, argv);
if (command_line::arg_present(vm, arg_is_service))
{
// TODO - Set the service status here for return codes
windows::t_service_runner<typename T_executor::t_daemon>::run(
executor.name()
, executor.create_daemon(vm)
);
return true;
}
else if (command_line::arg_present(vm, arg_install_service))
{
if (windows::ensure_admin(arguments))
{
arguments += " --run-as-service";
return windows::install_service(executor.name(), arguments);
}
}
else if (command_line::arg_present(vm, arg_uninstall_service))
{
if (windows::ensure_admin(arguments))
{
return windows::uninstall_service(executor.name());
}
}
else if (command_line::arg_present(vm, arg_start_service))
{
if (windows::ensure_admin(arguments))
{
return windows::start_service(executor.name());
}
}
else if (command_line::arg_present(vm, arg_stop_service))
{
if (windows::ensure_admin(arguments))
{
return windows::stop_service(executor.name());
}
}
else // interactive
{
//LOG_PRINT_L0(CRYPTONOTE_NAME << " v" << MONERO_VERSION_FULL);
return executor.run_interactive(vm);
}
return false;
}
}

View file

@ -0,0 +1,341 @@
#undef UNICODE
#undef _UNICODE
#include "common/scoped_message_writer.h"
#include "daemonizer/windows_service.h"
#include "string_tools.h"
#include <chrono>
#include <iostream>
#include <utility>
#include <memory>
#include <shellapi.h>
#include <thread>
#include <windows.h>
namespace windows {
namespace {
typedef std::unique_ptr<std::remove_pointer<SC_HANDLE>::type, decltype(&::CloseServiceHandle)> service_handle;
std::string get_last_error()
{
LPSTR p_error_text = nullptr;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_IGNORE_INSERTS
, nullptr
, GetLastError()
, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
, reinterpret_cast<LPSTR>(&p_error_text)
, 0
, nullptr
);
if (nullptr == p_error_text)
{
return "";
}
else
{
return std::string{p_error_text};
LocalFree(p_error_text);
}
}
bool relaunch_as_admin(
std::string const & command
, std::string const & arguments
)
{
SHELLEXECUTEINFO info{};
info.cbSize = sizeof(info);
info.lpVerb = "runas";
info.lpFile = command.c_str();
info.lpParameters = arguments.c_str();
info.hwnd = nullptr;
info.nShow = SW_SHOWNORMAL;
if (!ShellExecuteEx(&info))
{
tools::fail_msg_writer() << "Admin relaunch failed: " << get_last_error();
return false;
}
else
{
return true;
}
}
// When we relaunch as admin, Windows opens a new window. This just pauses
// to allow the user to read any output.
void pause_to_display_admin_window_messages()
{
std::chrono::milliseconds how_long{1500};
std::this_thread::sleep_for(how_long);
}
}
bool check_admin(bool & result)
{
BOOL is_admin = FALSE;
PSID p_administrators_group = nullptr;
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(
&nt_authority
, 2
, SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0
, &p_administrators_group
))
{
tools::fail_msg_writer() << "Security Identifier creation failed: " << get_last_error();
return false;
}
if (!CheckTokenMembership(
nullptr
, p_administrators_group
, &is_admin
))
{
tools::fail_msg_writer() << "Permissions check failed: " << get_last_error();
return false;
}
result = is_admin ? true : false;
return true;
}
bool ensure_admin(
std::string const & arguments
)
{
bool admin;
if (!check_admin(admin))
{
return false;
}
if (admin)
{
return true;
}
else
{
std::string command = epee::string_tools::get_current_module_path();
relaunch_as_admin(command, arguments);
return false;
}
}
bool install_service(
std::string const & service_name
, std::string const & arguments
)
{
std::string command = epee::string_tools::get_current_module_path();
std::string full_command = command + arguments;
service_handle p_manager{
OpenSCManager(
nullptr
, nullptr
, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE
)
, &::CloseServiceHandle
};
if (p_manager == nullptr)
{
tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
return false;
}
service_handle p_service{
CreateService(
p_manager.get()
, service_name.c_str()
, service_name.c_str()
, 0
//, GENERIC_EXECUTE | GENERIC_READ
, SERVICE_WIN32_OWN_PROCESS
, SERVICE_DEMAND_START
, SERVICE_ERROR_NORMAL
, full_command.c_str()
, nullptr
, nullptr
, ""
//, "NT AUTHORITY\\LocalService"
, nullptr // Implies LocalSystem account
, nullptr
)
, &::CloseServiceHandle
};
if (p_service == nullptr)
{
tools::fail_msg_writer() << "Couldn't create service: " << get_last_error();
return false;
}
tools::success_msg_writer() << "Service installed";
pause_to_display_admin_window_messages();
return true;
}
bool start_service(
std::string const & service_name
)
{
tools::msg_writer() << "Starting service";
SERVICE_STATUS_PROCESS service_status = {};
DWORD unused = 0;
service_handle p_manager{
OpenSCManager(
nullptr
, nullptr
, SC_MANAGER_CONNECT
)
, &::CloseServiceHandle
};
if (p_manager == nullptr)
{
tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
return false;
}
service_handle p_service{
OpenService(
p_manager.get()
, service_name.c_str()
//, SERVICE_START | SERVICE_QUERY_STATUS
, SERVICE_START
)
, &::CloseServiceHandle
};
if (p_service == nullptr)
{
tools::fail_msg_writer() << "Couldn't find service: " << get_last_error();
return false;
}
if (!StartService(
p_service.get()
, 0
, nullptr
))
{
tools::fail_msg_writer() << "Service start request failed: " << get_last_error();
return false;
}
tools::success_msg_writer() << "Service started";
pause_to_display_admin_window_messages();
return true;
}
bool stop_service(
std::string const & service_name
)
{
tools::msg_writer() << "Stopping service";
service_handle p_manager{
OpenSCManager(
nullptr
, nullptr
, SC_MANAGER_CONNECT
)
, &::CloseServiceHandle
};
if (p_manager == nullptr)
{
tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
return false;
}
service_handle p_service{
OpenService(
p_manager.get()
, service_name.c_str()
, SERVICE_STOP | SERVICE_QUERY_STATUS
)
, &::CloseServiceHandle
};
if (p_service == nullptr)
{
tools::fail_msg_writer() << "Couldn't find service: " << get_last_error();
return false;
}
SERVICE_STATUS status = {};
if (!ControlService(p_service.get(), SERVICE_CONTROL_STOP, &status))
{
tools::fail_msg_writer() << "Couldn't request service stop: " << get_last_error();
return false;
}
tools::success_msg_writer() << "Service stopped";
pause_to_display_admin_window_messages();
return true;
}
bool uninstall_service(
std::string const & service_name
)
{
service_handle p_manager{
OpenSCManager(
nullptr
, nullptr
, SC_MANAGER_CONNECT
)
, &::CloseServiceHandle
};
if (p_manager == nullptr)
{
tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
return false;
}
service_handle p_service{
OpenService(
p_manager.get()
, service_name.c_str()
, SERVICE_QUERY_STATUS | DELETE
)
, &::CloseServiceHandle
};
if (p_service == nullptr)
{
tools::fail_msg_writer() << "Couldn't find service: " << get_last_error();
return false;
}
SERVICE_STATUS status = {};
if (!DeleteService(p_service.get()))
{
tools::fail_msg_writer() << "Couldn't uninstall service: " << get_last_error();
return false;
}
tools::success_msg_writer() << "Service uninstalled";
pause_to_display_admin_window_messages();
return true;
}
} // namespace windows

View file

@ -0,0 +1,36 @@
#pragma once
#ifdef WIN32
#undef UNICODE
#undef _UNICODE
#include <string>
#include <windows.h>
namespace windows
{
bool check_admin(bool & result);
bool ensure_admin(
std::string const & arguments
);
bool install_service(
std::string const & service_name
, std::string const & arguments
);
bool uninstall_service(
std::string const & service_name
);
bool start_service(
std::string const & service_name
);
bool stop_service(
std::string const & service_name
);
}
#endif

View file

@ -0,0 +1,157 @@
#pragma once
#ifdef WIN32
#undef UNICODE
#undef _UNICODE
#include "daemonizer/windows_service.h"
#include <memory>
#include <string>
#include <vector>
#include <windows.h>
namespace windows {
namespace
{
std::vector<char> vecstring(std::string const & str)
{
std::vector<char> result{str.begin(), str.end()};
result.push_back('\0');
return result;
}
}
template <typename T_handler>
class t_service_runner final
{
private:
SERVICE_STATUS_HANDLE m_status_handle{nullptr};
SERVICE_STATUS m_status{};
std::mutex m_lock{};
std::string m_name;
T_handler m_handler;
static std::unique_ptr<t_service_runner<T_handler>> sp_instance;
public:
t_service_runner(
std::string name
, T_handler handler
)
: m_name{std::move(name)}
, m_handler{std::move(handler)}
{
m_status.dwServiceType = SERVICE_WIN32;
m_status.dwCurrentState = SERVICE_STOPPED;
m_status.dwControlsAccepted = 0;
m_status.dwWin32ExitCode = NO_ERROR;
m_status.dwServiceSpecificExitCode = NO_ERROR;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
}
t_service_runner & operator=(t_service_runner && other)
{
if (this != &other)
{
m_status_handle = std::move(other.m_status_handle);
m_status = std::move(other.m_status);
m_name = std::move(other.m_name);
m_handler = std::move(other.m_handler);
}
return *this;
}
static void run(
std::string name
, T_handler handler
)
{
sp_instance.reset(new t_service_runner<T_handler>{
std::move(name)
, std::move(handler)
});
sp_instance->run_();
}
private:
void run_()
{
SERVICE_TABLE_ENTRY table[] =
{
{ vecstring(m_name).data(), &service_main }
, { 0, 0 }
};
StartServiceCtrlDispatcher(table);
}
void report_status(DWORD status)
{
m_status.dwCurrentState = status;
if (status == SERVICE_RUNNING)
{
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
}
else if(status == SERVICE_STOP_PENDING)
{
m_status.dwControlsAccepted = 0;
}
SetServiceStatus(m_status_handle, &m_status);
}
static void WINAPI service_main(DWORD argc, LPSTR * argv)
{
sp_instance->service_main_(argc, argv);
}
void service_main_(DWORD argc, LPSTR * argv)
{
m_status_handle = RegisterServiceCtrlHandler(m_name.c_str(), &on_state_change_request);
if (m_status_handle == nullptr) return;
report_status(SERVICE_START_PENDING);
report_status(SERVICE_RUNNING);
m_handler.run();
on_state_change_request_(SERVICE_CONTROL_STOP);
// Ensure that the service is uninstalled
uninstall_service(m_name);
}
static void WINAPI on_state_change_request(DWORD control_code)
{
sp_instance->on_state_change_request_(control_code);
}
void on_state_change_request_(DWORD control_code)
{
switch (control_code)
{
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
report_status(SERVICE_STOP_PENDING);
m_handler.stop();
report_status(SERVICE_STOPPED);
break;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
default:
break;
}
}
};
template <typename T_handler>
std::unique_ptr<t_service_runner<T_handler>> t_service_runner<T_handler>::sp_instance;
}
#endif

View file

@ -82,18 +82,16 @@ namespace nodetool
node_server( node_server(
t_payload_net_handler& payload_handler t_payload_net_handler& payload_handler
, boost::uuids::uuid network_id
) )
: m_payload_handler(payload_handler) : m_payload_handler(payload_handler)
, m_allow_local_ip(false) , m_allow_local_ip(false)
, m_hide_my_port(false) , m_hide_my_port(false)
, m_network_id(std::move(network_id))
{} {}
static void init_options(boost::program_options::options_description& desc); static void init_options(boost::program_options::options_description& desc);
bool run(); bool run();
bool init(const boost::program_options::variables_map& vm, bool testnet); bool init(const boost::program_options::variables_map& vm);
bool deinit(); bool deinit();
bool send_stop_signal(); bool send_stop_signal();
uint32_t get_this_peer_port(){return m_listenning_port;} uint32_t get_this_peer_port(){return m_listenning_port;}

View file

@ -46,6 +46,7 @@
#include "net/local_ip.h" #include "net/local_ip.h"
#include "crypto/crypto.h" #include "crypto/crypto.h"
#include "storages/levin_abstract_invoke2.h" #include "storages/levin_abstract_invoke2.h"
#include "daemon/command_line_args.h"
// We have to look for miniupnpc headers in different places, dependent on if its compiled or external // We have to look for miniupnpc headers in different places, dependent on if its compiled or external
#ifdef UPNP_STATIC #ifdef UPNP_STATIC
@ -241,16 +242,20 @@ namespace nodetool
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm, bool testnet) bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm)
{ {
bool testnet = command_line::get_arg(vm, daemon_args::arg_testnet_on);
if (testnet) if (testnet)
{ {
memcpy(&m_network_id, &::config::testnet::NETWORK_ID, 16);
append_net_address(m_seed_nodes, "107.152.187.202:28080"); append_net_address(m_seed_nodes, "107.152.187.202:28080");
append_net_address(m_seed_nodes, "197.242.158.240:28080"); append_net_address(m_seed_nodes, "197.242.158.240:28080");
append_net_address(m_seed_nodes, "107.152.130.98:28080"); append_net_address(m_seed_nodes, "107.152.130.98:28080");
} }
else else
{ {
memcpy(&m_network_id, &::config::NETWORK_ID, 16);
// for each hostname in the seed nodes list, attempt to DNS resolve and // for each hostname in the seed nodes list, attempt to DNS resolve and
// add the result addresses as seed nodes // add the result addresses as seed nodes
// TODO: at some point add IPv6 support, but that won't be relevant // TODO: at some point add IPv6 support, but that won't be relevant

View file

@ -40,29 +40,10 @@ using namespace epee;
#include "misc_language.h" #include "misc_language.h"
#include "crypto/hash.h" #include "crypto/hash.h"
#include "core_rpc_server_error_codes.h" #include "core_rpc_server_error_codes.h"
#include "daemon/command_line_args.h"
namespace cryptonote namespace cryptonote
{ {
namespace
{
const command_line::arg_descriptor<std::string> arg_rpc_bind_ip = {
"rpc-bind-ip"
, "IP for RPC server"
, "127.0.0.1"
};
const command_line::arg_descriptor<std::string> arg_rpc_bind_port = {
"rpc-bind-port"
, "Port for RPC server"
, std::to_string(config::RPC_DEFAULT_PORT)
};
const command_line::arg_descriptor<std::string> arg_testnet_rpc_bind_port = {
"testnet-rpc-bind-port"
, "Port for testnet RPC server"
, std::to_string(config::testnet::RPC_DEFAULT_PORT)
};
}
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
void core_rpc_server::init_options(boost::program_options::options_description& desc) void core_rpc_server::init_options(boost::program_options::options_description& desc)
@ -75,11 +56,9 @@ namespace cryptonote
core_rpc_server::core_rpc_server( core_rpc_server::core_rpc_server(
core& cr core& cr
, nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p , nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p
, bool testnet
) )
: m_core(cr) : m_core(cr)
, m_p2p(p2p) , m_p2p(p2p)
, m_testnet(testnet)
{} {}
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::handle_command_line( bool core_rpc_server::handle_command_line(
@ -97,6 +76,8 @@ namespace cryptonote
const boost::program_options::variables_map& vm const boost::program_options::variables_map& vm
) )
{ {
m_testnet = command_line::get_arg(vm, daemon_args::arg_testnet_on);
m_net_server.set_threads_prefix("RPC"); m_net_server.set_threads_prefix("RPC");
bool r = handle_command_line(vm); bool r = handle_command_line(vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server");
@ -703,4 +684,23 @@ namespace cryptonote
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
}
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_bind_ip = {
"rpc-bind-ip"
, "IP for RPC server"
, "127.0.0.1"
};
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_bind_port = {
"rpc-bind-port"
, "Port for RPC server"
, std::to_string(config::RPC_DEFAULT_PORT)
};
const command_line::arg_descriptor<std::string> core_rpc_server::arg_testnet_rpc_bind_port = {
"testnet-rpc-bind-port"
, "Port for testnet RPC server"
, std::to_string(config::testnet::RPC_DEFAULT_PORT)
};
} // namespace cryptonote

View file

@ -39,6 +39,10 @@
#include "p2p/net_node.h" #include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h"
// yes, epee doesn't properly use its full namespace when calling its
// functions from macros. *sigh*
using namespace epee;
namespace cryptonote namespace cryptonote
{ {
/************************************************************************/ /************************************************************************/
@ -47,12 +51,16 @@ namespace cryptonote
class core_rpc_server: public epee::http_server_impl_base<core_rpc_server> class core_rpc_server: public epee::http_server_impl_base<core_rpc_server>
{ {
public: public:
static const command_line::arg_descriptor<std::string> arg_rpc_bind_ip;
static const command_line::arg_descriptor<std::string> arg_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_testnet_rpc_bind_port;
typedef epee::net_utils::connection_context_base connection_context; typedef epee::net_utils::connection_context_base connection_context;
core_rpc_server( core_rpc_server(
core& cr core& cr
, nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p , nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p
, bool testnet
); );
static void init_options(boost::program_options::options_description& desc); static void init_options(boost::program_options::options_description& desc);