Electroneum
Loading...
Searching...
No Matches
daemon.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 <memory>
33#include <stdexcept>
34#include <boost/algorithm/string/split.hpp>
35#include "misc_log_ex.h"
36#include "daemon/daemon.h"
37#include "rpc/daemon_handler.h"
38#include "rpc/zmq_server.h"
39
40#include "common/password.h"
41#include "common/util.h"
42#include "daemon/core.h"
43#include "daemon/p2p.h"
44#include "daemon/protocol.h"
45#include "daemon/rpc.h"
49#include "net/net_ssl.h"
50#include "version.h"
51
52using namespace epee;
53
54#include <functional>
55
56#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
57#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "daemon"
58
59namespace daemonize {
60
62private:
63 t_protocol protocol;
64public:
67 std::vector<std::unique_ptr<t_rpc>> rpcs;
68
70 boost::program_options::variables_map const & vm
71 )
72 : core{vm}
73 , protocol{vm, core, command_line::get_arg(vm, cryptonote::arg_offline)}
74 , p2p{vm, protocol}
75 {
76 // Handle circular dependencies
77 protocol.set_p2p_endpoint(p2p.get());
78 core.set_protocol(protocol.get());
79
82 rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, main_rpc_port, "core"});
83
85 if(!command_line::is_arg_defaulted(vm, restricted_rpc_port_arg))
86 {
87 auto restricted_rpc_port = command_line::get_arg(vm, restricted_rpc_port_arg);
88 rpcs.emplace_back(new t_rpc{vm, core, p2p, true, restricted_rpc_port, "restricted"});
89 }
90 }
91};
92
93void t_daemon::init_options(boost::program_options::options_description & option_spec)
94{
95 t_core::init_options(option_spec);
96 t_p2p::init_options(option_spec);
97 t_rpc::init_options(option_spec);
98}
99
101 boost::program_options::variables_map const & vm,
102 uint16_t public_rpc_port
103 )
104 : mp_internals{new t_internals{vm}},
105 public_rpc_port(public_rpc_port)
106{
110}
111
112t_daemon::~t_daemon() = default;
113
114// MSVC is brain-dead and can't default this...
116{
117 if (this != &other)
118 {
119 mp_internals = std::move(other.mp_internals);
120 other.mp_internals.reset(nullptr);
121 public_rpc_port = other.public_rpc_port;
122 }
123}
124
125// or this
127{
128 if (this != &other)
129 {
130 mp_internals = std::move(other.mp_internals);
131 other.mp_internals.reset(nullptr);
132 public_rpc_port = other.public_rpc_port;
133 }
134 return *this;
135}
136
137bool t_daemon::run(bool interactive)
138{
139 if (nullptr == mp_internals)
140 {
141 throw std::runtime_error{"Can't run stopped daemon"};
142 }
143
144 std::atomic<bool> stop(false), shutdown(false);
145 boost::thread stop_thread = boost::thread([&stop, &shutdown, this] {
146 while (!stop)
148 if (shutdown)
149 this->stop_p2p();
150 });
152 stop = true;
153 stop_thread.join();
154 });
155 tools::signal_handler::install([&stop, &shutdown](int){ stop = shutdown = true; });
156
157 try
158 {
159 if (!mp_internals->core.run())
160 return false;
161
162 for(auto& rpc: mp_internals->rpcs)
163 rpc->run();
164
165 std::unique_ptr<daemonize::t_command_server> rpc_commands;
166 if (interactive && mp_internals->rpcs.size())
167 {
168 // The first three variables are not used when the fourth is false
169 rpc_commands.reset(new daemonize::t_command_server(0, 0, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_disabled, false, mp_internals->rpcs.front()->get_server()));
170 rpc_commands->start_handling(std::bind(&daemonize::t_daemon::stop_p2p, this));
171 }
172
173 cryptonote::rpc::DaemonHandler rpc_daemon_handler(mp_internals->core.get(), mp_internals->p2p.get());
174 cryptonote::rpc::ZmqServer zmq_server(rpc_daemon_handler);
175
176 if (!zmq_rpc_disabled)
177 {
178 if (!zmq_server.addTCPSocket(zmq_rpc_bind_address, zmq_rpc_bind_port))
179 {
180 LOG_ERROR(std::string("Failed to add TCP Socket (") + zmq_rpc_bind_address
181 + ":" + zmq_rpc_bind_port + ") to ZMQ RPC Server");
182
183 if (rpc_commands)
184 rpc_commands->stop_handling();
185
186 for(auto& rpc : mp_internals->rpcs)
187 rpc->stop();
188
189 return false;
190 }
191
192 MINFO("Starting ZMQ server...");
193 zmq_server.run();
194
195 MINFO(std::string("ZMQ server started at ") + zmq_rpc_bind_address
196 + ":" + zmq_rpc_bind_port + ".");
197 }
198 else
199 MINFO("ZMQ server disabled");
200
201 if (public_rpc_port > 0)
202 {
203 MGINFO("Public RPC port " << public_rpc_port << " will be advertised to other peers over P2P");
204 mp_internals->p2p.get().set_rpc_port(public_rpc_port);
205 }
206
207 mp_internals->p2p.run(); // blocks until p2p goes down
208
209 if (rpc_commands)
210 rpc_commands->stop_handling();
211
212 if (!zmq_rpc_disabled)
213 zmq_server.stop();
214
215 for(auto& rpc : mp_internals->rpcs)
216 rpc->stop();
217 MGINFO("Node stopped.");
218 return true;
219 }
220 catch (std::exception const & ex)
221 {
222 MFATAL("Uncaught exception! " << ex.what());
223 return false;
224 }
225 catch (...)
226 {
227 MFATAL("Uncaught exception!");
228 return false;
229 }
230}
231
233{
234 if (nullptr == mp_internals)
235 {
236 throw std::runtime_error{"Can't stop stopped daemon"};
237 }
238 mp_internals->p2p.stop();
239 for(auto& rpc : mp_internals->rpcs)
240 rpc->stop();
241
242 mp_internals.reset(nullptr); // Ensure resources are cleaned up before we return
243}
244
245void t_daemon::stop_p2p()
246{
247 if (nullptr == mp_internals)
248 {
249 throw std::runtime_error{"Can't send stop signal to a stopped daemon"};
250 }
251 mp_internals->p2p.get().send_stop_signal();
252}
253
254} // namespace daemonize
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 addTCPSocket(boost::string_ref address, boost::string_ref port)
static void init_options(boost::program_options::options_description &option_spec)
Definition core.h:46
static void init_options(boost::program_options::options_description &option_spec)
Definition daemon.cpp:93
t_daemon & operator=(t_daemon &&other)
Definition daemon.cpp:126
t_daemon(boost::program_options::variables_map const &vm, uint16_t public_rpc_port=0)
Definition daemon.cpp:100
static void init_options(boost::program_options::options_description &option_spec)
Definition p2p.h:50
static void init_options(boost::program_options::options_description &option_spec)
Definition rpc.h:45
t_daemon(boost::program_options::variables_map const &_vm)
static bool install(T t)
installs a signal handler
Definition util.h:164
#define MFATAL(x)
Definition misc_log_ex.h:72
#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
bool is_arg_defaulted(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)
Holds cryptonote related classes and helpers.
Definition ban.cpp:40
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
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
bool sleep_no_w(long ms)
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
unsigned short uint16_t
Definition stdint.h:125
t_internals(boost::program_options::variables_map const &vm)
Definition daemon.cpp:69
std::vector< std::unique_ptr< t_rpc > > rpcs
Definition daemon.cpp:67