Electroneum
Loading...
Searching...
No Matches
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
42using namespace net_load_tests;
43
44#define EXIT_ON_ERROR(cond) { if (!(cond)) { LOG_PRINT_L0("ERROR: " << #cond); exit(1); } else {} }
45
46namespace
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 {
149 req2.data.resize(req.request_size);
150
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
218int 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}
int main()
void set_handler(levin_commands_handler< t_connection_context > *handler, void(*destroy)(levin_commands_handler< t_connection_context > *)=NULL)
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)
t_protocol_handler::config_type & get_config_object()
bool run_server(size_t threads_count, bool wait=true, const boost::thread::attributes &attrs=boost::thread::attributes())
Run the server's io_service loop.
#define END_INVOKE_MAP2()
#define HANDLE_NOTIFY_T2(NOTIFY, func)
#define CHAIN_LEVIN_NOTIFY_MAP2(context_type)
#define CHAIN_LEVIN_INVOKE_MAP2(context_type)
#define BEGIN_INVOKE_MAP2(owner_type)
#define HANDLE_INVOKE_T2(COMMAND, func)
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
std::string mlog_get_default_log_path(const char *default_filename)
Definition mlog.cpp:72
#define CATCH_ENTRY_L0(lacation, return_val)
#define TRY_ENTRY()
#define LOG_PRINT_L0(x)
Definition misc_log_ex.h:99
bool async_invoke_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg &out_struct, t_transport &transport, const callback_t &cb, size_t inv_timeout=LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
const std::string srv_port("36231")
const unsigned int min_thread_count
epee::net_utils::boosted_tcp_server< test_levin_protocol_handler > test_tcp_server
bool on_startup()
Definition util.cpp:778
#define EXIT_ON_ERROR(cond)
Definition srv.cpp:44
virtual void on_connection_close(test_connection_context &context)
virtual void on_connection_new(test_connection_context &context)