34#include <boost/asio/post.hpp>
35#include <boost/foreach.hpp>
36#include <boost/uuid/random_generator.hpp>
37#include <boost/chrono.hpp>
38#include <boost/utility/value_init.hpp>
39#include <boost/asio/bind_executor.hpp>
40#include <boost/asio/deadline_timer.hpp>
41#include <boost/date_time/posix_time/posix_time.hpp>
42#include <boost/thread/condition_variable.hpp>
43#include <boost/make_shared.hpp>
44#include <boost/thread.hpp>
55#undef MONERO_DEFAULT_LOG_CATEGORY
56#define MONERO_DEFAULT_LOG_CATEGORY "net"
58#define AGGRESSIVE_TIMEOUT_THRESHOLD 120
59#define NEW_CONNECTION_TIMEOUT_LOCAL 1200000
60#define NEW_CONNECTION_TIMEOUT_REMOTE 10000
61#define DEFAULT_TIMEOUT_MS_LOCAL 1800000
62#define DEFAULT_TIMEOUT_MS_REMOTE 300000
63#define TIMEOUT_EXTRA_MS_PER_BYTE 0.2
73 CHECK_AND_ASSERT_THROW_MES(
bool(ptr),
"shared_state cannot be null");
83 static std::mutex hosts_mutex;
84 std::lock_guard<std::mutex> guard(hosts_mutex);
85 static std::map<std::string, unsigned int> hosts;
86 unsigned int &val = hosts[
m_host];
88 MTRACE(
"New connection from host " <<
m_host <<
": " << val);
90 MTRACE(
"Closed connection from host " <<
m_host <<
": " << val);
91 CHECK_AND_ASSERT_THROW_MES(delta >= 0 || val >= (
unsigned)-delta,
"Count would go negative");
92 CHECK_AND_ASSERT_THROW_MES(delta <= 0 || val <= std::numeric_limits<unsigned int>::max() - (
unsigned)delta,
"Count would wrap");
102 const unsigned shift = (
104 std::min(std::max(count, 1u) - 1, 8u) :
117 return std::chrono::duration_cast<connection<T>::duration_t>(
118 std::chrono::duration<double, std::chrono::milliseconds::period>(
146 if (
m_state.timers.general.wait_expire) {
147 m_state.timers.general.cancel_expire =
true;
148 m_state.timers.general.reset_expire =
true;
151 duration + (add ? (
m_timers.general.expiry() - std::chrono::steady_clock::now()) :
duration_t{}),
159 duration + (add ? (
m_timers.general.expiry() - std::chrono::steady_clock::now()) :
duration_t{}),
170 if (
m_state.timers.general.wait_expire)
172 m_state.timers.general.wait_expire =
true;
174 auto on_wait = [
this,
self] {
175 std::lock_guard<std::mutex> guard(
m_state.lock);
176 m_state.timers.general.wait_expire =
false;
177 if (
m_state.timers.general.cancel_expire) {
178 m_state.timers.general.cancel_expire =
false;
179 if (
m_state.timers.general.reset_expire) {
180 m_state.timers.general.reset_expire =
false;
194 boost::asio::post(
m_strand, on_wait);
201 if (!
m_state.timers.general.wait_expire)
203 m_state.timers.general.cancel_expire =
true;
204 m_state.timers.general.reset_expire =
false;
211 if (
m_state.socket.wait_handshake)
219 m_state.socket.wait_read =
true;
220 boost::asio::async_read(
223 m_state.data.read.buffer.data(),
224 m_state.data.read.buffer.size()
227 boost::asio::bind_executor(
229 [
this,
self](
const ec_t &ec,
size_t bytes_transferred){
230 std::lock_guard<std::mutex> guard(m_state.lock);
231 m_state.socket.wait_read = false;
232 if (m_state.socket.cancel_read) {
233 m_state.socket.cancel_read = false;
234 state_status_check();
236 else if (ec.value()) {
241 static_cast<const unsigned char *
>(
242 m_state.data.read.buffer.data()
247 m_state.ssl.enabled = false;
248 finish_read(bytes_transferred);
251 m_state.ssl.detected = true;
260 m_state.socket.wait_handshake =
true;
261 auto on_handshake = [
this, self](
const ec_t &ec,
size_t bytes_transferred){
262 std::lock_guard<std::mutex> guard(m_state.lock);
263 m_state.socket.wait_handshake =
false;
264 if (m_state.socket.cancel_handshake) {
265 m_state.socket.cancel_handshake =
false;
266 state_status_check();
268 else if (ec.value()) {
271 socket_t::shutdown_both,
275 m_state.socket.connected =
false;
279 m_state.ssl.handshaked =
true;
284 const auto handshake = handshake_t::server;
285 static_cast<shared_state&
>(
290 [
this, self, on_handshake]{
294 m_state.data.read.buffer.data(),
295 m_state.ssl.forced ? 0 :
298 boost::asio::bind_executor(m_strand, on_handshake)
307 if (
m_state.timers.throttle.in.wait_expire ||
m_state.socket.wait_read ||
314 auto calc_duration = []{
318 return std::chrono::duration_cast<connection<T>::duration_t>(
319 std::chrono::duration<double, std::chrono::seconds::period>(
322 ).get_sleep_time_after_tick(1),
328 const auto duration = calc_duration();
330 m_timers.throttle.in.expires_after(duration);
331 m_state.timers.throttle.in.wait_expire =
true;
332 auto on_wait = [
this,
self](
const ec_t &ec){
333 std::lock_guard<std::mutex> guard(
m_state.lock);
334 m_state.timers.throttle.in.wait_expire =
false;
335 if (
m_state.timers.throttle.in.cancel_expire) {
336 m_state.timers.throttle.in.cancel_expire =
false;
343 std::lock_guard<std::mutex> guard(
m_state.lock);
344 const bool error_status =
m_state.timers.throttle.in.cancel_expire || ec.value();
346 boost::asio::post(
m_strand, std::bind(on_wait, ec));
348 m_state.timers.throttle.in.wait_expire =
false;
355 m_state.socket.wait_read =
true;
356 auto on_read = [
this,
self](
const ec_t &ec,
size_t bytes_transferred){
357 std::lock_guard<std::mutex> guard(
m_state.lock);
358 m_state.socket.wait_read =
false;
359 if (
m_state.socket.cancel_read) {
360 m_state.socket.cancel_read =
false;
361 state_status_check();
367 m_state.stat.in.throttle.handle_trafic_exact(bytes_transferred);
369 m_conn_context.m_current_speed_down =
speed;
370 m_conn_context.m_max_speed_down = std::max(
371 m_conn_context.m_max_speed_down,
374 if (speed_limit_is_enabled()) {
376 network_throttle_manager_t::m_lock_get_global_throttle_in
378 network_throttle_manager_t::get_global_throttle_in(
379 ).handle_trafic_exact(bytes_transferred);
382 m_conn_context.m_last_recv = time(NULL);
383 m_conn_context.m_recv_cnt += bytes_transferred;
384 start_timer(get_timeout_from_bytes_read(bytes_transferred),
true);
386 finish_read(bytes_transferred);
389 if (!m_state.ssl.enabled)
392 m_state.data.read.buffer.data(),
393 m_state.data.read.buffer.size()
395 boost::asio::bind_executor(m_strand, on_read)
400 [
this, self, on_read]{
406 boost::asio::bind_executor(m_strand, on_read)
420 m_state.socket.handle_read =
true;
424 [
this,
self, bytes_transferred]{
426 reinterpret_cast<char *
>(
m_state.data.read.buffer.data()),
429 std::lock_guard<std::mutex> guard(
m_state.lock);
434 m_state.socket.handle_read =
false;
442 std::lock_guard<std::mutex> guard(
m_state.lock);
443 m_state.socket.handle_read =
false;
450 if (
m_state.socket.wait_write) {
453 socket_t::shutdown_receive,
456 m_state.socket.shutdown_read =
true;
458 if (!
m_state.socket.wait_write || ec.value()) {
471 if (
m_state.timers.throttle.out.wait_expire ||
m_state.socket.wait_write ||
472 m_state.data.write.queue.empty() ||
479 auto calc_duration = [
this]{
483 return std::chrono::duration_cast<connection<T>::duration_t>(
484 std::chrono::duration<double, std::chrono::seconds::period>(
487 ).get_sleep_time_after_tick(
488 m_state.data.write.queue.back().size()
495 const auto duration = calc_duration();
497 m_timers.throttle.out.expires_after(duration);
498 m_state.timers.throttle.out.wait_expire =
true;
499 auto on_wait = [
this, self](
const ec_t &ec){
500 std::lock_guard<std::mutex> guard(
m_state.lock);
501 m_state.timers.throttle.out.wait_expire =
false;
502 if (
m_state.timers.throttle.out.cancel_expire) {
503 m_state.timers.throttle.out.cancel_expire =
false;
504 state_status_check();
509 m_timers.throttle.out.async_wait([
this, self, on_wait](
const ec_t &ec){
510 std::lock_guard<std::mutex> guard(m_state.lock);
511 const bool error_status = m_state.timers.throttle.out.cancel_expire || ec.value();
513 boost::asio::post(m_strand, std::bind(on_wait, ec));
515 m_state.timers.throttle.out.wait_expire =
false;
522 m_state.socket.wait_write =
true;
523 auto on_write = [
this, self](
const ec_t &ec,
size_t bytes_transferred){
524 std::lock_guard<std::mutex> guard(m_state.lock);
525 m_state.socket.wait_write =
false;
526 if (m_state.socket.cancel_write) {
527 m_state.socket.cancel_write =
false;
528 m_state.data.write.queue.clear();
529 m_state.data.write.total_bytes = 0;
530 state_status_check();
532 else if (ec.value()) {
533 m_state.data.write.queue.clear();
534 m_state.data.write.total_bytes = 0;
539 m_state.stat.out.throttle.handle_trafic_exact(bytes_transferred);
540 const auto speed = m_state.stat.out.throttle.get_current_speed();
541 m_conn_context.m_current_speed_up = speed;
542 m_conn_context.m_max_speed_down = std::max(
543 m_conn_context.m_max_speed_down,
546 if (speed_limit_is_enabled()) {
548 network_throttle_manager_t::m_lock_get_global_throttle_out
550 network_throttle_manager_t::get_global_throttle_out(
551 ).handle_trafic_exact(bytes_transferred);
553 connection_basic::logger_handle_net_write(bytes_transferred);
554 m_conn_context.m_last_send =
time(NULL);
555 m_conn_context.m_send_cnt += bytes_transferred;
557 start_timer(get_default_timeout(),
true);
559 const std::size_t byte_count = m_state.data.write.queue.back().size();
560 assert(bytes_transferred == byte_count);
561 m_state.data.write.queue.pop_back();
562 m_state.data.write.total_bytes -=
563 std::min(m_state.data.write.total_bytes, byte_count);
564 m_state.condition.notify_all();
565 if (m_state.data.write.queue.empty() && m_state.socket.shutdown_read) {
573 if (!m_state.ssl.enabled)
574 boost::asio::async_write(
575 connection_basic::socket_.next_layer(),
577 m_state.data.write.queue.back().data(),
578 m_state.data.write.queue.back().size()
580 boost::asio::bind_executor(m_strand, on_write)
585 [
this, self, on_write]{
586 boost::asio::async_write(
587 connection_basic::socket_,
589 m_state.data.write.queue.back().data(),
590 m_state.data.write.queue.back().size()
592 boost::asio::bind_executor(m_strand, on_write)
601 if (
m_state.socket.wait_shutdown)
604 m_state.socket.wait_shutdown =
true;
605 auto on_shutdown = [
this,
self](
const ec_t &ec){
606 std::lock_guard<std::mutex> guard(
m_state.lock);
607 m_state.socket.wait_shutdown =
false;
608 if (
m_state.socket.cancel_shutdown) {
609 m_state.socket.cancel_shutdown =
false;
631 [
this,
self, on_shutdown]{
633 boost::asio::bind_executor(
m_strand, on_shutdown)
643 bool wait_socket =
false;
644 if (
m_state.socket.wait_handshake)
645 wait_socket =
m_state.socket.cancel_handshake =
true;
646 if (
m_state.timers.throttle.in.wait_expire) {
647 m_state.timers.throttle.in.cancel_expire =
true;
651 wait_socket =
m_state.socket.cancel_read =
true;
652 if (
m_state.timers.throttle.out.wait_expire) {
653 m_state.timers.throttle.out.cancel_expire =
true;
657 wait_socket =
m_state.socket.cancel_write =
true;
658 if (
m_state.socket.wait_shutdown)
659 wait_socket =
m_state.socket.cancel_shutdown =
true;
671 m_state.protocol.wait_release =
true;
675 m_state.protocol.wait_release =
false;
676 m_state.protocol.released =
true;
692 m_state.condition.notify_all();
700 if (
m_state.timers.general.wait_expire)
702 if (
m_state.socket.wait_handshake)
704 if (
m_state.timers.throttle.in.wait_expire)
708 if (
m_state.socket.handle_read)
710 if (
m_state.timers.throttle.out.wait_expire)
715 if (
m_state.socket.wait_shutdown)
717 if (
m_state.protocol.wait_init)
719 if (
m_state.protocol.wait_callback)
721 if (
m_state.protocol.wait_release)
723 if (
m_state.socket.connected) {
727 socket_t::shutdown_both,
731 m_state.socket.connected =
false;
752 m_state.condition.notify_all();
760 if (
m_state.timers.general.wait_expire)
762 if (
m_state.socket.wait_handshake)
764 if (
m_state.timers.throttle.in.wait_expire)
768 if (
m_state.socket.handle_read)
770 if (
m_state.timers.throttle.out.wait_expire)
779 if (
m_state.socket.wait_shutdown)
781 if (
m_state.protocol.wait_init)
783 if (
m_state.protocol.wait_callback)
785 if (
m_state.protocol.wait_release)
787 if (
m_state.socket.connected) {
790 socket_t::shutdown_both,
794 m_state.socket.connected =
false;
805 std::lock_guard<std::mutex> guard(
m_state.lock);
813 std::lock_guard<std::mutex> guard(
m_state.lock);
816 if (std::numeric_limits<std::size_t>::max() -
m_state.data.write.total_bytes < message.size())
821 auto wait_consume = [
this] {
822 auto random_delay = []{
823 using engine = std::mt19937;
824 std::random_device
dev;
825 std::seed_seq::result_type rand[
828 std::generate_n(rand, engine::state_size, std::ref(
dev));
829 std::seed_seq
seed(rand, rand + engine::state_size);
831 return std::chrono::milliseconds(
832 std::uniform_int_distribution<>(5000, 6000)(rng)
844 m_state.data.write.wait_consume =
true;
852 m_state.data.write.queue.size() <=
854 m_state.data.write.total_bytes <=
860 m_state.data.write.wait_consume =
false;
868 auto wait_sender = [
this] {
873 m_state.status != status_t::RUNNING ||
874 !m_state.data.write.wait_consume
882 constexpr size_t CHUNK_SIZE = 32 * 1024;
884 message.size() <= 2 * CHUNK_SIZE
888 const std::size_t byte_count = message.size();
889 m_state.data.write.queue.emplace_front(std::move(message));
890 m_state.data.write.total_bytes += byte_count;
894 while (!message.empty()) {
897 m_state.data.write.queue.emplace_front(
898 message.take_slice(CHUNK_SIZE)
900 m_state.data.write.total_bytes +=
m_state.data.write.queue.front().size();
904 m_state.condition.notify_all();
911 bool is_multithreaded,
912 boost::optional<network_address> real_remote
915 std::unique_lock<std::mutex> guard(
m_state.lock);
926 endpoint.address().is_v6() ?
933 boost::asio::detail::socket_ops::host_to_network_long(
934 endpoint.address().to_v4().to_uint()
945 if (filter && !filter->is_remote_host_allowed(*real_remote))
951 if (is_income && limit && limit->is_host_limit(*real_remote))
955 #if !defined(_WIN32) || !defined(__i686)
957 boost::asio::detail::socket_option::integer<IPPROTO_IP, IP_TOS>{
966 boost::asio::ip::tcp::no_delay{
false},
973 boost::uuids::random_generator()(),
978 m_host = real_remote->host_str();
980 m_local = real_remote->is_loopback() || real_remote->is_local();
987 m_state.socket.connected =
true;
990 std::chrono::milliseconds(
994 m_state.protocol.wait_init =
true;
998 m_state.protocol.wait_init =
false;
999 m_state.protocol.initialized =
true;
1004 else if (!is_income || !
m_state.ssl.enabled)
1011 template<
typename T>
1030 template<
typename T>
1049 template<
typename T>
1052 std::lock_guard<std::mutex> guard(
m_state.lock);
1062 template<
typename T>
1065 bool is_multithreaded
1071 template<
typename T>
1074 bool is_multithreaded,
1081 template<
typename T>
1084 std::lock_guard<std::mutex> guard(
m_state.lock);
1091 port =
"<not connected>";
1094 address = endpoint.address().to_string();
1095 port = std::to_string(endpoint.port());
1102 " (via " <<
address <<
":" << port <<
")"
1106 template<
typename T>
1112 template<
typename T>
1118 template<
typename T>
1121 return send(std::move(message));
1124 template<
typename T>
1130 template<
typename T>
1133 std::lock_guard<std::mutex> guard(
m_state.lock);
1140 template<
typename T>
1154 template<
typename T>
1157 std::lock_guard<std::mutex> guard(
m_state.lock);
1161 ++
m_state.protocol.wait_callback;
1164 std::lock_guard<std::mutex> guard(
m_state.lock);
1165 --
m_state.protocol.wait_callback;
1174 template<
typename T>
1180 template<
typename T>
1185 std::lock_guard<std::mutex> guard(
m_state.lock);
1187 ++
m_state.protocol.reference_counter;
1190 catch (boost::bad_weak_ptr &exception) {
1195 template<
typename T>
1199 std::lock_guard<std::mutex> guard(
m_state.lock);
1200 if (!(--
m_state.protocol.reference_counter))
1201 self = std::move(this->self);
1205 template<
typename T>
1208 std::lock_guard<std::mutex> guard(
m_state.lock);
1212 template<
class t_protocol_handler>
1231 template<
class t_protocol_handler>
1249 template<
class t_protocol_handler>
1256 template<
class t_protocol_handler>
1264 template<
class t_protocol_handler>
1266 uint32_t port_ipv6,
const std::string& address_ipv6,
bool use_ipv6,
bool require_ipv4,
1279 m_state->configure_ssl(std::move(ssl_options));
1281 std::string ipv4_failed =
"";
1282 std::string ipv6_failed =
"";
1284 boost::asio::ip::tcp::resolver resolver(
io_context_);
1288 const auto results = resolver.resolve(
1289 address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::canonical_name
1291 acceptor_.open(results.begin()->endpoint().protocol());
1293 acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(
true));
1297 boost::asio::ip::tcp::endpoint binded_endpoint =
acceptor_.local_endpoint();
1298 m_port = binded_endpoint.port();
1299 MDEBUG(
"start accept (IPv4)");
1303 boost::asio::placeholders::error));
1305 catch (
const std::exception &e)
1307 ipv4_failed = e.what();
1310 if (ipv4_failed !=
"")
1312 MERROR(
"Failed to bind IPv4: " << ipv4_failed);
1315 throw std::runtime_error(
"Failed to bind IPv4 (set to required)");
1323 if (port_ipv6 == 0) port_ipv6 = port;
1325 const auto results = resolver.resolve(
1326 address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::canonical_name
1331 acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(
true));
1336 boost::asio::ip::tcp::endpoint binded_endpoint =
acceptor_ipv6.local_endpoint();
1338 MDEBUG(
"start accept (IPv6)");
1342 boost::asio::placeholders::error));
1344 catch (
const std::exception &e)
1346 ipv6_failed = e.what();
1350 if (use_ipv6 && ipv6_failed !=
"")
1352 MERROR(
"Failed to bind IPv6: " << ipv6_failed);
1353 if (ipv4_failed !=
"")
1355 throw std::runtime_error(
"Failed to bind IPv4 and IPv6");
1361 catch (
const std::exception &e)
1363 MFATAL(
"Error starting server: " << e.what());
1368 MFATAL(
"Error starting server");
1373 template<
class t_protocol_handler>
1375 const std::string port_ipv6,
const std::string address_ipv6,
bool use_ipv6,
bool require_ipv4,
1382 MERROR(
"Failed to convert port no = " << port);
1387 MERROR(
"Failed to convert port no = " << port_ipv6);
1390 return this->
init_server(p,
address, p_ipv6, address_ipv6, use_ipv6, require_ipv4, std::move(ssl_options));
1393 template<
class t_protocol_handler>
1399 thread_name += boost::to_string(local_thr_index) +
"]";
1400 MLOG_SET_THREAD_NAME(thread_name);
1409 catch(
const std::exception& ex)
1411 _erro(
"Exception at server worker thread, what=" << ex.what());
1415 _erro(
"Exception at server worker thread, unknown execption");
1420 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::worker_thread",
false);
1423 template<
class t_protocol_handler>
1428 if (it==
server_type_map.end())
throw std::runtime_error(
"Unknown prefix/server type:" + std::string(prefix_name));
1429 auto connection_type = it->second;
1430 MINFO(
"Set server type to: " << connection_type <<
" from name: " <<
m_thread_name_prefix <<
", prefix_name = " << prefix_name);
1433 template<
class t_protocol_handler>
1440 template<
class t_protocol_handler>
1447 template<
class t_protocol_handler>
1451 m_state->response_soft_limit = limit;
1454 template<
class t_protocol_handler>
1460 MLOG_SET_THREAD_NAME(
"[SRV_MAIN]");
1466 for (std::size_t i = 0; i < threads_count; ++i)
1468 boost::shared_ptr<boost::thread> thread(
new boost::thread(
1477 _fact(
"JOINING all threads");
1478 for (std::size_t i = 0; i <
m_threads.size(); ++i) {
1481 _fact(
"JOINING all threads - almost");
1483 _fact(
"JOINING all threads - DONE");
1487 _dbg1(
"Reiniting OK.");
1494 _dbg1(
"Net service stopped without stop request, restarting...");
1497 _dbg1(
"Reiniting service failed, exit.");
1501 _dbg1(
"Reiniting OK.");
1506 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::run_server",
false);
1509 template<
class t_protocol_handler>
1514 BOOST_FOREACH(boost::shared_ptr<boost::thread>& thp,
m_threads)
1516 if(thp->get_id() == boost::this_thread::get_id())
1522 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::is_thread_worker",
false);
1525 template<
class t_protocol_handler>
1529 boost::chrono::milliseconds ms(wait_mseconds);
1530 for (std::size_t i = 0; i <
m_threads.size(); ++i)
1534 _dbg1(
"Interrupting thread " <<
m_threads[i]->native_handle());
1539 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::timed_wait_server_stop",
false);
1542 template<
class t_protocol_handler>
1547 state->stop_signal_sent =
true;
1557 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::send_stop_signal()",
void());
1560 template<
class t_protocol_handler>
1566 template<
class t_protocol_handler>
1572 template<
class t_protocol_handler>
1575 MDEBUG(
"handle_accept");
1577 boost::asio::ip::tcp::acceptor* current_acceptor = &
acceptor_;
1587 bool accept_started =
false;
1593 const char *ssl_message =
"unknown";
1594 switch ((*current_new_connection)->get_ssl_support())
1600 MDEBUG(
"New server for RPC connections, SSL " << ssl_message);
1601 (*current_new_connection)->setRpcStation();
1605 current_acceptor->async_accept((*current_new_connection)->socket(),
1606 boost::bind(accept_function_pointer,
this,
1607 boost::asio::placeholders::error));
1608 accept_started =
true;
1610 boost::asio::socket_base::keep_alive opt(
true);
1611 conn->socket().set_option(opt);
1623 conn->save_dbg_log();
1628 MERROR(
"Error in boosted_tcp_server<t_protocol_handler>::handle_accept: " << e);
1631 catch (
const std::exception &e)
1633 MERROR(
"Exception in boosted_tcp_server<t_protocol_handler>::handle_accept: " << e.what());
1640 _erro(
"Some problems at accept: " << e.message() <<
", connections_count = " <<
m_state->sock_count);
1643 current_acceptor->async_accept((*current_new_connection)->socket(),
1644 boost::bind(accept_function_pointer,
this,
1645 boost::asio::placeholders::error));
1648 template<
class t_protocol_handler>
1651 if(std::addressof(
get_io_context()) == std::addressof(sock.get_executor().context()))
1656 conn->get_context(out);
1657 conn->save_dbg_log();
1663 MWARNING(out <<
" was not added, socket/io_context mismatch");
1668 template<
class t_protocol_handler>
1673 sock_.open(remote_endpoint.protocol());
1674 if(bind_ip !=
"0.0.0.0" && bind_ip !=
"0" && bind_ip !=
"" )
1676 boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip), 0);
1677 boost::system::error_code ec;
1678 sock_.bind(local_endpoint, ec);
1681 MERROR(
"Error binding to " << bind_ip <<
": " << ec.message());
1682 if (sock_.is_open())
1692 boost::system::error_code ec = boost::asio::error::would_block;
1695 struct local_async_context
1697 boost::system::error_code ec;
1698 boost::mutex connect_mut;
1699 boost::condition_variable cond;
1702 boost::shared_ptr<local_async_context> local_shared_context(
new local_async_context());
1703 local_shared_context->ec = boost::asio::error::would_block;
1704 boost::unique_lock<boost::mutex> lock(local_shared_context->connect_mut);
1705 auto connect_callback = [](boost::system::error_code ec_, boost::shared_ptr<local_async_context> shared_context)
1707 shared_context->connect_mut.lock(); shared_context->ec = ec_; shared_context->cond.notify_one(); shared_context->connect_mut.unlock();
1710 sock_.async_connect(remote_endpoint, std::bind<void>(connect_callback, std::placeholders::_1, local_shared_context));
1711 while(local_shared_context->ec == boost::asio::error::would_block)
1713 bool r = local_shared_context->cond.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(conn_timeout));
1716 if (sock_.is_open())
1720 if(local_shared_context->ec == boost::asio::error::would_block && !r)
1724 _dbg3(
"Failed to connect to " << adr <<
":" << port <<
", because of timeout (" << conn_timeout <<
")");
1728 ec = local_shared_context->ec;
1730 if (ec || !sock_.is_open())
1732 _dbg3(
"Some problems at connect, message: " << ec.message());
1733 if (sock_.is_open())
1738 _dbg3(
"Connected success to " << adr <<
':' << port);
1740 const ssl_support_t ssl_support = new_connection_l->get_ssl_support();
1744 MDEBUG(
"Handshaking SSL...");
1745 if (!new_connection_l->handshake(boost::asio::ssl::stream_base::client))
1749 boost::system::error_code ignored_ec;
1750 sock_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
1754 MERROR(
"SSL handshake failed");
1755 if (sock_.is_open())
1763 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::try_connect",
CONNECT_FAILURE);
1766 template<
class t_protocol_handler>
1774 MDEBUG(
"connections_ size now " <<
connections_.size());
1777 boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
1779 bool try_ipv6 =
false;
1781 boost::asio::ip::tcp::resolver resolver(
io_context_);
1782 boost::asio::ip::tcp::resolver::results_type results{};
1783 boost::system::error_code resolve_error;
1788 results = resolver.resolve(
1789 boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
1792 catch (
const boost::system::system_error& e)
1794 if (!
m_use_ipv6 || (resolve_error != boost::asio::error::host_not_found &&
1795 resolve_error != boost::asio::error::host_not_found_try_again))
1806 std::string bind_ip_to_use;
1812 _erro(
"Failed to resolve " << adr);
1818 MINFO(
"Resolving address as IPv4 failed, trying IPv6");
1823 bind_ip_to_use = bind_ip;
1828 results = resolver.resolve(
1829 boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
1834 _erro(
"Failed to resolve " << adr);
1839 if (bind_ip ==
"0.0.0.0")
1841 bind_ip_to_use =
"::";
1845 bind_ip_to_use =
"";
1852 const auto iterator = results.begin();
1854 MDEBUG(
"Trying to connect to " << adr <<
":" << port <<
", bind_ip = " << bind_ip_to_use);
1857 boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
1859 auto try_connect_result =
try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_support);
1865 MERROR(
"SSL handshake failed on an autodetect connection, reconnecting without SSL");
1866 new_connection_l->disable_ssl();
1879 new_connection_l->get_context(conn_context);
1884 _erro(
"[sock " << new_connection_l->socket().native_handle() <<
"] Failed to start connection, connections_count = " <<
m_state->sock_count);
1887 new_connection_l->save_dbg_log();
1891 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::connect",
false);
1894 template<
class t_protocol_handler>
template<
class t_callback>
1901 MDEBUG(
"connections_ size now " <<
connections_.size());
1904 boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
1906 bool try_ipv6 =
false;
1908 boost::asio::ip::tcp::resolver resolver(
io_context_);
1909 boost::asio::ip::tcp::resolver::results_type results{};
1910 boost::system::error_code resolve_error;
1915 results = resolver.resolve(
1916 boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
1919 catch (
const boost::system::system_error& e)
1921 if (!
m_use_ipv6 || (resolve_error != boost::asio::error::host_not_found &&
1922 resolve_error != boost::asio::error::host_not_found_try_again))
1937 _erro(
"Failed to resolve " << adr);
1942 MINFO(
"Resolving address as IPv4 failed, trying IPv6");
1948 results = resolver.resolve(
1949 boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
1954 _erro(
"Failed to resolve " << adr);
1959 boost::asio::ip::tcp::endpoint remote_endpoint(*results.begin());
1961 sock_.open(remote_endpoint.protocol());
1962 if(bind_ip !=
"0.0.0.0" && bind_ip !=
"0" && bind_ip !=
"" )
1964 boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip.c_str()), 0);
1965 boost::system::error_code ec;
1966 sock_.bind(local_endpoint, ec);
1969 MERROR(
"Error binding to " << bind_ip <<
": " << ec.message());
1970 if (sock_.is_open())
1976 boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(
new boost::asio::deadline_timer(
io_context_));
1978 sh_deadline->expires_from_now(boost::posix_time::milliseconds(conn_timeout));
1979 sh_deadline->async_wait([=](
const boost::system::error_code& error)
1981 if(error != boost::asio::error::operation_aborted)
1983 _dbg3(
"Failed to connect to " << adr <<
':' << port <<
", because of timeout (" << conn_timeout <<
")");
1984 new_connection_l->socket().close();
1988 sock_.async_connect(remote_endpoint, [=](
const boost::system::error_code& ec_)
1991 boost::system::error_code ignored_ec;
1992 boost::asio::ip::tcp::socket::endpoint_type lep = new_connection_l->socket().local_endpoint(ignored_ec);
1995 if(!sh_deadline->cancel())
1997 cb(conn_context, boost::asio::error::operation_aborted);
2000 _dbg3(
"[sock " << new_connection_l->socket().native_handle() <<
"] Connected success to " << adr <<
':' << port <<
2001 " from " << lep.address().to_string() <<
':' << lep.port());
2010 new_connection_l->get_context(conn_context);
2011 cb(conn_context, ec_);
2015 _dbg3(
"[sock " << new_connection_l->socket().native_handle() <<
"] Failed to start connection to " << adr <<
':' << port);
2016 cb(conn_context, boost::asio::error::fault);
2021 _dbg3(
"[sock " << new_connection_l->socket().native_handle() <<
"] Failed to connect to " << adr <<
':' << port <<
2022 " from " << lep.address().to_string() <<
':' << lep.port() <<
": " << ec_.message() <<
':' << ec_.value());
2023 cb(conn_context, ec_);
2027 CATCH_ENTRY_L0(
"boosted_tcp_server<t_protocol_handler>::connect_async",
false);
#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT
Definition abstract_tcp_server2.h:67
#define NEW_CONNECTION_TIMEOUT_LOCAL
Definition abstract_tcp_server2.inl:59
#define NEW_CONNECTION_TIMEOUT_REMOTE
Definition abstract_tcp_server2.inl:60
#define TIMEOUT_EXTRA_MS_PER_BYTE
Definition abstract_tcp_server2.inl:63
#define AGGRESSIVE_TIMEOUT_THRESHOLD
Definition abstract_tcp_server2.inl:58
#define DEFAULT_TIMEOUT_MS_LOCAL
Definition abstract_tcp_server2.inl:61
#define DEFAULT_TIMEOUT_MS_REMOTE
Definition abstract_tcp_server2.inl:62
static void close()
Definition blockchain_blackball.cpp:279
Definition byte_slice.h:69
boost::asio::ip::tcp::acceptor acceptor_ipv6
Definition abstract_tcp_server2.h:522
boost::shared_ptr< connection< t_protocol_handler > > connection_ptr
Definition abstract_tcp_server2.h:356
uint32_t m_port
Definition abstract_tcp_server2.h:526
size_t m_threads_count
Definition abstract_tcp_server2.h:533
void set_connection_limit(i_connection_limit *plimit)
Definition abstract_tcp_server2.inl:1441
void handle_accept_ipv6(const boost::system::error_code &e)
Definition abstract_tcp_server2.inl:1567
bool m_require_ipv4
Definition abstract_tcp_server2.h:531
std::map< std::string, t_connection_type > server_type_map
Definition abstract_tcp_server2.h:365
std::vector< boost::shared_ptr< boost::thread > > m_threads
Definition abstract_tcp_server2.h:534
boost::asio::ip::tcp::acceptor acceptor_
Acceptor used to listen for incoming connections.
Definition abstract_tcp_server2.h:521
try_connect_result_t
Definition abstract_tcp_server2.h:349
@ CONNECT_FAILURE
Definition abstract_tcp_server2.h:351
@ CONNECT_NO_SSL
Definition abstract_tcp_server2.h:352
@ CONNECT_SUCCESS
Definition abstract_tcp_server2.h:350
std::atomic< bool > m_stop_signal_sent
Definition abstract_tcp_server2.h:525
~boosted_tcp_server()
Definition abstract_tcp_server2.inl:1250
bool connect(const std::string &adr, const std::string &port, uint32_t conn_timeot, t_connection_context &cn, const std::string &bind_ip="0.0.0.0", epee::net_utils::ssl_support_t ssl_support=epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
Definition abstract_tcp_server2.inl:1767
bool timed_wait_server_stop(uint64_t wait_mseconds)
wait for service workers stop
Definition abstract_tcp_server2.inl:1526
connection_ptr new_connection_
The next connection to be accepted.
Definition abstract_tcp_server2.h:542
boost::asio::io_context & get_io_context()
Definition abstract_tcp_server2.h:437
t_protocol_handler::connection_context t_connection_context
Definition abstract_tcp_server2.h:357
boosted_tcp_server(t_connection_type connection_type)
Definition abstract_tcp_server2.inl:1213
try_connect_result_t try_connect(connection_ptr new_connection_l, const std::string &adr, const std::string &port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support)
Definition abstract_tcp_server2.inl:1669
boost::mutex connections_mutex
Definition abstract_tcp_server2.h:546
void handle_accept_ipv4(const boost::system::error_code &e)
Handle completion of an asynchronous accept operation.
Definition abstract_tcp_server2.inl:1561
connection_ptr new_connection_ipv6
Definition abstract_tcp_server2.h:543
bool worker_thread()
Run the server's io_context loop.
Definition abstract_tcp_server2.inl:1394
void create_server_type_map()
Definition abstract_tcp_server2.inl:1257
bool add_connection(t_connection_context &out, boost::asio::ip::tcp::socket &&sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support=epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
Definition abstract_tcp_server2.inl:1649
std::string m_address_ipv6
Definition abstract_tcp_server2.h:529
void send_stop_signal()
Stop the server.
Definition abstract_tcp_server2.inl:1543
critical_section m_threads_lock
Definition abstract_tcp_server2.h:536
void set_connection_filter(i_connection_filter *pfilter)
Definition abstract_tcp_server2.inl:1434
t_connection_type m_connection_type
Definition abstract_tcp_server2.h:539
std::string m_address
Definition abstract_tcp_server2.h:528
std::string m_thread_name_prefix
Definition abstract_tcp_server2.h:532
epee::net_utils::network_address default_remote
Definition abstract_tcp_server2.h:523
bool run_server(size_t threads_count, bool wait=true, const boost::thread::attributes &attrs=boost::thread::attributes())
Run the server's io_context loop.
Definition abstract_tcp_server2.inl:1455
void handle_accept(const boost::system::error_code &e, bool ipv6=false)
Definition abstract_tcp_server2.inl:1573
bool connect_async(const std::string &adr, const std::string &port, uint32_t conn_timeot, const t_callback &cb, const std::string &bind_ip="0.0.0.0", epee::net_utils::ssl_support_t ssl_support=epee::net_utils::ssl_support_t::e_ssl_support_autodetect, t_connection_context &&initial=t_connection_context{})
void set_threads_prefix(const std::string &prefix_name)
Definition abstract_tcp_server2.inl:1424
bool init_server(uint32_t port, const std::string &address="0.0.0.0", uint32_t port_ipv6=0, const std::string &address_ipv6="::", bool use_ipv6=false, bool require_ipv4=true, ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect)
Definition abstract_tcp_server2.inl:1265
boost::asio::io_context & io_context_
Definition abstract_tcp_server2.h:518
std::unique_ptr< worker > m_io_context_local_instance
Definition abstract_tcp_server2.h:517
uint32_t m_port_ipv6
Definition abstract_tcp_server2.h:527
void set_response_soft_limit(std::size_t limit)
Definition abstract_tcp_server2.inl:1448
bool m_use_ipv6
Definition abstract_tcp_server2.h:530
boost::thread::id m_main_thread_id
Definition abstract_tcp_server2.h:535
std::set< connection_ptr > connections_
Definition abstract_tcp_server2.h:547
bool is_thread_worker()
Definition abstract_tcp_server2.inl:1510
const std::shared_ptr< typename connection< epee::net_utils::http::http_custom_handler< epee::net_utils::connection_context_base > >::shared_state > m_state
Definition abstract_tcp_server2.h:505
std::atomic< uint32_t > m_thread_index
Definition abstract_tcp_server2.h:537
std::atomic< long > sock_count
Definition connection_basic.hpp:67
boost::asio::ssl::stream< boost::asio::ip::tcp::socket > socket_
Socket for the connection.
Definition connection_basic.hpp:117
static int get_tos_flag()
Definition connection_basic.cpp:226
boost::asio::io_context::strand strand_
Strand to ensure the connection's handlers are not called concurrently.
Definition connection_basic.hpp:115
void logger_handle_net_read(size_t size)
Definition connection_basic.cpp:270
boost::asio::ip::tcp::socket & socket()
Definition connection_basic.hpp:130
ssl_support_t m_ssl_support
Definition connection_basic.hpp:118
connection_basic_shared_state & get_state() noexcept
Definition connection_basic.hpp:128
volatile bool m_is_multithreaded
Definition connection_basic.hpp:113
connection_basic(boost::asio::io_context &context, boost::asio::ip::tcp::socket &&sock, std::shared_ptr< connection_basic_shared_state > state, ssl_support_t ssl_support)
Definition connection_basic.cpp:124
Represents a single connection from a client.
Definition abstract_tcp_server2.h:100
void setRpcStation()
Definition abstract_tcp_server2.inl:1206
virtual bool call_run_once_service_io()
Definition abstract_tcp_server2.inl:1141
boost::asio::ip::tcp::socket socket_t
Definition abstract_tcp_server2.h:114
io_context_t & m_io_context
Definition abstract_tcp_server2.h:262
void terminate()
Definition abstract_tcp_server2.inl:742
virtual bool send_done()
Definition abstract_tcp_server2.inl:1125
void start_timer(duration_t duration, bool add={})
Definition abstract_tcp_server2.inl:144
t_protocol_handler::connection_context t_connection_context
Definition abstract_tcp_server2.h:102
void cancel_handler()
Definition abstract_tcp_server2.inl:667
boost::asio::io_context io_context_t
Definition abstract_tcp_server2.h:112
void async_wait_timer()
Definition abstract_tcp_server2.inl:168
bool m_local
Definition abstract_tcp_server2.h:268
void start_write()
Definition abstract_tcp_server2.inl:469
t_protocol_handler m_handler
Definition abstract_tcp_server2.h:271
void start_read()
Definition abstract_tcp_server2.inl:305
void interrupt()
Definition abstract_tcp_server2.inl:684
connection(io_context_t &io_context, std::shared_ptr< shared_state > state, t_connection_type connection_type, epee::net_utils::ssl_support_t ssl_support, t_connection_context &&initial=t_connection_context{})
Construct a connection with the given io_context.
Definition abstract_tcp_server2.inl:1012
void on_terminating()
Definition abstract_tcp_server2.inl:757
virtual bool do_send(byte_slice message)
(see do_send from i_service_endpoint)
Definition abstract_tcp_server2.inl:1119
bool send(epee::byte_slice message)
Definition abstract_tcp_server2.inl:811
virtual bool release()
Definition abstract_tcp_server2.inl:1196
void finish_read(size_t bytes_transferred)
Definition abstract_tcp_server2.inl:413
virtual bool request_callback()
Definition abstract_tcp_server2.inl:1155
bool speed_limit_is_enabled() const
tells us should we be sleeping here (e.g. do not sleep on RPC connections)
Definition abstract_tcp_server2.inl:1107
boost::shared_ptr< connection_t > connection_ptr
Definition abstract_tcp_server2.h:105
void on_interrupted()
Definition abstract_tcp_server2.inl:697
std::string m_host
Definition abstract_tcp_server2.h:269
void start_handshake()
Definition abstract_tcp_server2.inl:209
virtual io_context_t & get_io_context()
Definition abstract_tcp_server2.inl:1175
timers_t m_timers
Definition abstract_tcp_server2.h:266
bool start_internal(bool is_income, bool is_multithreaded, boost::optional< network_address > real_remote)
Definition abstract_tcp_server2.inl:909
@ RUNNING
Definition abstract_tcp_server2.h:154
@ INTERRUPTED
Definition abstract_tcp_server2.h:155
@ TERMINATING
Definition abstract_tcp_server2.h:156
@ WASTED
Definition abstract_tcp_server2.h:157
@ TERMINATED
Definition abstract_tcp_server2.h:153
void terminate_async()
Definition abstract_tcp_server2.inl:800
duration_t get_timeout_from_bytes_read(size_t bytes) const
Definition abstract_tcp_server2.inl:115
virtual ~connection() noexcept(false)
Definition abstract_tcp_server2.inl:1050
void cancel_timer()
Definition abstract_tcp_server2.inl:199
void state_status_check()
Definition abstract_tcp_server2.inl:125
state_t m_state
Definition abstract_tcp_server2.h:270
strand_t m_strand
Definition abstract_tcp_server2.h:265
void start_shutdown()
Definition abstract_tcp_server2.inl:599
epee::net_utils::ssl_support_t ssl_support_t
Definition abstract_tcp_server2.h:106
void cancel_socket()
Definition abstract_tcp_server2.inl:641
t_connection_context m_conn_context
Definition abstract_tcp_server2.h:264
void save_dbg_log()
Definition abstract_tcp_server2.inl:1082
virtual bool add_ref()
Definition abstract_tcp_server2.inl:1181
unsigned int host_count(int delta=0)
Definition abstract_tcp_server2.inl:81
bool start(bool is_income, bool is_multithreaded)
Start the first asynchronous operation for the connection.
Definition abstract_tcp_server2.inl:1063
timer_t::duration duration_t
Definition abstract_tcp_server2.h:108
bool cancel()
Definition abstract_tcp_server2.inl:1113
t_connection_type m_connection_type
Definition abstract_tcp_server2.h:263
connection_ptr self
Definition abstract_tcp_server2.h:267
virtual bool close()
Definition abstract_tcp_server2.inl:1131
duration_t get_default_timeout()
Definition abstract_tcp_server2.inl:98
boost::system::error_code ec_t
Definition abstract_tcp_server2.h:109
Definition net_utils_base.h:69
Definition net_utils_base.h:172
Definition net_utils_base.h:225
static boost::mutex m_lock_get_global_throttle_in
Definition network_throttle.hpp:107
static i_network_throttle & get_global_throttle_in()
singleton ; for friend class ; caller MUST use proper locks! like m_lock_get_global_throttle_in
Definition network_throttle.cpp:76
static i_network_throttle & get_global_throttle_out()
ditto ; use lock ... use m_lock_get_global_throttle_out obviously
Definition network_throttle.cpp:89
static boost::mutex m_lock_get_global_throttle_out
Definition network_throttle.hpp:109
const uint8_t seed[32]
Definition code-generator.cpp:37
bool success
Definition cold-transaction.cpp:57
std::unique_ptr< test_connection > conn(new test_connection(io_service, m_handler_config))
const char * res
Definition hmac_keccak.cpp:42
static int dev
Definition ipfrdr.c:126
uint32_t address
Definition getifaddr.c:269
#define AUTO_VAL_INIT(v)
Definition misc_language.h:36
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
Definition misc_language.h:80
bool sleep_no_w(long ms)
Definition misc_language.cpp:35
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
Definition misc_language.h:97
T & check_and_get(std::shared_ptr< T > &ptr)
Definition abstract_tcp_server2.inl:71
@ ipv6
Definition enums.h:44
@ invalid
Definition enums.h:42
std::string to_string(t_connection_type type)
Definition connection_basic.cpp:70
bool is_ssl(const unsigned char *data, size_t len)
Definition net_ssl.cpp:424
constexpr size_t get_ssl_magic_size()
Definition net_ssl.h:150
t_connection_type
Definition connection_basic.hpp:93
@ e_connection_type_NET
Definition connection_basic.hpp:94
@ e_connection_type_RPC
Definition connection_basic.hpp:95
@ e_connection_type_P2P
Definition connection_basic.hpp:96
ssl_support_t
Definition net_ssl.h:49
@ e_ssl_support_disabled
Definition net_ssl.h:50
@ e_ssl_support_autodetect
Definition net_ssl.h:52
@ e_ssl_support_enabled
Definition net_ssl.h:51
TODO: (mj-xmr) This will be reduced in an another PR.
Definition byte_slice.h:40
int time
Definition gen_wide_data.py:40
if(!cryptonote::get_account_address_from_str_or_url(info, cryptonote::TESTNET, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN"))
Definition signature.cpp:53
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
The io_context used to perform asynchronous operations.
Definition abstract_tcp_server2.h:509
Definition abstract_tcp_server2.h:274
std::size_t response_soft_limit
Definition abstract_tcp_server2.h:286
Definition abstract_tcp_server2.h:76
Definition abstract_tcp_server2.h:83
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:153
#define CRITICAL_REGION_END()
Definition syncobj.h:158
#define CRITICAL_REGION_BEGIN(x)
Definition syncobj.h:154