Electroneum
srv.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 <boost/thread/mutex.hpp>
33 #include <boost/thread/thread.hpp>
34 
35 #include "include_base_utils.h"
36 #include "misc_log_ex.h"
38 #include "common/util.h"
39 
40 #include "net_load_tests.h"
41 
42 using namespace net_load_tests;
43 
44 #define EXIT_ON_ERROR(cond) { if (!(cond)) { LOG_PRINT_L0("ERROR: " << #cond); exit(1); } else {} }
45 
46 namespace
47 {
48  struct srv_levin_commands_handler : public test_levin_commands_handler
49  {
50  srv_levin_commands_handler(test_tcp_server& tcp_server)
51  : m_tcp_server(tcp_server)
52  , m_open_close_test_conn_id(boost::uuids::nil_uuid())
53  {
54  }
55 
56  virtual void on_connection_new(test_connection_context& context)
57  {
59  context.m_closed = false;
60 
61  //std::this_thread::sleep_for(std::chrono::milliseconds(10));
62 
63  boost::unique_lock<boost::mutex> lock(m_open_close_test_mutex);
64  if (!m_open_close_test_conn_id.is_nil())
65  {
66  EXIT_ON_ERROR(m_open_close_test_helper->handle_new_connection(context.m_connection_id, true));
67  }
68  }
69 
70  virtual void on_connection_close(test_connection_context& context)
71  {
73 
74  boost::unique_lock<boost::mutex> lock(m_open_close_test_mutex);
75  if (context.m_connection_id == m_open_close_test_conn_id)
76  {
77  LOG_PRINT_L0("Stop open/close test");
78  m_open_close_test_conn_id = boost::uuids::nil_uuid();
79  m_open_close_test_helper.reset(0);
80  }
81  }
82 
85 
86  BEGIN_INVOKE_MAP2(srv_levin_commands_handler)
87  HANDLE_NOTIFY_T2(CMD_CLOSE_ALL_CONNECTIONS, &srv_levin_commands_handler::handle_close_all_connections)
88  HANDLE_NOTIFY_T2(CMD_SHUTDOWN, &srv_levin_commands_handler::handle_shutdown)
89  HANDLE_NOTIFY_T2(CMD_SEND_DATA_REQUESTS, &srv_levin_commands_handler::handle_send_data_requests)
90  HANDLE_INVOKE_T2(CMD_GET_STATISTICS, &srv_levin_commands_handler::handle_get_statistics)
91  HANDLE_INVOKE_T2(CMD_RESET_STATISTICS, &srv_levin_commands_handler::handle_reset_statistics)
92  HANDLE_INVOKE_T2(CMD_START_OPEN_CLOSE_TEST, &srv_levin_commands_handler::handle_start_open_close_test)
94 
95  int handle_close_all_connections(int command, const CMD_CLOSE_ALL_CONNECTIONS::request& req, test_connection_context& context)
96  {
97  close_connections(context.m_connection_id);
98  return 1;
99  }
100 
101  int handle_get_statistics(int command, const CMD_GET_STATISTICS::request&, CMD_GET_STATISTICS::response& rsp, test_connection_context& /*context*/)
102  {
103  rsp.opened_connections_count = m_tcp_server.get_config_object().get_connections_count();
104  rsp.new_connection_counter = new_connection_counter();
105  rsp.close_connection_counter = close_connection_counter();
106  LOG_PRINT_L0("Statistics: " << rsp.to_string());
107  return 1;
108  }
109 
110  int handle_reset_statistics(int command, const CMD_RESET_STATISTICS::request&, CMD_RESET_STATISTICS::response& /*rsp*/, test_connection_context& /*context*/)
111  {
112  m_new_connection_counter.reset();
113  m_new_connection_counter.inc();
114  m_close_connection_counter.reset();
115  return 1;
116  }
117 
118  int handle_start_open_close_test(int command, const CMD_START_OPEN_CLOSE_TEST::request& req, CMD_START_OPEN_CLOSE_TEST::response&, test_connection_context& context)
119  {
120  boost::unique_lock<boost::mutex> lock(m_open_close_test_mutex);
121  if (0 == m_open_close_test_helper.get())
122  {
123  LOG_PRINT_L0("Start open/close test (" << req.open_request_target << ", " << req.max_opened_conn_count << ")");
124 
125  m_open_close_test_conn_id = context.m_connection_id;
126  m_open_close_test_helper.reset(new open_close_test_helper(m_tcp_server, req.open_request_target, req.max_opened_conn_count));
127  return 1;
128  }
129  else
130  {
131  return -1;
132  }
133  }
134 
135  int handle_shutdown(int command, const CMD_SHUTDOWN::request& req, test_connection_context& /*context*/)
136  {
137  LOG_PRINT_L0("Got shutdown request. Shutting down...");
138  m_tcp_server.send_stop_signal();
139  return 1;
140  }
141 
142  int handle_send_data_requests(int /*command*/, const CMD_SEND_DATA_REQUESTS::request& req, test_connection_context& context)
143  {
144  boost::uuids::uuid cmd_conn_id = context.m_connection_id;
145  m_tcp_server.get_config_object().foreach_connection([&](test_connection_context& ctx) {
146  if (ctx.m_connection_id != cmd_conn_id)
147  {
148  CMD_DATA_REQUEST::request req2;
149  req2.data.resize(req.request_size);
150 
151  bool r = epee::net_utils::async_invoke_remote_command2<CMD_DATA_REQUEST::response>(ctx.m_connection_id, CMD_DATA_REQUEST::ID, req2,
152  m_tcp_server.get_config_object(), [=](int code, const CMD_DATA_REQUEST::response& rsp, const test_connection_context&) {
153  if (code <= 0)
154  {
155  LOG_PRINT_L0("Failed to invoke CMD_DATA_REQUEST. code = " << code);
156  }
157  });
158  if (!r)
159  LOG_PRINT_L0("Failed to invoke CMD_DATA_REQUEST");
160  }
161  return true;
162  });
163 
164  return 1;
165  }
166 
167  private:
168  void close_connections(boost::uuids::uuid cmd_conn_id)
169  {
170  LOG_PRINT_L0("Closing connections. Number of opened connections: " << m_tcp_server.get_config_object().get_connections_count());
171 
172  size_t count = 0;
173  bool r = m_tcp_server.get_config_object().foreach_connection([&](test_connection_context& ctx) {
174  if (ctx.m_connection_id != cmd_conn_id)
175  {
176  ++count;
177  if (!ctx.m_closed)
178  {
179  ctx.m_closed = true;
180  m_tcp_server.get_config_object().close(ctx.m_connection_id);
181  }
182  else
183  {
184  LOG_PRINT_L0(count << " connection already closed");
185  }
186  }
187  return true;
188  });
189 
190  if (0 < count)
191  {
192  // Perhaps not all connections were closed, try to close it after 7 seconds
193  boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(m_tcp_server.get_io_service(), boost::posix_time::seconds(7)));
194  sh_deadline->async_wait([=](const boost::system::error_code& ec)
195  {
196  boost::shared_ptr<boost::asio::deadline_timer> t = sh_deadline; // Capture sh_deadline
197  if (!ec)
198  {
199  close_connections(cmd_conn_id);
200  }
201  else
202  {
203  LOG_PRINT_L0("ERROR: " << ec.message() << ':' << ec.value());
204  }
205  });
206  }
207  }
208 
209  private:
210  test_tcp_server& m_tcp_server;
211 
212  boost::uuids::uuid m_open_close_test_conn_id;
213  boost::mutex m_open_close_test_mutex;
214  std::unique_ptr<open_close_test_helper> m_open_close_test_helper;
215  };
216 }
217 
218 int main(int argc, char** argv)
219 {
220  TRY_ENTRY();
222  //set up logging options
223  mlog_configure(mlog_get_default_log_path("net_load_tests_srv.log"), true);
224 
225  size_t thread_count = (std::max)(min_thread_count, boost::thread::hardware_concurrency() / 2);
226 
228  if (!tcp_server.init_server(srv_port, "127.0.0.1"))
229  return 1;
230 
231  srv_levin_commands_handler *commands_handler = new srv_levin_commands_handler(tcp_server);
232  tcp_server.get_config_object().set_handler(commands_handler, [](epee::levin::levin_commands_handler<test_connection_context> *handler) { delete handler; });
233  tcp_server.get_config_object().m_invoke_timeout = 10000;
234  //tcp_server.get_config_object().m_max_packet_size = max_packet_size;
235 
236  if (!tcp_server.run_server(thread_count, true))
237  return 2;
238  return 0;
239  CATCH_ENTRY_L0("main", 1);
240 }
#define HANDLE_NOTIFY_T2(NOTIFY, func)
boost::uuids::uuid uuid
std::string mlog_get_default_log_path(const char *default_filename)
Definition: mlog.cpp:72
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
#define LOG_PRINT_L0(x)
Definition: misc_log_ex.h:99
bool init_server(uint32_t port, const std::string address="0.0.0.0", ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect)
bool run_server(size_t threads_count, bool wait=true, const boost::thread::attributes &attrs=boost::thread::attributes())
Run the server&#39;s io_service loop.
#define BEGIN_INVOKE_MAP2(owner_type)
bool on_startup()
Definition: util.cpp:778
mdb_size_t count(MDB_cursor *cur)
#define TRY_ENTRY()
Definition: misc_log_ex.h:151
#define EXIT_ON_ERROR(cond)
Definition: srv.cpp:44
int main(int argc, char **argv)
Definition: srv.cpp:218
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
Definition: zmq.h:98
virtual void on_connection_new(test_connection_context &context)
#define END_INVOKE_MAP2()
#define HANDLE_INVOKE_T2(COMMAND, func)
virtual void on_connection_close(test_connection_context &context)
#define CHAIN_LEVIN_NOTIFY_MAP2(context_type)
const std::string srv_port("36231")
const unsigned int min_thread_count
#define CHAIN_LEVIN_INVOKE_MAP2(context_type)
#define CATCH_ENTRY_L0(lacation, return_val)
Definition: misc_log_ex.h:165
const boost::uuids::uuid m_connection_id
t_protocol_handler::config_type & get_config_object()