Electroneum
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1// Copyrights(c) 2017-2021, The Electroneum Project
2// Copyrights(c) 2014-2019, The Monero Project
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without modification, are
7// permitted provided that the following conditions are met:
8//
9// 1. Redistributions of source code must retain the above copyright notice, this list of
10// conditions and the following disclaimer.
11//
12// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13// of conditions and the following disclaimer in the documentation and/or other
14// materials provided with the distribution.
15//
16// 3. Neither the name of the copyright holder nor the names of its contributors may be
17// used to endorse or promote products derived from this software without specific
18// prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31
32#include "common/command_line.h"
34#include "common/password.h"
35#include "common/util.h"
39#include "daemon/daemon.h"
40#include "daemon/executor.h"
42#include "misc_log_ex.h"
43#include "net/parse.h"
44#include "p2p/net_node.h"
45#include "rpc/core_rpc_server.h"
46#include "rpc/rpc_args.h"
49#include "version.h"
50
51#ifdef STACK_TRACE
52#include "common/stack_trace.h"
53#endif // STACK_TRACE
54
55#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
56#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "daemon"
57
58namespace po = boost::program_options;
59namespace bf = boost::filesystem;
60
61uint16_t parse_public_rpc_port(const po::variables_map &vm)
62{
63 const auto &public_node_arg = daemon_args::arg_public_node;
64 const bool public_node = command_line::get_arg(vm, public_node_arg);
65 if (!public_node)
66 {
67 return 0;
68 }
69
70 std::string rpc_port_str;
71 const auto &restricted_rpc_port = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
72 if (!command_line::is_arg_defaulted(vm, restricted_rpc_port))
73 {
74 rpc_port_str = command_line::get_arg(vm, restricted_rpc_port);;
75 }
77 {
79 }
80 else
81 {
82 throw std::runtime_error("restricted RPC mode is required");
83 }
84
85 uint16_t rpc_port;
86 if (!string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
87 {
88 throw std::runtime_error("invalid RPC port " + rpc_port_str);
89 }
90
91 const auto rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_bind_ip);
92 const auto address = net::get_network_address(rpc_bind_address, rpc_port);
93 if (!address) {
94 throw std::runtime_error("failed to parse RPC bind address");
95 }
96 if (address->get_zone() != epee::net_utils::zone::public_)
97 {
98 throw std::runtime_error(std::string(zone_to_string(address->get_zone()))
99 + " network zone is not supported, please check RPC server bind address");
100 }
101
102 if (address->is_loopback() || address->is_local())
103 {
104 MLOG_RED(el::Level::Warning, "--" << public_node_arg.name
105 << " is enabled, but RPC server " << address->str()
106 << " may be unreachable from outside, please check RPC server bind address");
107 }
108
109 return rpc_port;
110}
111
112int main(int argc, char const * argv[])
113{
114 try {
115
116 // TODO parse the debug options like set log level right here at start
117
119
121
122 // Build argument description
123 po::options_description all_options("All");
124 po::options_description hidden_options("Hidden");
125 po::options_description visible_options("Options");
126 po::options_description core_settings("Settings");
127 po::positional_options_description positional_options;
128 {
129 // Misc Options
130
135
136 // Settings
146
147 daemonizer::init_options(hidden_options, visible_options);
149
150 // Hidden options
152
153 visible_options.add(core_settings);
154 all_options.add(visible_options);
155 all_options.add(hidden_options);
156
157 // Positional
158 positional_options.add(daemon_args::arg_command.name, -1); // -1 for unlimited arguments
159 }
160
161 // Do command line parsing
162 po::variables_map vm;
163 bool ok = command_line::handle_error_helper(visible_options, [&]()
164 {
165 boost::program_options::store(
166 boost::program_options::command_line_parser(argc, argv)
167 .options(all_options).positional(positional_options).run()
168 , vm
169 );
170
171 return true;
172 });
173 if (!ok) return 1;
174
176 {
177 std::cout << "Electroneum '" << ELECTRONEUM_RELEASE_NAME << "' (v" << ELECTRONEUM_VERSION_FULL << ")" << ENDL << ENDL;
178 std::cout << "Usage: " + std::string{argv[0]} + " [options|settings] [daemon_command...]" << std::endl << std::endl;
179 std::cout << visible_options << std::endl;
180 return 0;
181 }
182
183 // Electroneum Version
185 {
186 std::cout << "Electroneum '" << ELECTRONEUM_RELEASE_NAME << "' (v" << ELECTRONEUM_VERSION_FULL << ")" << ENDL;
187 return 0;
188 }
189
190 // OS
192 {
193 std::cout << "OS: " << tools::get_os_version_string() << ENDL;
194 return 0;
195 }
196
198 boost::filesystem::path config_path(config);
199 boost::system::error_code ec;
200 if (bf::exists(config_path, ec))
201 {
202 try
203 {
204 po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), core_settings), vm);
205 }
206 catch (const std::exception &e)
207 {
208 // log system isn't initialized yet
209 std::cerr << "Error parsing config file: " << e.what() << std::endl;
210 throw;
211 }
212 }
214 {
215 std::cerr << "Can't find config file " << config << std::endl;
216 return 1;
217 }
218
219 const bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
220 const bool stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
221 const bool regtest = command_line::get_arg(vm, cryptonote::arg_regtest_on);
222 if (testnet + stagenet + regtest > 1)
223 {
224 std::cerr << "Can't specify more than one of --tesnet and --stagenet and --regtest" << ENDL;
225 return 1;
226 }
227
228 std::string db_type = command_line::get_arg(vm, cryptonote::arg_db_type);
229
230 // verify that blockchaindb type is valid
232 {
233 std::cout << "Invalid database type (" << db_type << "), available types are: " <<
234 cryptonote::blockchain_db_types(", ") << std::endl;
235 return 0;
236 }
237
238 // data_dir
239 // default: e.g. ~/.electroneum/ or ~/.electroneum/testnet
240 // if data-dir argument given:
241 // absolute path
242 // relative path: relative to cwd
243
244 // Create data dir if it doesn't exist
245 boost::filesystem::path data_dir = boost::filesystem::absolute(
247
248 // FIXME: not sure on windows implementation default, needs further review
249 //bf::path relative_path_base = daemonizer::get_relative_path_base(vm);
250 bf::path relative_path_base = data_dir;
251
252 po::notify(vm);
253
254 // log_file_path
255 // default: <data_dir>/<CRYPTONOTE_NAME>.log
256 // if log-file argument given:
257 // absolute path
258 // relative path: relative to data_dir
259 bf::path log_file_path {data_dir / std::string(CRYPTONOTE_NAME ".log")};
262 if (!log_file_path.has_parent_path())
263 log_file_path = bf::absolute(log_file_path, relative_path_base);
265
266 // Set log level
268 {
270 }
271
272 // after logs initialized
274
275#ifdef STACK_TRACE
276 tools::set_stack_trace_log(log_file_path.filename().string());
277#endif // STACK_TRACE
278
281
282 // If there are positional options, we're running a daemon command
283 {
285
286 if (command.size())
287 {
289 auto rpc_ip_str = command_line::get_arg(vm, arg.rpc_bind_ip);
291
292 uint32_t rpc_ip;
293 uint16_t rpc_port;
294 if (!epee::string_tools::get_ip_int32_from_string(rpc_ip, rpc_ip_str))
295 {
296 std::cerr << "Invalid IP: " << rpc_ip_str << std::endl;
297 return 1;
298 }
299 if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
300 {
301 std::cerr << "Invalid port: " << rpc_port_str << std::endl;
302 return 1;
303 }
304
305 const char *env_rpc_login = nullptr;
306 const bool has_rpc_arg = command_line::has_arg(vm, arg.rpc_login);
307 const bool use_rpc_env = !has_rpc_arg && (env_rpc_login = getenv("RPC_LOGIN")) != nullptr && strlen(env_rpc_login) > 0;
308 boost::optional<tools::login> login{};
309 if (has_rpc_arg || use_rpc_env)
310 {
311 login = tools::login::parse(
312 has_rpc_arg ? command_line::get_arg(vm, arg.rpc_login) : std::string(env_rpc_login), false, [](bool verify) {
313#ifdef HAVE_READLINE
314 rdln::suspend_readline pause_readline;
315#endif
316 return tools::password_container::prompt(verify, "Daemon client password");
317 }
318 );
319 if (!login)
320 {
321 std::cerr << "Failed to obtain password" << std::endl;
322 return 1;
323 }
324 }
325
326 auto ssl_options = cryptonote::rpc_args::process_ssl(vm, true);
327 if (!ssl_options)
328 return 1;
329
330 daemonize::t_command_server rpc_commands{rpc_ip, rpc_port, std::move(login), std::move(*ssl_options)};
331 if (rpc_commands.process_command_vec(command))
332 {
333 return 0;
334 }
335 else
336 {
337#ifdef HAVE_READLINE
338 rdln::suspend_readline pause_readline;
339#endif
340 std::cerr << "Unknown command: " << command.front() << std::endl;
341 return 1;
342 }
343 }
344 }
345
346#ifdef STACK_TRACE
347 tools::set_stack_trace_log(log_file_path.filename().string());
348#endif // STACK_TRACE
349
352
353 // logging is now set up
354 MGINFO("Electroneum '" << ELECTRONEUM_RELEASE_NAME << "' (v" << ELECTRONEUM_VERSION_FULL << ")");
355
356 MINFO("Moving from main() into the daemonize now.");
357
358 return daemonizer::daemonize(argc, argv, daemonize::t_executor{parse_public_rpc_port(vm)}, vm) ? 0 : 1;
359 }
360 catch (std::exception const & ex)
361 {
362 LOG_ERROR("Exception in main! " << ex.what());
363 }
364 catch (...)
365 {
366 LOG_ERROR("Exception in main!");
367 }
368 return 1;
369}
int main()
static const command_line::arg_descriptor< std::string, false, true, 2 > arg_rpc_bind_port
static const command_line::arg_descriptor< std::string > arg_rpc_restricted_bind_port
static const command_line::arg_descriptor< bool > arg_restricted_rpc
bool process_command_vec(const std::vector< std::string > &cmd)
static void init_options(boost::program_options::options_description &configurable_options)
Definition executor.cpp:46
#define CRYPTONOTE_NAME
void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size=MAX_LOG_FILE_SIZE, const std::size_t max_log_files=MAX_LOG_FILES)
Definition mlog.cpp:148
void mlog_set_log(const char *log)
Definition mlog.cpp:288
#define MLOG_RED(level, x)
Definition misc_log_ex.h:65
#define ENDL
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
#define MGINFO(x)
Definition misc_log_ex.h:80
#define MINFO(x)
Definition misc_log_ex.h:75
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
const arg_descriptor< bool > arg_help
const arg_descriptor< bool > arg_version
bool is_arg_defaulted(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
bool handle_error_helper(const boost::program_options::options_description &desc, F parser)
std::enable_if<!std::is_same< T, bool >::value, bool >::type has_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
const command_line::arg_descriptor< std::string, false, true, 2 > arg_data_dir
const command_line::arg_descriptor< bool > arg_regtest_on
const command_line::arg_descriptor< bool, false > arg_testnet_on
const command_line::arg_descriptor< std::string > arg_db_type
bool blockchain_valid_db_type(const std::string &db_type)
const command_line::arg_descriptor< bool, false > arg_stagenet_on
std::string blockchain_db_types(const std::string &sep)
const command_line::arg_descriptor< std::string, false, true, 2 > arg_log_file
const command_line::arg_descriptor< std::size_t > arg_max_log_files
const command_line::arg_descriptor< std::string > arg_log_level
const command_line::arg_descriptor< std::string, false, true, 2 > arg_config_file
const command_line::arg_descriptor< bool > arg_public_node
const command_line::arg_descriptor< bool > arg_os_version
const command_line::arg_descriptor< std::vector< std::string > > arg_command
const command_line::arg_descriptor< bool > arg_zmq_rpc_disabled
const command_line::arg_descriptor< std::string, false, true, 2 > arg_zmq_rpc_bind_port
const command_line::arg_descriptor< std::string > arg_zmq_rpc_bind_ip
const command_line::arg_descriptor< unsigned > arg_max_concurrency
const command_line::arg_descriptor< std::size_t > arg_max_log_file_size
bool daemonize(int argc, char const *argv[], T_executor &&executor, boost::program_options::variables_map const &vm)
void init_options(boost::program_options::options_description &hidden_options, boost::program_options::options_description &normal_options)
@ Warning
Useful when application has potentially harmful situtaions.
bool set_module_name_and_folder(const std::string &path_to_process_)
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
bool get_ip_int32_from_string(uint32_t &ip, const std::string &ip_str)
expect< epee::net_utils::network_address > get_network_address(const boost::string_ref address, const std::uint16_t default_port)
Definition parse.cpp:38
void set_max_concurrency(unsigned n)
Definition util.cpp:857
bool create_directories_if_necessary(const std::string &path)
creates directories for a path
Definition util.cpp:625
void set_stack_trace_log(const std::string &log)
bool on_startup()
Definition util.cpp:778
std::string get_os_version_string()
Returns the OS version string.
Definition util.cpp:566
uint16_t parse_public_rpc_port(const po::variables_map &vm)
Definition main.cpp:61
unsigned short uint16_t
Definition stdint.h:125
unsigned int uint32_t
Definition stdint.h:126
const command_line::arg_descriptor< std::string > rpc_login
Definition rpc_args.h:56
const command_line::arg_descriptor< std::string > rpc_bind_ip
Definition rpc_args.h:55
static boost::optional< epee::net_utils::ssl_options_t > process_ssl(const boost::program_options::variables_map &vm, const bool any_cert_option=false)
Definition rpc_args.cpp:197
static boost::optional< login > parse(std::string &&userpass, bool verify, const std::function< boost::optional< password_container >(bool)> &prompt)
Definition password.cpp:268
const char * address
Definition multisig.cpp:37
const char *const ELECTRONEUM_RELEASE_NAME
const char *const ELECTRONEUM_VERSION_FULL