Monero
Loading...
Searching...
No Matches
abstract_tcp_server2.inl
Go to the documentation of this file.
1
7// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
8// All rights reserved.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are met:
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above copyright
15// notice, this list of conditions and the following disclaimer in the
16// documentation and/or other materials provided with the distribution.
17// * Neither the name of the Andrey N. Sabelnikov nor the
18// names of its contributors may be used to endorse or promote products
19// derived from this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
25// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31//
32
33
34#include <boost/asio/post.hpp>
35#include <boost/foreach.hpp>
36#include <boost/uuid/random_generator.hpp>
37#include <boost/uuid/uuid_io.hpp>
38#include <boost/chrono.hpp>
39#include <boost/utility/value_init.hpp>
40#include <boost/asio/bind_executor.hpp>
41#include <boost/asio/deadline_timer.hpp>
42#include <boost/date_time/posix_time/posix_time.hpp> // TODO
43#include <boost/thread/condition_variable.hpp> // TODO
44#include <boost/make_shared.hpp>
45#include <boost/thread.hpp>
46#include "warnings.h"
48#include "misc_language.h"
49
50#include <sstream>
51#include <iomanip>
52#include <algorithm>
53#include <functional>
54#include <random>
55
56#undef MONERO_DEFAULT_LOG_CATEGORY
57#define MONERO_DEFAULT_LOG_CATEGORY "net"
58
59#define AGGRESSIVE_TIMEOUT_THRESHOLD 120 // sockets
60#define NEW_CONNECTION_TIMEOUT_LOCAL 1200000 // 2 minutes
61#define NEW_CONNECTION_TIMEOUT_REMOTE 10000 // 10 seconds
62#define DEFAULT_TIMEOUT_MS_LOCAL 1800000 // 30 minutes
63#define DEFAULT_TIMEOUT_MS_REMOTE 300000 // 5 minutes
64#define TIMEOUT_EXTRA_MS_PER_BYTE 0.2
65
66
67namespace epee
68{
69namespace net_utils
70{
71 template<typename T>
72 T& check_and_get(std::shared_ptr<T>& ptr)
73 {
74 CHECK_AND_ASSERT_THROW_MES(bool(ptr), "shared_state cannot be null");
75 return *ptr;
76 }
77
78 /************************************************************************/
79 /* */
80 /************************************************************************/
81 template<typename T>
82 unsigned int connection<T>::host_count(int delta)
83 {
84 static std::mutex hosts_mutex;
85 std::lock_guard<std::mutex> guard(hosts_mutex);
86 static std::map<std::string, unsigned int> hosts;
87 unsigned int &val = hosts[m_host];
88 if (delta > 0)
89 MTRACE("New connection from host " << m_host << ": " << val);
90 else if (delta < 0)
91 MTRACE("Closed connection from host " << m_host << ": " << val);
92 CHECK_AND_ASSERT_THROW_MES(delta >= 0 || val >= (unsigned)-delta, "Count would go negative");
93 CHECK_AND_ASSERT_THROW_MES(delta <= 0 || val <= std::numeric_limits<unsigned int>::max() - (unsigned)delta, "Count would wrap");
94 val += delta;
95 return val;
96 }
97
98 template<typename T>
100 {
101 unsigned count{};
102 try { count = host_count(); } catch (...) {}
103 const unsigned shift = (
105 std::min(std::max(count, 1u) - 1, 8u) :
106 0
107 );
108 return (
109 m_local ?
110 std::chrono::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift) :
111 std::chrono::milliseconds(DEFAULT_TIMEOUT_MS_REMOTE >> shift)
112 );
113 }
114
115 template<typename T>
117 {
118 return std::chrono::duration_cast<connection<T>::duration_t>(
119 std::chrono::duration<double, std::chrono::milliseconds::period>(
121 )
122 );
123 }
124
125 template<typename T>
127 {
128 switch (m_state.status)
129 {
131 interrupt();
132 break;
135 break;
138 break;
139 default:
140 break;
141 }
142 }
143
144 template<typename T>
145 void connection<T>::start_timer(duration_t duration, bool add)
146 {
147 if (m_state.timers.general.wait_expire) {
148 m_state.timers.general.cancel_expire = true;
149 m_state.timers.general.reset_expire = true;
150 m_timers.general.expires_after(
151 std::min(
152 duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
154 )
155 );
156 }
157 else {
158 m_timers.general.expires_after(
159 std::min(
160 duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
162 )
163 );
165 }
166 }
167
168 template<typename T>
170 {
171 if (m_state.timers.general.wait_expire)
172 return;
173 m_state.timers.general.wait_expire = true;
175 auto on_wait = [this, self] {
176 std::lock_guard<std::mutex> guard(m_state.lock);
177 m_state.timers.general.wait_expire = false;
178 if (m_state.timers.general.cancel_expire) {
179 m_state.timers.general.cancel_expire = false;
180 if (m_state.timers.general.reset_expire) {
181 m_state.timers.general.reset_expire = false;
183 }
184 else if (m_state.status == status_t::INTERRUPTED)
186 else if (m_state.status == status_t::TERMINATING)
188 }
189 else if (m_state.status == status_t::RUNNING)
190 interrupt();
191 else if (m_state.status == status_t::INTERRUPTED)
192 terminate();
193 };
194 m_timers.general.async_wait([this, self, on_wait](const ec_t & ec){
195 boost::asio::post(m_strand, on_wait);
196 });
197 }
198
199 template<typename T>
201 {
202 if (!m_state.timers.general.wait_expire)
203 return;
204 m_state.timers.general.cancel_expire = true;
205 m_state.timers.general.reset_expire = false;
206 m_timers.general.cancel();
207 }
208
209 template<typename T>
211 {
212 if (m_state.socket.wait_handshake)
213 return;
214 static_assert(
215 epee::net_utils::get_ssl_magic_size() <= sizeof(m_state.data.read.buffer),
216 ""
217 );
219 if (!m_state.ssl.forced && !m_state.ssl.detected) {
220 m_state.socket.wait_read = true;
221 boost::asio::async_read(
222 connection_basic::socket_.next_layer(),
223 boost::asio::buffer(
224 m_state.data.read.buffer.data(),
225 m_state.data.read.buffer.size()
226 ),
227 boost::asio::transfer_exactly(epee::net_utils::get_ssl_magic_size()),
228 boost::asio::bind_executor(
229 m_strand,
230 [this, self](const ec_t &ec, size_t bytes_transferred){
231 std::lock_guard<std::mutex> guard(m_state.lock);
232 m_state.socket.wait_read = false;
233 if (m_state.socket.cancel_read) {
234 m_state.socket.cancel_read = false;
235 state_status_check();
236 }
237 else if (ec.value()) {
238 terminate();
239 }
240 else if (
242 static_cast<const unsigned char *>(
243 m_state.data.read.buffer.data()
244 ),
245 bytes_transferred
246 )
247 ) {
248 m_state.ssl.enabled = false;
249 handle_read(bytes_transferred);
250 }
251 else {
252 m_state.ssl.detected = true;
253 start_handshake();
254 }
255 }
256 )
257 );
258 return;
259 }
260
261 m_state.socket.wait_handshake = true;
262 auto on_handshake = [this, self](const ec_t &ec, size_t bytes_transferred){
263 std::lock_guard<std::mutex> guard(m_state.lock);
264 m_state.socket.wait_handshake = false;
265 if (m_state.socket.cancel_handshake) {
266 m_state.socket.cancel_handshake = false;
267 state_status_check();
268 }
269 else if (ec.value()) {
270 ec_t ec;
271 connection_basic::socket_.next_layer().shutdown(
272 socket_t::shutdown_both,
273 ec
274 );
275 connection_basic::socket_.next_layer().close(ec);
276 m_state.socket.connected = false;
277 interrupt();
278 }
279 else {
280 m_state.ssl.handshaked = true;
281 start_write();
282 start_read();
283 }
284 };
285 const auto handshake = handshake_t::server;
286 static_cast<shared_state&>(
288 ).ssl_options().configure(connection_basic::socket_, handshake);
289 boost::asio::post(
290 m_strand,
291 [this, self, on_handshake]{
292 connection_basic::socket_.async_handshake(
293 handshake,
294 boost::asio::buffer(
295 m_state.data.read.buffer.data(),
296 m_state.ssl.forced ? 0 :
298 ),
299 boost::asio::bind_executor(m_strand, on_handshake)
300 );
301 }
302 );
303 }
304
305 template<typename T>
307 {
308 if (m_state.timers.throttle.in.wait_expire || m_state.socket.wait_read ||
309 m_state.socket.handle_read || m_state.socket.shutdown_read
310 ) {
311 return;
312 }
315 auto calc_duration = []{
318 );
319 return std::chrono::duration_cast<connection<T>::duration_t>(
320 std::chrono::duration<double, std::chrono::seconds::period>(
321 std::min(
323 ).get_sleep_time_after_tick(1),
324 1.0
325 )
326 )
327 );
328 };
329 const auto duration = calc_duration();
330 if (duration > duration_t{}) {
331 m_timers.throttle.in.expires_after(duration);
332 m_state.timers.throttle.in.wait_expire = true;
333 auto on_wait = [this, self](const ec_t &ec){
334 std::lock_guard<std::mutex> guard(m_state.lock);
335 m_state.timers.throttle.in.wait_expire = false;
336 if (m_state.timers.throttle.in.cancel_expire) {
337 m_state.timers.throttle.in.cancel_expire = false;
339 }
340 else if (ec.value())
341 interrupt();
342 };
343 m_timers.throttle.in.async_wait([this, self, on_wait](const ec_t &ec){
344 std::lock_guard<std::mutex> guard(m_state.lock);
345 const bool error_status = m_state.timers.throttle.in.cancel_expire || ec.value();
346 if (error_status)
347 boost::asio::post(m_strand, std::bind(on_wait, ec));
348 else {
349 m_state.timers.throttle.in.wait_expire = false;
350 start_read();
351 }
352 });
353 return;
354 }
355 }
356 m_state.socket.wait_read = true;
357 auto on_read = [this, self](const ec_t &ec, size_t bytes_transferred){
358 std::lock_guard<std::mutex> guard(m_state.lock);
359 m_state.socket.wait_read = false;
360 if (m_state.socket.cancel_read) {
361 m_state.socket.cancel_read = false;
364 else if (ec.value())
365 terminate();
366 else {
367 {
368 m_state.stat.in.throttle.handle_trafic_exact(bytes_transferred);
369 const auto speed = m_state.stat.in.throttle.get_current_speed();
370 m_conn_context.m_current_speed_down = speed;
371 m_conn_context.m_max_speed_down = std::max(
372 m_conn_context.m_max_speed_down,
373 speed
374 );
375 if (speed_limit_is_enabled()) {
377 network_throttle_manager_t::m_lock_get_global_throttle_in
378 );
379 network_throttle_manager_t::get_global_throttle_in(
380 ).handle_trafic_exact(bytes_transferred);
383 m_conn_context.m_last_recv = time(NULL);
384 m_conn_context.m_recv_cnt += bytes_transferred;
385 start_timer(get_timeout_from_bytes_read(bytes_transferred), true);
386 }
387 handle_read(bytes_transferred);
388 }
389 };
390 if (!m_state.ssl.enabled)
391 connection_basic::socket_.next_layer().async_read_some(
392 boost::asio::buffer(
393 m_state.data.read.buffer.data(),
394 m_state.data.read.buffer.size()
395 ),
396 boost::asio::bind_executor(m_strand, on_read)
397 );
398 else
399 boost::asio::post(
400 m_strand,
401 [this, self, on_read]{
402 connection_basic::socket_.async_read_some(
403 boost::asio::buffer(
404 m_state.data.read.buffer.data(),
405 m_state.data.read.buffer.size()
406 ),
407 boost::asio::bind_executor(m_strand, on_read)
408 );
410 );
412
413 template<typename T>
414 void connection<T>::handle_read(size_t bytes_transferred)
415 {
416 // Post handle_recv to a separate `strand_`, distinct from `m_strand`
417 // which is listening for reads/writes. This avoids a circular dep.
418 // handle_recv can queue many writes, and `m_strand` will process those
419 // writes until the connection terminates without deadlocking waiting
420 // for handle_recv.
421 m_state.socket.handle_read = true;
423 boost::asio::post(
425 [this, self, bytes_transferred]{
426 bool success = false;
427 TRY_ENTRY();
428 success = m_handler.handle_recv(
429 reinterpret_cast<char *>(m_state.data.read.buffer.data()),
430 bytes_transferred
431 );
432 CATCH_ENTRY_SWALLOW_EX("m_handler.handle_recv");
433 std::lock_guard<std::mutex> guard(m_state.lock);
434 const bool error_status = m_state.status == status_t::INTERRUPTED
435 || m_state.status == status_t::TERMINATING
436 || !success;
437 if (!error_status) {
438 m_state.socket.handle_read = false;
439 start_read();
440 return;
441 }
442 boost::asio::post(
443 m_strand,
444 [this, self, success]{
445 // expect error_status == true
446 std::lock_guard<std::mutex> guard(m_state.lock);
447 m_state.socket.handle_read = false;
448 if (m_state.status == status_t::INTERRUPTED)
449 on_interrupted();
450 else if (m_state.status == status_t::TERMINATING)
451 on_terminating();
452 else if (!success) {
453 ec_t ec;
454 if (m_state.socket.wait_write) {
455 // Allow the already queued writes time to finish, but no more new reads
456 connection_basic::socket_.next_layer().shutdown(
457 socket_t::shutdown_receive,
458 ec
459 );
460 m_state.socket.shutdown_read = true;
461 }
462 if (!m_state.socket.wait_write || ec.value()) {
463 interrupt();
464 }
465 }
466 }
467 );
468 }
469 );
470 }
471
472 template<typename T>
474 {
475 if (m_state.timers.throttle.out.wait_expire || m_state.socket.wait_write ||
476 m_state.data.write.queue.empty() ||
477 (m_state.ssl.enabled && !m_state.ssl.handshaked)
478 ) {
479 return;
480 }
483 auto calc_duration = [this]{
486 );
487 return std::chrono::duration_cast<connection<T>::duration_t>(
488 std::chrono::duration<double, std::chrono::seconds::period>(
489 std::min(
491 ).get_sleep_time_after_tick(
492 m_state.data.write.queue.back().size()
493 ),
494 1.0
495 )
496 )
497 );
498 };
499 const auto duration = calc_duration();
500 if (duration > duration_t{}) {
501 m_timers.throttle.out.expires_after(duration);
502 m_state.timers.throttle.out.wait_expire = true;
503 auto on_wait = [this, self](const ec_t &ec){
504 std::lock_guard<std::mutex> guard(m_state.lock);
505 m_state.timers.throttle.out.wait_expire = false;
506 if (m_state.timers.throttle.out.cancel_expire) {
507 m_state.timers.throttle.out.cancel_expire = false;
509 }
510 else if (ec.value())
511 interrupt();
512 };
513 m_timers.throttle.out.async_wait([this, self, on_wait](const ec_t &ec){
514 std::lock_guard<std::mutex> guard(m_state.lock);
515 const bool error_status = m_state.timers.throttle.out.cancel_expire || ec.value();
516 if (error_status)
517 boost::asio::post(m_strand, std::bind(on_wait, ec));
518 else {
519 m_state.timers.throttle.out.wait_expire = false;
520 start_write();
521 }
522 });
523 return;
524 }
525 }
526
527 m_state.socket.wait_write = true;
528 auto on_write = [this, self](const ec_t &ec, size_t bytes_transferred){
529 std::lock_guard<std::mutex> guard(m_state.lock);
530 m_state.socket.wait_write = false;
531 if (m_state.socket.cancel_write) {
532 m_state.socket.cancel_write = false;
533 m_state.data.write.queue.clear();
534 m_state.data.write.total_bytes = 0;
535 state_status_check();
536 }
537 else if (ec.value()) {
538 m_state.data.write.queue.clear();
539 m_state.data.write.total_bytes = 0;
540 interrupt();
541 }
542 else {
543 {
544 m_state.stat.out.throttle.handle_trafic_exact(bytes_transferred);
545 const auto speed = m_state.stat.out.throttle.get_current_speed();
546 m_conn_context.m_current_speed_up = speed;
547 m_conn_context.m_max_speed_down = std::max(
548 m_conn_context.m_max_speed_down,
549 speed
550 );
551 if (speed_limit_is_enabled()) {
553 network_throttle_manager_t::m_lock_get_global_throttle_out
554 );
555 network_throttle_manager_t::get_global_throttle_out(
556 ).handle_trafic_exact(bytes_transferred);
557 }
558 connection_basic::logger_handle_net_write(bytes_transferred);
559 m_conn_context.m_last_send = time(NULL);
560 m_conn_context.m_send_cnt += bytes_transferred;
561
562 start_timer(get_default_timeout(), true);
563 }
564 const std::size_t byte_count = m_state.data.write.queue.back().size();
565 assert(bytes_transferred == byte_count);
566 m_state.data.write.queue.pop_back();
567 m_state.data.write.total_bytes -=
568 std::min(m_state.data.write.total_bytes, byte_count);
569 m_state.condition.notify_all();
570 if (m_state.data.write.queue.empty() && m_state.socket.shutdown_read) {
571 // All writes have been sent and reads shutdown already, connection can be closed
572 interrupt();
573 } else {
574 start_write();
575 }
576 }
577 };
578 if (!m_state.ssl.enabled)
579 boost::asio::async_write(
580 connection_basic::socket_.next_layer(),
581 boost::asio::buffer(
582 m_state.data.write.queue.back().data(),
583 m_state.data.write.queue.back().size()
584 ),
585 boost::asio::bind_executor(m_strand, on_write)
586 );
587 else
588 boost::asio::post(
589 m_strand,
590 [this, self, on_write]{
591 boost::asio::async_write(
592 connection_basic::socket_,
593 boost::asio::buffer(
594 m_state.data.write.queue.back().data(),
595 m_state.data.write.queue.back().size()
596 ),
597 boost::asio::bind_executor(m_strand, on_write)
598 );
599 }
600 );
601 }
602
603 template<typename T>
605 {
606 if (m_state.socket.wait_shutdown)
607 return;
609 m_state.socket.wait_shutdown = true;
610 auto on_shutdown = [this, self](const ec_t &ec){
611 std::lock_guard<std::mutex> guard(m_state.lock);
612 m_state.socket.wait_shutdown = false;
613 if (m_state.socket.cancel_shutdown) {
614 m_state.socket.cancel_shutdown = false;
615 switch (m_state.status)
616 {
618 interrupt();
619 break;
621 terminate();
622 break;
625 break;
626 default:
627 break;
628 }
629 }
630 else {
631 terminate();
632 }
633 };
634 boost::asio::post(
635 m_strand,
636 [this, self, on_shutdown]{
637 connection_basic::socket_.async_shutdown(
638 boost::asio::bind_executor(m_strand, on_shutdown)
639 );
640 }
641 );
643 }
644
645 template<typename T>
647 {
648 bool wait_socket = false;
649 if (m_state.socket.wait_handshake)
650 wait_socket = m_state.socket.cancel_handshake = true;
651 if (m_state.timers.throttle.in.wait_expire) {
652 m_state.timers.throttle.in.cancel_expire = true;
653 m_timers.throttle.in.cancel();
654 }
655 if (m_state.socket.wait_read)
656 wait_socket = m_state.socket.cancel_read = true;
657 if (m_state.timers.throttle.out.wait_expire) {
658 m_state.timers.throttle.out.cancel_expire = true;
659 m_timers.throttle.out.cancel();
660 }
661 if (m_state.socket.wait_write)
662 wait_socket = m_state.socket.cancel_write = true;
663 if (m_state.socket.wait_shutdown)
664 wait_socket = m_state.socket.cancel_shutdown = true;
665 if (wait_socket) {
666 ec_t ec;
667 connection_basic::socket_.next_layer().cancel(ec);
668 }
669 }
670
671 template<typename T>
673 {
674 if (m_state.protocol.released || m_state.protocol.wait_release)
675 return;
676 m_state.protocol.wait_release = true;
677 m_state.lock.unlock();
678 m_handler.release_protocol();
679 m_state.lock.lock();
680 m_state.protocol.wait_release = false;
681 m_state.protocol.released = true;
682 if (m_state.status == status_t::INTERRUPTED)
684 else if (m_state.status == status_t::TERMINATING)
686 }
687
688 template<typename T>
690 {
691 if (m_state.status != status_t::RUNNING)
692 return;
694 cancel_timer();
697 m_state.condition.notify_all();
699 }
700
701 template<typename T>
703 {
704 assert(m_state.status == status_t::INTERRUPTED);
705 if (m_state.timers.general.wait_expire)
706 return;
707 if (m_state.socket.wait_handshake)
708 return;
709 if (m_state.timers.throttle.in.wait_expire)
710 return;
711 if (m_state.socket.wait_read)
712 return;
713 if (m_state.socket.handle_read)
714 return;
715 if (m_state.timers.throttle.out.wait_expire)
716 return;
717 // \NOTE See on_terminating() comments
718 //if (m_state.socket.wait_write)
719 // return;
720 if (m_state.socket.wait_shutdown)
721 return;
722 if (m_state.protocol.wait_init)
723 return;
724 if (m_state.protocol.wait_callback)
725 return;
726 if (m_state.protocol.wait_release)
727 return;
728 if (m_state.socket.connected) {
729 if (!m_state.ssl.enabled) {
730 ec_t ec;
731 connection_basic::socket_.next_layer().shutdown(
732 socket_t::shutdown_both,
733 ec
734 );
735 connection_basic::socket_.next_layer().close(ec);
736 m_state.socket.connected = false;
737 m_state.status = status_t::WASTED;
738 }
739 else
741 }
742 else
743 m_state.status = status_t::WASTED;
744 m_state.condition.notify_all();
745 }
746
747 template<typename T>
749 {
750 if (m_state.status != status_t::RUNNING &&
752 )
753 return;
755 cancel_timer();
758 m_state.condition.notify_all();
760 }
761
762 template<typename T>
764 {
765 assert(m_state.status == status_t::TERMINATING);
766 if (m_state.timers.general.wait_expire)
767 return;
768 if (m_state.socket.wait_handshake)
769 return;
770 if (m_state.timers.throttle.in.wait_expire)
771 return;
772 if (m_state.socket.wait_read)
773 return;
774 if (m_state.socket.handle_read)
775 return;
776 if (m_state.timers.throttle.out.wait_expire)
777 return;
778 // Writes cannot be canceled due to `async_write` being a "composed"
779 // handler. ASIO has new cancellation routines, not available in 1.66, to
780 // handle this situation. The problem is that if cancel is called after an
781 // intermediate handler is queued, the op will not check the cancel flag in
782 // our code, and will instead queue up another write.
783 //if (m_state.socket.wait_write)
784 // return;
785 if (m_state.socket.wait_shutdown)
786 return;
787 if (m_state.protocol.wait_init)
788 return;
789 if (m_state.protocol.wait_callback)
790 return;
791 if (m_state.protocol.wait_release)
792 return;
793 if (m_state.socket.connected) {
794 ec_t ec;
795 connection_basic::socket_.next_layer().shutdown(
796 socket_t::shutdown_both,
797 ec
798 );
799 connection_basic::socket_.next_layer().close(ec);
800 m_state.socket.connected = false;
801 }
802 m_state.status = status_t::WASTED;
803 m_state.condition.notify_all();
804 }
805
806 template<typename T>
808 {
809 // synchronize with intermediate writes on `m_strand`
811 boost::asio::post(m_strand, [this, self] {
812 std::lock_guard<std::mutex> guard(m_state.lock);
813 terminate();
814 });
815 }
816
817 template<typename T>
819 {
820 std::lock_guard<std::mutex> guard(m_state.lock);
821 if (m_state.status != status_t::RUNNING || m_state.socket.wait_handshake)
822 return false;
823 if (std::numeric_limits<std::size_t>::max() - m_state.data.write.total_bytes < message.size())
824 return false;
825
826 // Wait for the write queue to fall below the max. If it doesn't after a
827 // randomized delay, drop the connection. P2P senders fail fast instead of
828 // parking an io_context worker thread here.
829 auto wait_consume = [this] {
830 auto random_delay = []{
831 using engine = std::mt19937;
832 std::random_device dev;
833 std::seed_seq::result_type rand[
834 engine::state_size // Use complete bit space
835 ]{};
836 std::generate_n(rand, engine::state_size, std::ref(dev));
837 std::seed_seq seed(rand, rand + engine::state_size);
838 engine rng(seed);
839 return std::chrono::milliseconds(
840 std::uniform_int_distribution<>(5000, 6000)(rng)
841 );
842 };
843
844 // The bytes check intentionally does not include incoming message size.
845 // This allows for a soft overflow; a single http response will never fail
846 // this check, but multiple responses could. Clients can avoid this case
847 // by reading the entire response before making another request. P2P
848 // should never hit the MAX_BYTES check (when using default values).
849 if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
850 m_state.data.write.total_bytes <= static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit)
851 return true;
852
854 MWARNING("Connection " << m_conn_context.m_connection_id << " tripped write limit, terminating");
856 return false;
857 }
858 m_state.data.write.wait_consume = true;
859 bool success = m_state.condition.wait_for(
860 m_state.lock,
861 random_delay(),
862 [this]{
863 return (
864 m_state.status != status_t::RUNNING ||
865 (
866 m_state.data.write.queue.size() <=
868 m_state.data.write.total_bytes <=
870 )
871 );
872 }
873 );
874 m_state.data.write.wait_consume = false;
875 if (!success) {
877 return false;
878 }
879 else
880 return m_state.status == status_t::RUNNING;
881 };
882 auto wait_sender = [this] {
883 m_state.condition.wait(
884 m_state.lock,
885 [this] {
886 return (
887 m_state.status != status_t::RUNNING ||
888 !m_state.data.write.wait_consume
889 );
890 }
891 );
892 return m_state.status == status_t::RUNNING;
893 };
894 if (!wait_sender())
895 return false;
896 /* CHUNK_SIZE indirectly caps outgoing to 128 * 1024 * 1000
897 (ABSTRACT_SERVER_SEND_QUE_MAX_COUNT). The "soft" limit total is currently
898 100 MiB (ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT). These values will
899 need to be re-visited alongside block limit increases. */
900 constexpr size_t CHUNK_SIZE = 128 * 1024;
902 message.size() <= 2 * CHUNK_SIZE
903 ) {
904 if (!wait_consume())
905 return false;
906 const std::size_t byte_count = message.size();
907 m_state.data.write.queue.emplace_front(std::move(message));
908 m_state.data.write.total_bytes += byte_count;
909 start_write();
910 }
911 else {
912 std::size_t soft_limit = 0;
913 const epee::misc_utils::auto_scope_leave_caller scope_exit_handler =
915 m_state.data.write.total_bytes += soft_limit;
916 });
917
918 while (!message.empty()) {
919 if (!wait_consume())
920 return false;
921 m_state.data.write.queue.emplace_front(
922 message.take_slice(CHUNK_SIZE)
923 );
924 soft_limit += m_state.data.write.queue.front().size();
925 start_write();
926 }
927 }
928 m_state.condition.notify_all();
929 return true;
930 }
931
932 template<typename T>
934 bool is_income,
935 bool is_multithreaded,
936 boost::optional<network_address> real_remote
937 )
938 {
939 std::unique_lock<std::mutex> guard(m_state.lock);
940 if (m_state.status != status_t::TERMINATED)
941 return false;
942 if (!real_remote) {
943 ec_t ec;
944 auto endpoint = connection_basic::socket_.next_layer().remote_endpoint(
945 ec
946 );
947 if (ec.value())
948 return false;
949 real_remote = (
950 endpoint.address().is_v6() ?
952 ipv6_network_address{endpoint.address().to_v6(), endpoint.port()}
953 } :
956 uint32_t{
957 boost::asio::detail::socket_ops::host_to_network_long(
958 endpoint.address().to_v4().to_uint()
959 )
960 },
961 endpoint.port()
962 }
963 }
964 );
965 }
966 auto *filter = static_cast<shared_state&>(
968 ).pfilter;
969 if (filter && !filter->is_remote_host_allowed(*real_remote))
970 return false;
971
972 auto *limit = static_cast<shared_state&>(
974 ).plimit;
975 if (is_income && limit && limit->is_host_limit(*real_remote))
976 return false;
977
978 ec_t ec;
979 #if !defined(_WIN32) || !defined(__i686)
980 if (real_remote->get_type_id() == ipv4_network_address::get_type_id()) {
981 connection_basic::socket_.next_layer().set_option(
982 boost::asio::detail::socket_option::integer<IPPROTO_IP, IP_TOS>{
984 },
985 ec
986 );
987 if (ec.value())
988 return false;
989 }
990 #endif
991 connection_basic::socket_.next_layer().set_option(
992 boost::asio::ip::tcp::no_delay{false},
993 ec
994 );
995 if (ec.value())
996 return false;
997 connection_basic::m_is_multithreaded = is_multithreaded;
998 m_conn_context.set_details(
999 boost::uuids::random_generator()(),
1000 *real_remote,
1001 is_income,
1003 );
1004 m_host = real_remote->host_str();
1005 try { host_count(1); } catch(...) { /* ignore */ }
1006 m_local = real_remote->is_loopback() || real_remote->is_local();
1007 m_state.ssl.enabled = (
1009 );
1010 m_state.ssl.forced = (
1012 );
1013 m_state.socket.connected = true;
1014 m_state.status = status_t::RUNNING;
1016 std::chrono::milliseconds(
1018 )
1019 );
1020 m_state.protocol.wait_init = true;
1021 guard.unlock();
1022 m_handler.after_init_connection();
1023 guard.lock();
1024 m_state.protocol.wait_init = false;
1025 m_state.protocol.initialized = true;
1026 if (m_state.status == status_t::INTERRUPTED)
1028 else if (m_state.status == status_t::TERMINATING)
1030 else if (!is_income || !m_state.ssl.enabled)
1031 start_read();
1032 else
1034 return true;
1035 }
1036
1037 template<typename T>
1039 io_context_t &io_context,
1040 std::shared_ptr<shared_state> shared_state,
1041 t_connection_type connection_type,
1042 ssl_support_t ssl_support,
1043 t_connection_context&& initial
1044 ):
1045 connection(
1046 io_context,
1047 socket_t{io_context},
1048 std::move(shared_state),
1049 connection_type,
1050 ssl_support,
1051 std::move(initial)
1052 )
1053 {
1054 }
1055
1056 template<typename T>
1058 io_context_t &io_context,
1059 socket_t &&socket,
1060 std::shared_ptr<shared_state> shared_state,
1061 t_connection_type connection_type,
1062 ssl_support_t ssl_support,
1063 t_connection_context&& initial
1064 ):
1065 connection_basic(io_context, std::move(socket), shared_state, ssl_support),
1067 m_connection_type(connection_type),
1068 m_io_context{io_context},
1069 m_conn_context(std::move(initial)),
1072 {
1073 }
1074
1075 template<typename T>
1077 {
1078 std::lock_guard<std::mutex> guard(m_state.lock);
1079 assert(m_state.status == status_t::TERMINATED ||
1080 m_state.status == status_t::WASTED ||
1081 m_io_context.stopped()
1082 );
1083 if (m_state.status != status_t::WASTED)
1084 return;
1085 try { host_count(-1); } catch (...) { /* ignore */ }
1086 }
1087
1088 template<typename T>
1090 bool is_income,
1091 bool is_multithreaded
1092 )
1093 {
1094 return start_internal(is_income, is_multithreaded, {});
1095 }
1096
1097 template<typename T>
1099 bool is_income,
1100 bool is_multithreaded,
1101 network_address real_remote
1102 )
1103 {
1104 return start_internal(is_income, is_multithreaded, real_remote);
1105 }
1106
1107 template<typename T>
1109 {
1110 std::lock_guard<std::mutex> guard(m_state.lock);
1111 std::string address;
1112 std::string port;
1113 ec_t ec;
1114 auto endpoint = connection_basic::socket().remote_endpoint(ec);
1115 if (ec.value()) {
1116 address = "<not connected>";
1117 port = "<not connected>";
1118 }
1119 else {
1120 address = endpoint.address().to_string();
1121 port = std::to_string(endpoint.port());
1122 }
1123 MDEBUG(
1124 " connection type " << std::to_string(m_connection_type) <<
1125 " " << connection_basic::socket().local_endpoint().address().to_string() <<
1126 ":" << connection_basic::socket().local_endpoint().port() <<
1127 " <--> " << m_conn_context.m_remote_address.str() <<
1128 " (via " << address << ":" << port << ")"
1129 );
1130 }
1131
1132 template<typename T>
1137
1138 template<typename T>
1139 bool connection<T>::cancel(const bool wait_for_shutdown)
1140 {
1141 return close(wait_for_shutdown);
1142 }
1143
1144 template<typename T>
1146 {
1147 return send(std::move(message));
1148 }
1149
1150 template<typename T>
1152 {
1153 return true;
1154 }
1155
1156 template<typename T>
1157 bool connection<T>::close(const bool wait_for_shutdown)
1158 {
1159 std::lock_guard<std::mutex> guard(m_state.lock);
1160 if (m_state.status == status_t::TERMINATED || m_state.status == status_t::WASTED)
1161 return true;
1162 if (!wait_for_shutdown && m_state.status != status_t::RUNNING)
1163 return false;
1165
1166 // Sometimes we do *not* want to wait for the connection to shut down because for example handle_recv might try to
1167 // close the connection when handling a request. But handle_recv can't complete the shutdown sequence because
1168 // handle_read is set to true. So, in that case we call terminate_async and return here.
1169 if (!wait_for_shutdown)
1170 return true;
1171
1172 // Sometimes we *do* want to wait for the connection to shut down for example when stopping the server. When
1173 // stopping the server, we don't want the io_context to stop before the shutdown sequence completes, since we
1174 // execute terminate inside m_strand. So we wait for the connection's shutdown sequence to complete before stopping
1175 // the io_context.
1176 MDEBUG("Waiting for connection " << m_conn_context.m_connection_id << " to shutdown, current state: " << m_state.status);
1177 const bool shutdown = m_state.condition.wait_for(
1178 m_state.lock,
1179 std::chrono::seconds(5),
1180 [this]{
1181 return (
1182 m_state.status == status_t::TERMINATED || m_state.status == status_t::WASTED
1183 );
1184 }
1185 );
1186 if (shutdown)
1187 MDEBUG("Shut down connection " << m_conn_context.m_connection_id);
1188 else
1189 MERROR("Connection " << m_conn_context.m_connection_id << " did not shut down");
1190
1191 return shutdown;
1192 }
1193
1194 template<typename T>
1196 {
1198 if (!m_io_context.poll_one())
1200 }
1201 else {
1202 if (!m_io_context.run_one())
1203 return false;
1204 }
1205 return true;
1206 }
1207
1208 template<typename T>
1210 {
1211 std::lock_guard<std::mutex> guard(m_state.lock);
1212 if (m_state.status != status_t::RUNNING)
1213 return false;
1215 ++m_state.protocol.wait_callback;
1216 boost::asio::post(connection_basic::strand_, [this, self]{
1217 TRY_ENTRY();
1218 m_handler.handle_qued_callback();
1219 CATCH_ENTRY_SWALLOW_EX("m_handler.handle_qued_callback");
1220 std::lock_guard<std::mutex> guard(m_state.lock);
1221 --m_state.protocol.wait_callback;
1222 if (m_state.status == status_t::INTERRUPTED)
1224 else if (m_state.status == status_t::TERMINATING)
1226 });
1227 return true;
1228 }
1229
1230 template<typename T>
1235
1236 template<typename T>
1238 {
1239 auto self = connection<T>::weak_from_this().lock();
1240 if (!self)
1241 return false;
1242 std::lock_guard<std::mutex> guard(m_state.lock);
1243 this->self = std::move(self);
1244 ++m_state.protocol.reference_counter;
1245 return true;
1246 }
1247
1248 template<typename T>
1250 {
1252 std::lock_guard<std::mutex> guard(m_state.lock);
1253 if (!(--m_state.protocol.reference_counter))
1254 self = std::move(this->self);
1255 return true;
1256 }
1257
1258 template<typename T>
1260 {
1261 std::lock_guard<std::mutex> guard(m_state.lock);
1263 }
1264
1265 template<class t_protocol_handler>
1267 m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
1274 m_threads_count(0),
1275 m_thread_index(0),
1276 m_connection_type( connection_type ),
1279 {
1281 m_thread_name_prefix = "NET";
1282 }
1283
1284 template<class t_protocol_handler>
1285 boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_context& extarnal_io_context, t_connection_type connection_type) :
1286 m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
1287 io_context_(extarnal_io_context),
1292 m_threads_count(0),
1293 m_thread_index(0),
1294 m_connection_type(connection_type),
1297 {
1299 m_thread_name_prefix = "NET";
1300 }
1301 //---------------------------------------------------------------------------------
1302 template<class t_protocol_handler>
1308 //---------------------------------------------------------------------------------
1309 template<class t_protocol_handler>
1316 //---------------------------------------------------------------------------------
1317 template<class t_protocol_handler>
1319 uint32_t port_ipv6, const std::string& address_ipv6, bool use_ipv6, bool require_ipv4,
1320 ssl_options_t ssl_options)
1321 {
1322 TRY_ENTRY();
1323 m_stop_signal_sent = false;
1324 m_port = port;
1325 m_port_ipv6 = port_ipv6;
1326 m_address = address;
1327 m_address_ipv6 = address_ipv6;
1328 m_use_ipv6 = use_ipv6;
1329 m_require_ipv4 = require_ipv4;
1330
1331 if (ssl_options)
1332 m_state->configure_ssl(std::move(ssl_options));
1333
1334 std::string ipv4_failed = "";
1335 std::string ipv6_failed = "";
1336
1337 boost::asio::ip::tcp::resolver resolver(io_context_);
1338
1339 try
1340 {
1341 const auto results = resolver.resolve(
1342 address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::canonical_name
1343 );
1344 acceptor_.open(results.begin()->endpoint().protocol());
1345#if !defined(_WIN32)
1346 acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
1347#endif
1348 acceptor_.bind(*results.begin());
1349 acceptor_.listen();
1350 boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
1351 m_port = binded_endpoint.port();
1352 MDEBUG("start accept (IPv4)");
1354 acceptor_.async_accept(new_connection_->socket(),
1356 boost::asio::placeholders::error));
1357 }
1358 catch (const std::exception &e)
1359 {
1360 ipv4_failed = e.what();
1361 }
1362
1363 if (ipv4_failed != "")
1364 {
1365 MERROR("Failed to bind IPv4: " << ipv4_failed);
1366 if (require_ipv4)
1367 {
1368 throw std::runtime_error("Failed to bind IPv4 (set to required)");
1369 }
1370 }
1371
1372 if (use_ipv6)
1373 {
1374 try
1375 {
1376 if (port_ipv6 == 0) port_ipv6 = port; // default arg means bind to same port as ipv4
1377
1378 const auto results = resolver.resolve(
1379 address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::canonical_name
1380 );
1381
1382 acceptor_ipv6.open(results.begin()->endpoint().protocol());
1383#if !defined(_WIN32)
1384 acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
1385#endif
1386 acceptor_ipv6.set_option(boost::asio::ip::v6_only(true));
1387 acceptor_ipv6.bind(*results.begin());
1388 acceptor_ipv6.listen();
1389 boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_ipv6.local_endpoint();
1390 m_port_ipv6 = binded_endpoint.port();
1391 MDEBUG("start accept (IPv6)");
1393 acceptor_ipv6.async_accept(new_connection_ipv6->socket(),
1395 boost::asio::placeholders::error));
1396 }
1397 catch (const std::exception &e)
1398 {
1399 ipv6_failed = e.what();
1400 }
1401 }
1402
1403 if (use_ipv6 && ipv6_failed != "")
1404 {
1405 MERROR("Failed to bind IPv6: " << ipv6_failed);
1406 if (ipv4_failed != "")
1407 {
1408 throw std::runtime_error("Failed to bind IPv4 and IPv6");
1409 }
1410 }
1411
1412 return true;
1413 }
1414 catch (const std::exception &e)
1415 {
1416 MFATAL("Error starting server: " << e.what());
1417 return false;
1418 }
1419 catch (...)
1420 {
1421 MFATAL("Error starting server");
1422 return false;
1423 }
1424 }
1425 //-----------------------------------------------------------------------------
1426 template<class t_protocol_handler>
1427 bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address,
1428 const std::string port_ipv6, const std::string address_ipv6, bool use_ipv6, bool require_ipv4,
1429 ssl_options_t ssl_options)
1430 {
1431 uint32_t p = 0;
1432 uint32_t p_ipv6 = 0;
1433
1434 if (port.size() && !string_tools::get_xtype_from_string(p, port)) {
1435 MERROR("Failed to convert port no = " << port);
1436 return false;
1437 }
1438
1439 if (port_ipv6.size() && !string_tools::get_xtype_from_string(p_ipv6, port_ipv6)) {
1440 MERROR("Failed to convert port no = " << port_ipv6);
1441 return false;
1442 }
1443 return this->init_server(p, address, p_ipv6, address_ipv6, use_ipv6, require_ipv4, std::move(ssl_options));
1444 }
1445 //---------------------------------------------------------------------------------
1446 template<class t_protocol_handler>
1448 {
1449 TRY_ENTRY();
1450 const uint32_t local_thr_index = m_thread_index++; // atomically increment, getting value before increment
1451 std::string thread_name = std::string("[") + m_thread_name_prefix;
1452 thread_name += boost::to_string(local_thr_index) + "]";
1453 MLOG_SET_THREAD_NAME(thread_name);
1454 // _fact("Thread name: " << m_thread_name_prefix);
1455 while(!m_stop_signal_sent)
1456 {
1457 try
1458 {
1459 io_context_.run();
1460 return true;
1461 }
1462 catch(const std::exception& ex)
1463 {
1464 _erro("Exception at server worker thread, what=" << ex.what());
1465 }
1466 catch(...)
1467 {
1468 _erro("Exception at server worker thread, unknown execption");
1469 }
1470 }
1471 //_info("Worker thread finished");
1472 return true;
1473 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::worker_thread", false);
1474 }
1475 //---------------------------------------------------------------------------------
1476 template<class t_protocol_handler>
1478 {
1479 m_thread_name_prefix = prefix_name;
1480 auto it = server_type_map.find(m_thread_name_prefix);
1481 if (it==server_type_map.end()) throw std::runtime_error("Unknown prefix/server type:" + std::string(prefix_name));
1482 auto connection_type = it->second; // the value of type
1483 MINFO("Set server type to: " << connection_type << " from name: " << m_thread_name_prefix << ", prefix_name = " << prefix_name);
1484 }
1485 //---------------------------------------------------------------------------------
1486 template<class t_protocol_handler>
1488 {
1489 assert(m_state != nullptr); // always set in constructor
1490 m_state->pfilter = pfilter;
1491 }
1492 //---------------------------------------------------------------------------------
1493 template<class t_protocol_handler>
1495 {
1496 assert(m_state != nullptr); // always set in constructor
1497 m_state->plimit = plimit;
1498 }
1499 //---------------------------------------------------------------------------------
1500 template<class t_protocol_handler>
1502 {
1503 assert(m_state != nullptr); // always set in constructor
1504 m_state->response_soft_limit = limit;
1505 }
1506 //---------------------------------------------------------------------------------
1507 template<class t_protocol_handler>
1508 bool boosted_tcp_server<t_protocol_handler>::run_server(size_t threads_count, bool wait, const boost::thread::attributes& attrs)
1509 {
1510 TRY_ENTRY();
1511 m_threads_count = threads_count;
1512 m_main_thread_id = boost::this_thread::get_id();
1513 MLOG_SET_THREAD_NAME("[SRV_MAIN]");
1514 while(!m_stop_signal_sent)
1515 {
1516
1517 // Create a pool of threads to run all of the io_contexts.
1519 for (std::size_t i = 0; i < threads_count; ++i)
1520 {
1521 boost::shared_ptr<boost::thread> thread(new boost::thread(
1522 attrs, boost::bind(&boosted_tcp_server<t_protocol_handler>::worker_thread, this)));
1523 _note("Run server thread name: " << m_thread_name_prefix);
1524 m_threads.push_back(thread);
1525 }
1527 // Wait for all threads in the pool to exit.
1528 if (wait)
1529 {
1530 _fact("JOINING all threads");
1531 for (std::size_t i = 0; i < m_threads.size(); ++i) {
1532 m_threads[i]->join();
1533 }
1534 _fact("JOINING all threads - almost");
1535 m_threads.clear();
1536 _fact("JOINING all threads - DONE");
1537
1538 }
1539 else {
1540 _dbg1("Reiniting OK.");
1541 return true;
1542 }
1543
1544 if(wait && !m_stop_signal_sent)
1545 {
1546 //some problems with the listening socket ?..
1547 _dbg1("Net service stopped without stop request, restarting...");
1549 {
1550 _dbg1("Reiniting service failed, exit.");
1551 return false;
1552 }else
1553 {
1554 _dbg1("Reiniting OK.");
1555 }
1556 }
1557 }
1558 return true;
1559 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::run_server", false);
1560 }
1561 //---------------------------------------------------------------------------------
1562 template<class t_protocol_handler>
1564 {
1565 TRY_ENTRY();
1567 BOOST_FOREACH(boost::shared_ptr<boost::thread>& thp, m_threads)
1568 {
1569 if(thp->get_id() == boost::this_thread::get_id())
1570 return true;
1571 }
1572 if(m_threads_count == 1 && boost::this_thread::get_id() == m_main_thread_id)
1573 return true;
1574 return false;
1575 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::is_thread_worker", false);
1576 }
1577 //---------------------------------------------------------------------------------
1578 template<class t_protocol_handler>
1580 {
1581 TRY_ENTRY();
1582 boost::chrono::milliseconds ms(wait_mseconds);
1583 for (std::size_t i = 0; i < m_threads.size(); ++i)
1584 {
1585 if(m_threads[i]->joinable() && !m_threads[i]->try_join_for(ms))
1586 {
1587 _dbg1("Interrupting thread " << m_threads[i]->native_handle());
1588 m_threads[i]->interrupt();
1589 }
1590 }
1591 return true;
1592 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::timed_wait_server_stop", false);
1593 }
1594 //---------------------------------------------------------------------------------
1595 template<class t_protocol_handler>
1597 {
1598 if (m_stop_signal_sent.exchange(true))
1599 {
1600 MDEBUG("Stop signal already sent");
1601 return false;
1602 }
1604 state->stop_signal_sent = true;
1605 return true;
1606 }
1607 //---------------------------------------------------------------------------------
1608 template<class t_protocol_handler>
1610 {
1611 decltype(connections_) connections;
1612 {
1613 boost::unique_lock<boost::mutex> lock(connections_mutex);
1614 connections.swap(connections_);
1615 }
1616
1617 for (auto &c: connections)
1618 {
1619 c->cancel(true/*wait_for_shutdown*/);
1620 }
1621 }
1622 //---------------------------------------------------------------------------------
1623 template<class t_protocol_handler>
1625 {
1626 {
1627 boost::unique_lock<boost::mutex> lock(connections_mutex);
1628 if (!connections_.empty())
1629 {
1630 MERROR("Stopping io_context with " << connections_.size() << " server-owned connections still open");
1631 }
1632 }
1633 MDEBUG("Stopping io_context");
1634 io_context_.stop();
1635 }
1636 //---------------------------------------------------------------------------------
1637 template<class t_protocol_handler>
1639 {
1640 TRY_ENTRY();
1641 if (!mark_stop_signal_sent())
1642 return;
1645 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
1646 }
1647 //---------------------------------------------------------------------------------
1648 template<class t_protocol_handler>
1649 void boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4(const boost::system::error_code& e)
1650 {
1651 this->handle_accept(e, false);
1652 }
1653 //---------------------------------------------------------------------------------
1654 template<class t_protocol_handler>
1655 void boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6(const boost::system::error_code& e)
1656 {
1657 this->handle_accept(e, true);
1658 }
1659 //---------------------------------------------------------------------------------
1660 template<class t_protocol_handler>
1661 void boosted_tcp_server<t_protocol_handler>::handle_accept(const boost::system::error_code& e, bool ipv6)
1662 {
1663 MDEBUG("handle_accept");
1664
1665 boost::asio::ip::tcp::acceptor* current_acceptor = &acceptor_;
1666 connection_ptr* current_new_connection = &new_connection_;
1667 auto accept_function_pointer = &boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4;
1668 if (ipv6)
1669 {
1670 current_acceptor = &acceptor_ipv6;
1671 current_new_connection = &new_connection_ipv6;
1673 }
1674
1675 bool accept_started = false;
1676 try
1677 {
1678 if (!e)
1679 {
1681 const char *ssl_message = "unknown";
1682 switch ((*current_new_connection)->get_ssl_support())
1683 {
1684 case epee::net_utils::ssl_support_t::e_ssl_support_disabled: ssl_message = "disabled"; break;
1685 case epee::net_utils::ssl_support_t::e_ssl_support_enabled: ssl_message = "enabled"; break;
1686 case epee::net_utils::ssl_support_t::e_ssl_support_autodetect: ssl_message = "autodetection"; break;
1687 }
1688 MDEBUG("New server for RPC connections, SSL " << ssl_message);
1689 (*current_new_connection)->setRpcStation(); // hopefully this is not needed actually
1690 }
1691 connection_ptr conn(std::move((*current_new_connection)));
1692 (*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, conn->get_ssl_support()));
1693 current_acceptor->async_accept((*current_new_connection)->socket(),
1694 boost::bind(accept_function_pointer, this,
1695 boost::asio::placeholders::error));
1696 accept_started = true;
1697
1698 boost::asio::socket_base::keep_alive opt(true);
1699 conn->socket().set_option(opt);
1700
1701 bool res;
1703 res = conn->start(true, 1 < m_threads_count);
1704 else
1705 res = conn->start(true, 1 < m_threads_count, default_remote);
1706 if (!res)
1707 {
1708 conn->cancel();
1709 return;
1710 }
1711 conn->save_dbg_log();
1712 return;
1713 }
1714 else
1715 {
1716 MERROR("Error in boosted_tcp_server<t_protocol_handler>::handle_accept: " << e);
1717 }
1718 }
1719 catch (const std::exception &e)
1720 {
1721 MERROR("Exception in boosted_tcp_server<t_protocol_handler>::handle_accept: " << e.what());
1722 if (accept_started)
1723 return;
1724 }
1725
1726 // error path, if e or exception
1727 assert(m_state != nullptr); // always set in constructor
1728 _erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
1730 (*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
1731 current_acceptor->async_accept((*current_new_connection)->socket(),
1732 boost::bind(accept_function_pointer, this,
1733 boost::asio::placeholders::error));
1734 }
1735 //---------------------------------------------------------------------------------
1736 template<class t_protocol_handler>
1738 {
1739 if(std::addressof(get_io_context()) == std::addressof(sock.get_executor().context()))
1740 {
1742 if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
1743 {
1744 conn->get_context(out);
1745 conn->save_dbg_log();
1746 return true;
1747 }
1748 }
1749 else
1750 {
1751 MWARNING(out << " was not added, socket/io_context mismatch");
1752 }
1753 return false;
1754 }
1755 //---------------------------------------------------------------------------------
1756 template<class t_protocol_handler>
1757 typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::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)
1758 {
1759 TRY_ENTRY();
1760
1761 sock_.open(remote_endpoint.protocol());
1762 if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
1763 {
1764 boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip), 0);
1765 boost::system::error_code ec;
1766 sock_.bind(local_endpoint, ec);
1767 if (ec)
1768 {
1769 MERROR("Error binding to " << bind_ip << ": " << ec.message());
1770 if (sock_.is_open())
1771 sock_.close();
1772 return CONNECT_FAILURE;
1773 }
1774 }
1775
1776 /*
1777 NOTICE: be careful to make sync connection from event handler: in case if all threads suddenly do sync connect, there will be no thread to dispatch events from io service.
1778 */
1779
1780 boost::system::error_code ec = boost::asio::error::would_block;
1781
1782 //have another free thread(s), work in wait mode, without event handling
1783 struct local_async_context
1784 {
1785 boost::system::error_code ec;
1786 boost::mutex connect_mut;
1787 boost::condition_variable cond;
1788 };
1789
1790 boost::shared_ptr<local_async_context> local_shared_context(new local_async_context());
1791 local_shared_context->ec = boost::asio::error::would_block;
1792 boost::unique_lock<boost::mutex> lock(local_shared_context->connect_mut);
1793 auto connect_callback = [](boost::system::error_code ec_, boost::shared_ptr<local_async_context> shared_context)
1794 {
1795 shared_context->connect_mut.lock(); shared_context->ec = ec_; shared_context->cond.notify_one(); shared_context->connect_mut.unlock();
1796 };
1797
1798 sock_.async_connect(remote_endpoint, std::bind<void>(connect_callback, std::placeholders::_1, local_shared_context));
1799 while(local_shared_context->ec == boost::asio::error::would_block)
1800 {
1801 bool r = local_shared_context->cond.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(conn_timeout));
1803 {
1804 if (sock_.is_open())
1805 sock_.close();
1806 return CONNECT_FAILURE;
1807 }
1808 if(local_shared_context->ec == boost::asio::error::would_block && !r)
1809 {
1810 //timeout
1811 sock_.close();
1812 _dbg3("Failed to connect to " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")");
1813 return CONNECT_FAILURE;
1814 }
1815 }
1816 ec = local_shared_context->ec;
1817
1818 if (ec || !sock_.is_open())
1819 {
1820 _dbg3("Some problems at connect, message: " << ec.message());
1821 if (sock_.is_open())
1822 sock_.close();
1823 return CONNECT_FAILURE;
1824 }
1825
1826 _dbg3("Connected success to " << adr << ':' << port);
1827
1828 const ssl_support_t ssl_support = new_connection_l->get_ssl_support();
1830 {
1831 // Handshake
1832 MDEBUG("Handshaking SSL...");
1833 if (!new_connection_l->handshake(boost::asio::ssl::stream_base::client))
1834 {
1836 {
1837 boost::system::error_code ignored_ec;
1838 sock_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
1839 sock_.close();
1840 return CONNECT_NO_SSL;
1841 }
1842 MERROR("SSL handshake failed");
1843 if (sock_.is_open())
1844 sock_.close();
1845 return CONNECT_FAILURE;
1846 }
1847 }
1848
1849 return CONNECT_SUCCESS;
1850
1851 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::try_connect", CONNECT_FAILURE);
1852 }
1853 //---------------------------------------------------------------------------------
1854 template<class t_protocol_handler>
1855 bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
1856 {
1857 TRY_ENTRY();
1858
1860 connections_mutex.lock();
1861 connections_.insert(new_connection_l);
1862 MDEBUG("connections_ size now " << connections_.size());
1863 connections_mutex.unlock();
1865 boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
1866
1867 bool try_ipv6 = false;
1868
1869 boost::asio::ip::tcp::resolver resolver(io_context_);
1870 boost::asio::ip::tcp::resolver::results_type results{};
1871 boost::system::error_code resolve_error;
1872
1873 try
1874 {
1875 //resolving ipv4 address as ipv6 throws, catch here and move on
1876 results = resolver.resolve(
1877 boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
1878 );
1879 }
1880 catch (const boost::system::system_error& e)
1881 {
1882 if (!m_use_ipv6 || (resolve_error != boost::asio::error::host_not_found &&
1883 resolve_error != boost::asio::error::host_not_found_try_again))
1884 {
1885 throw;
1886 }
1887 try_ipv6 = true;
1888 }
1889 catch (...)
1890 {
1891 throw;
1892 }
1893
1894 std::string bind_ip_to_use;
1895
1896 if(results.empty())
1897 {
1898 if (!m_use_ipv6)
1899 {
1900 _erro("Failed to resolve " << adr);
1901 return false;
1902 }
1903 else
1904 {
1905 try_ipv6 = true;
1906 MINFO("Resolving address as IPv4 failed, trying IPv6");
1907 }
1908 }
1909 else
1910 {
1911 bind_ip_to_use = bind_ip;
1912 }
1913
1914 if (try_ipv6)
1915 {
1916 results = resolver.resolve(
1917 boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
1918 );
1919
1920 if(results.empty())
1921 {
1922 _erro("Failed to resolve " << adr);
1923 return false;
1924 }
1925 else
1926 {
1927 if (bind_ip == "0.0.0.0")
1928 {
1929 bind_ip_to_use = "::";
1930 }
1931 else
1932 {
1933 bind_ip_to_use = "";
1934 }
1935
1936 }
1937
1938 }
1939
1940 const auto iterator = results.begin();
1941
1942 MDEBUG("Trying to connect to " << adr << ":" << port << ", bind_ip = " << bind_ip_to_use);
1943
1944 //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
1945 boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
1946
1947 auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_support);
1948 if (try_connect_result == CONNECT_FAILURE)
1949 return false;
1950 if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL)
1951 {
1952 // we connected, but could not connect with SSL, try without
1953 MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
1954 new_connection_l->disable_ssl();
1955 try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
1956 if (try_connect_result != CONNECT_SUCCESS)
1957 return false;
1958 }
1959
1960 // start adds the connection to the config object's list, so we don't need to have it locally anymore
1961 connections_mutex.lock();
1962 connections_.erase(new_connection_l);
1963 connections_mutex.unlock();
1964 bool r = new_connection_l->start(false, 1 < m_threads_count);
1965 if (r)
1966 {
1967 new_connection_l->get_context(conn_context);
1968 }
1969 else
1970 {
1971 assert(m_state != nullptr); // always set in constructor
1972 _erro("[sock " << new_connection_l->socket().native_handle() << "] Failed to start connection, connections_count = " << m_state->sock_count);
1973 }
1974
1975 new_connection_l->save_dbg_log();
1976
1977 return r;
1978
1979 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::connect", false);
1980 }
1981 //---------------------------------------------------------------------------------
1982 template<class t_protocol_handler> template<class t_callback>
1983 bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support, t_connection_context&& initial)
1984 {
1985 TRY_ENTRY();
1986 connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support, std::move(initial)) );
1987 connections_mutex.lock();
1988 connections_.insert(new_connection_l);
1989 MDEBUG("connections_ size now " << connections_.size());
1990 connections_mutex.unlock();
1992 boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
1993
1994 bool try_ipv6 = false;
1995
1996 boost::asio::ip::tcp::resolver resolver(io_context_);
1997 boost::asio::ip::tcp::resolver::results_type results{};
1998 boost::system::error_code resolve_error;
1999
2000 try
2001 {
2002 //resolving ipv4 address as ipv6 throws, catch here and move on
2003 results = resolver.resolve(
2004 boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
2005 );
2006 }
2007 catch (const boost::system::system_error& e)
2008 {
2009 if (!m_use_ipv6 || (resolve_error != boost::asio::error::host_not_found &&
2010 resolve_error != boost::asio::error::host_not_found_try_again))
2011 {
2012 throw;
2013 }
2014 try_ipv6 = true;
2015 }
2016 catch (...)
2017 {
2018 throw;
2019 }
2020
2021 if(results.empty())
2022 {
2023 if (!try_ipv6)
2024 {
2025 _erro("Failed to resolve " << adr);
2026 return false;
2027 }
2028 else
2029 {
2030 MINFO("Resolving address as IPv4 failed, trying IPv6");
2031 }
2032 }
2033
2034 if (try_ipv6)
2035 {
2036 results = resolver.resolve(
2037 boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
2038 );
2039
2040 if(results.empty())
2041 {
2042 _erro("Failed to resolve " << adr);
2043 return false;
2044 }
2045 }
2046
2047 boost::asio::ip::tcp::endpoint remote_endpoint(*results.begin());
2048
2049 sock_.open(remote_endpoint.protocol());
2050 if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
2051 {
2052 boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip.c_str()), 0);
2053 boost::system::error_code ec;
2054 sock_.bind(local_endpoint, ec);
2055 if (ec)
2056 {
2057 MERROR("Error binding to " << bind_ip << ": " << ec.message());
2058 if (sock_.is_open())
2059 sock_.close();
2060 return false;
2061 }
2062 }
2063
2064 boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_context_));
2065 //start deadline
2066 sh_deadline->expires_from_now(boost::posix_time::milliseconds(conn_timeout));
2067 sh_deadline->async_wait([=](const boost::system::error_code& error)
2068 {
2069 if(error != boost::asio::error::operation_aborted)
2070 {
2071 _dbg3("Failed to connect to " << adr << ':' << port << ", because of timeout (" << conn_timeout << ")");
2072 new_connection_l->socket().close();
2073 }
2074 });
2075 //start async connect
2076 sock_.async_connect(remote_endpoint, [=](const boost::system::error_code& ec_)
2077 {
2078 t_connection_context conn_context = AUTO_VAL_INIT(conn_context);
2079 boost::system::error_code ignored_ec;
2080 boost::asio::ip::tcp::socket::endpoint_type lep = new_connection_l->socket().local_endpoint(ignored_ec);
2081 if(!ec_)
2082 {//success
2083 if(!sh_deadline->cancel())
2084 {
2085 cb(conn_context, boost::asio::error::operation_aborted);//this mean that deadline timer already queued callback with cancel operation, rare situation
2086 }else
2087 {
2088 _dbg3("[sock " << new_connection_l->socket().native_handle() << "] Connected success to " << adr << ':' << port <<
2089 " from " << lep.address().to_string() << ':' << lep.port());
2090
2091 // start adds the connection to the config object's list, so we don't need to have it locally anymore
2092 connections_mutex.lock();
2093 connections_.erase(new_connection_l);
2094 connections_mutex.unlock();
2095 bool r = new_connection_l->start(false, 1 < m_threads_count);
2096 if (r)
2097 {
2098 new_connection_l->get_context(conn_context);
2099 cb(conn_context, ec_);
2100 }
2101 else
2102 {
2103 _dbg3("[sock " << new_connection_l->socket().native_handle() << "] Failed to start connection to " << adr << ':' << port);
2104 cb(conn_context, boost::asio::error::fault);
2105 }
2106 }
2107 }else
2108 {
2109 _dbg3("[sock " << new_connection_l->socket().native_handle() << "] Failed to connect to " << adr << ':' << port <<
2110 " from " << lep.address().to_string() << ':' << lep.port() << ": " << ec_.message() << ':' << ec_.value());
2111 cb(conn_context, ec_);
2112 }
2113 });
2114 return true;
2115 CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::connect_async", false);
2116 }
2117
2118} // namespace
2119} // namespace
#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT
Definition abstract_tcp_server2.h:67
#define NEW_CONNECTION_TIMEOUT_LOCAL
Definition abstract_tcp_server2.inl:60
#define NEW_CONNECTION_TIMEOUT_REMOTE
Definition abstract_tcp_server2.inl:61
#define TIMEOUT_EXTRA_MS_PER_BYTE
Definition abstract_tcp_server2.inl:64
#define AGGRESSIVE_TIMEOUT_THRESHOLD
Definition abstract_tcp_server2.inl:59
#define DEFAULT_TIMEOUT_MS_LOCAL
Definition abstract_tcp_server2.inl:62
#define DEFAULT_TIMEOUT_MS_REMOTE
Definition abstract_tcp_server2.inl:63
Definition byte_slice.h:69
boost::asio::ip::tcp::acceptor acceptor_ipv6
Definition abstract_tcp_server2.h:537
boost::shared_ptr< connection< t_protocol_handler > > connection_ptr
Definition abstract_tcp_server2.h:358
uint32_t m_port
Definition abstract_tcp_server2.h:541
size_t m_threads_count
Definition abstract_tcp_server2.h:548
void set_connection_limit(i_connection_limit *plimit)
Definition abstract_tcp_server2.inl:1494
void handle_accept_ipv6(const boost::system::error_code &e)
Definition abstract_tcp_server2.inl:1655
bool m_require_ipv4
Definition abstract_tcp_server2.h:546
std::map< std::string, t_connection_type > server_type_map
Definition abstract_tcp_server2.h:367
std::vector< boost::shared_ptr< boost::thread > > m_threads
Definition abstract_tcp_server2.h:549
boost::asio::ip::tcp::acceptor acceptor_
Acceptor used to listen for incoming connections.
Definition abstract_tcp_server2.h:536
try_connect_result_t
Definition abstract_tcp_server2.h:351
@ CONNECT_FAILURE
Definition abstract_tcp_server2.h:353
@ CONNECT_NO_SSL
Definition abstract_tcp_server2.h:354
@ CONNECT_SUCCESS
Definition abstract_tcp_server2.h:352
std::atomic< bool > m_stop_signal_sent
Definition abstract_tcp_server2.h:540
~boosted_tcp_server()
Definition abstract_tcp_server2.inl:1303
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:1855
bool timed_wait_server_stop(uint64_t wait_mseconds)
wait for service workers stop
Definition abstract_tcp_server2.inl:1579
connection_ptr new_connection_
The next connection to be accepted.
Definition abstract_tcp_server2.h:557
boost::asio::io_context & get_io_context()
Definition abstract_tcp_server2.h:452
t_protocol_handler::connection_context t_connection_context
Definition abstract_tcp_server2.h:359
boosted_tcp_server(t_connection_type connection_type)
Definition abstract_tcp_server2.inl:1266
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:1757
boost::mutex connections_mutex
Definition abstract_tcp_server2.h:561
void handle_accept_ipv4(const boost::system::error_code &e)
Handle completion of an asynchronous accept operation.
Definition abstract_tcp_server2.inl:1649
connection_ptr new_connection_ipv6
Definition abstract_tcp_server2.h:558
bool worker_thread()
Run the server's io_context loop.
Definition abstract_tcp_server2.inl:1447
void create_server_type_map()
Definition abstract_tcp_server2.inl:1310
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:1737
std::string m_address_ipv6
Definition abstract_tcp_server2.h:544
void send_stop_signal()
Definition abstract_tcp_server2.inl:1638
bool mark_stop_signal_sent()
Mark the server as stopping without closing connections or stopping the io_context.
Definition abstract_tcp_server2.inl:1596
critical_section m_threads_lock
Definition abstract_tcp_server2.h:551
void set_connection_filter(i_connection_filter *pfilter)
Definition abstract_tcp_server2.inl:1487
t_connection_type m_connection_type
Definition abstract_tcp_server2.h:554
std::string m_address
Definition abstract_tcp_server2.h:543
std::string m_thread_name_prefix
Definition abstract_tcp_server2.h:547
epee::net_utils::network_address default_remote
Definition abstract_tcp_server2.h:538
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:1508
void handle_accept(const boost::system::error_code &e, bool ipv6=false)
Definition abstract_tcp_server2.inl:1661
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:1477
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:1318
void stop_io_context()
Stop the server io_context.
Definition abstract_tcp_server2.inl:1624
boost::asio::io_context & io_context_
Definition abstract_tcp_server2.h:533
std::unique_ptr< worker > m_io_context_local_instance
Definition abstract_tcp_server2.h:532
uint32_t m_port_ipv6
Definition abstract_tcp_server2.h:542
void set_response_soft_limit(std::size_t limit)
Definition abstract_tcp_server2.inl:1501
bool m_use_ipv6
Definition abstract_tcp_server2.h:545
boost::thread::id m_main_thread_id
Definition abstract_tcp_server2.h:550
std::set< connection_ptr > connections_
Definition abstract_tcp_server2.h:562
bool is_thread_worker()
Definition abstract_tcp_server2.inl:1563
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:520
void close_server_connections()
Close boosted_tcp_server-owned connections, including ones not yet registered with the protocol handl...
Definition abstract_tcp_server2.inl:1609
std::atomic< uint32_t > m_thread_index
Definition abstract_tcp_server2.h:552
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:1259
virtual bool call_run_once_service_io()
Definition abstract_tcp_server2.inl:1195
boost::asio::ip::tcp::socket socket_t
Definition abstract_tcp_server2.h:122
io_context_t & m_io_context
Definition abstract_tcp_server2.h:262
void terminate()
Definition abstract_tcp_server2.inl:748
virtual bool send_done()
Definition abstract_tcp_server2.inl:1151
void start_timer(duration_t duration, bool add={})
Definition abstract_tcp_server2.inl:145
t_protocol_handler::connection_context t_connection_context
Definition abstract_tcp_server2.h:102
void cancel_handler()
Definition abstract_tcp_server2.inl:672
boost::asio::io_context io_context_t
Definition abstract_tcp_server2.h:120
void async_wait_timer()
Definition abstract_tcp_server2.inl:169
bool m_local
Definition abstract_tcp_server2.h:268
void start_write()
Definition abstract_tcp_server2.inl:473
t_protocol_handler m_handler
Definition abstract_tcp_server2.h:271
void start_read()
Definition abstract_tcp_server2.inl:306
void interrupt()
Definition abstract_tcp_server2.inl:689
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:1038
void on_terminating()
Definition abstract_tcp_server2.inl:763
virtual bool do_send(byte_slice message)
(see do_send from i_service_endpoint)
Definition abstract_tcp_server2.inl:1145
bool send(epee::byte_slice message)
Definition abstract_tcp_server2.inl:818
virtual bool release()
Definition abstract_tcp_server2.inl:1249
virtual bool request_callback()
Definition abstract_tcp_server2.inl:1209
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:1133
boost::shared_ptr< connection_t > connection_ptr
Definition abstract_tcp_server2.h:113
void on_interrupted()
Definition abstract_tcp_server2.inl:702
std::string m_host
Definition abstract_tcp_server2.h:269
void start_handshake()
Definition abstract_tcp_server2.inl:210
virtual io_context_t & get_io_context()
Definition abstract_tcp_server2.inl:1231
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:933
@ RUNNING
Definition abstract_tcp_server2.h:106
@ INTERRUPTED
Definition abstract_tcp_server2.h:107
@ TERMINATING
Definition abstract_tcp_server2.h:108
@ WASTED
Definition abstract_tcp_server2.h:109
@ TERMINATED
Definition abstract_tcp_server2.h:105
void terminate_async()
Definition abstract_tcp_server2.inl:807
duration_t get_timeout_from_bytes_read(size_t bytes) const
Definition abstract_tcp_server2.inl:116
virtual ~connection() noexcept(false)
Definition abstract_tcp_server2.inl:1076
void cancel_timer()
Definition abstract_tcp_server2.inl:200
void handle_read(size_t bytes_transferred)
Definition abstract_tcp_server2.inl:414
bool cancel(bool wait_for_shutdown=false)
Definition abstract_tcp_server2.inl:1139
void state_status_check()
Definition abstract_tcp_server2.inl:126
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:604
epee::net_utils::ssl_support_t ssl_support_t
Definition abstract_tcp_server2.h:114
void cancel_socket()
Definition abstract_tcp_server2.inl:646
t_connection_context m_conn_context
Definition abstract_tcp_server2.h:264
virtual bool close(const bool wait_for_shutdown)
Definition abstract_tcp_server2.inl:1157
void save_dbg_log()
Definition abstract_tcp_server2.inl:1108
virtual bool add_ref()
Definition abstract_tcp_server2.inl:1237
unsigned int host_count(int delta=0)
Definition abstract_tcp_server2.inl:82
bool start(bool is_income, bool is_multithreaded)
Start the first asynchronous operation for the connection.
Definition abstract_tcp_server2.inl:1089
timer_t::duration duration_t
Definition abstract_tcp_server2.h:116
t_connection_type m_connection_type
Definition abstract_tcp_server2.h:263
connection_ptr self
Definition abstract_tcp_server2.h:267
duration_t get_default_timeout()
Definition abstract_tcp_server2.inl:99
boost::system::error_code ec_t
Definition abstract_tcp_server2.h:117
Definition net_utils_base.h:70
static constexpr address_type get_type_id() noexcept
Definition net_utils_base.h:93
Definition net_utils_base.h:173
Definition net_utils_base.h:229
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
Definition net_ssl.h:78
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))
#define false
#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:72
@ 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:423
constexpr size_t get_ssl_magic_size()
Definition net_ssl.h:154
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:50
@ e_ssl_support_disabled
Definition net_ssl.h:51
@ e_ssl_support_autodetect
Definition net_ssl.h:53
@ e_ssl_support_enabled
Definition net_ssl.h:52
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Definition string_tools_lexical.h:45
TODO: (mj-xmr) This will be reduced in an another PR.
Definition byte_slice.h:40
int time
Definition gen_wide_data.py:40
Definition speed.py:1
Definition enums.h:68
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:524
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
Definition blake256.h:36
#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
#define T(x)