Monero
Loading...
Searching...
No Matches
levin_protocol_handler_async.h
Go to the documentation of this file.
1// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above copyright
9// notice, this list of conditions and the following disclaimer in the
10// documentation and/or other materials provided with the distribution.
11// * Neither the name of the Andrey N. Sabelnikov nor the
12// names of its contributors may be used to endorse or promote products
13// derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
19// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25//
26
27#pragma once
28#include <boost/asio/deadline_timer.hpp>
29#include <boost/uuid/uuid_generators.hpp>
30#include <boost/unordered_map.hpp>
31#include <boost/smart_ptr/make_shared.hpp>
32
33#include <atomic>
34#include <deque>
35
36#include "levin_base.h"
37#include "buffer.h"
38#include "misc_language.h"
39#include "syncobj.h"
40#include "time_helper.h"
41#include "int-util.h"
42
43#include <random>
44#include <chrono>
45
46#undef MONERO_DEFAULT_LOG_CATEGORY
47#define MONERO_DEFAULT_LOG_CATEGORY "net"
48
49#ifndef MIN_BYTES_WANTED
50#define MIN_BYTES_WANTED 512
51#endif
52
53template<typename context_t>
54void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, const char* category)
55{
56 MCINFO("net.p2p.traffic", context << bytes << " bytes " << (sent ? "sent" : "received") << (error ? "/corrupt" : "")
57 << " for category " << category << " initiated by " << (initiator ? "us" : "peer"));
58}
59
60template<typename context_t>
61void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, int command)
62{
63 char buf[32];
64 snprintf(buf, sizeof(buf), "command-%u", command);
65 on_levin_traffic(context, initiator, sent, error, bytes, buf);
66}
67
68namespace epee
69{
70namespace levin
71{
72
73/************************************************************************/
74/* */
75/************************************************************************/
76template<class t_connection_context>
78
79template<class t_connection_context>
81{
82 typedef boost::unordered_map<boost::uuids::uuid, async_protocol_handler<t_connection_context>* > connections_map;
85
88
89 async_protocol_handler<t_connection_context>* find_connection(boost::uuids::uuid connection_id) const;
90 int find_and_lock_connection(boost::uuids::uuid connection_id, async_protocol_handler<t_connection_context>*& aph);
91
92 friend class async_protocol_handler<t_connection_context>;
93
96
97 void delete_connections (size_t count, bool incoming);
98
99public:
100 typedef t_connection_context connection_context;
104
105 int invoke(int command, message_writer in_msg, std::string& buff_out, boost::uuids::uuid connection_id);
106 template<class callback_t>
107 int invoke_async(int command, message_writer in_msg, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
108
109 bool send(epee::byte_slice message, const boost::uuids::uuid& connection_id);
110 bool close(boost::uuids::uuid connection_id, const bool wait_for_shutdown);
111 bool update_connection_context(const t_connection_context& contxt);
112 bool request_callback(boost::uuids::uuid connection_id);
113 template<class callback_t>
114 bool foreach_connection(const callback_t &cb);
115 template<class callback_t>
116 bool for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb);
121
125 void del_out_connections(size_t count);
126 void del_in_connections(size_t count);
127};
128
129
130/************************************************************************/
131/* */
132/************************************************************************/
133template<class t_connection_context = net_utils::connection_context_base>
135{
136 std::string m_fragment_buffer;
137
139 {
140 if (message.size() < sizeof(message_writer::header))
141 return false;
142
144 std::memcpy(std::addressof(head), message.data(), sizeof(head));
145 if(!m_pservice_endpoint->do_send(std::move(message)))
146 return false;
147
148 on_levin_traffic(m_connection_context, true, true, false, head.m_cb, head.m_command);
149 MDEBUG(m_connection_context << "LEVIN_PACKET_SENT. [len=" << head.m_cb
150 << ", flags" << head.m_flags
151 << ", r?=" << head.m_have_to_return_data
152 <<", cmd = " << head.m_command
153 << ", ver=" << head.m_protocol_version);
154 return true;
155 }
156
157public:
158 typedef t_connection_context connection_context;
160
166
167 std::atomic<bool> m_protocol_released;
168 std::atomic<bool> m_invoke_buf_ready;
169
171
173 std::string m_local_inv_buff;
174
176
177 std::atomic<uint32_t> m_wait_count;
178 std::atomic<uint32_t> m_close_called;
182 t_connection_context& m_connection_context;
183 std::atomic<uint64_t> m_max_packet_size;
184
187
190
192 {
193 virtual bool handle(int res, const epee::span<const uint8_t> buff, connection_context& context)=0;
194 virtual bool is_timer_started() const=0;
195 virtual void cancel()=0;
196 virtual bool cancel_timer()=0;
197 virtual void reset_timer()=0;
198 };
199 template <class callback_t>
201 {
202 anvoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command)
203 :m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_context()), m_timer_started(false),
205 {
207 {
208 MDEBUG(con.get_context_ref() << "anvoke_handler, timeout: " << timeout);
209 m_timer.expires_from_now(boost::posix_time::milliseconds(timeout));
210 m_timer.async_wait([&con, command, cb, timeout](const boost::system::error_code& ec)
211 {
212 if(ec == boost::asio::error::operation_aborted)
213 return;
214 MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
215 epee::span<const uint8_t> fake;
216 cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
217 con.close(false);
218 con.finish_outer_call();
219 });
220 m_timer_started = true;
221 }
222 }
224 {}
225 callback_t m_cb;
227 boost::asio::deadline_timer m_timer;
233 virtual bool handle(int res, const epee::span<const uint8_t> buff, typename async_protocol_handler::connection_context& context)
234 {
235 if(!cancel_timer())
236 return false;
237 m_cb(res, buff, context);
239 return true;
240 }
241 virtual bool is_timer_started() const
242 {
243 return m_timer_started;
244 }
245 virtual void cancel()
246 {
247 if(cancel_timer())
248 {
252 }
253 }
254 virtual bool cancel_timer()
255 {
257 {
259 boost::system::error_code ignored_ec;
260 m_timer_cancelled = 1 == m_timer.cancel(ignored_ec);
261 }
262 return m_timer_cancelled;
263 }
264 virtual void reset_timer()
265 {
266 if (m_command == connection_context::handshake_command())
267 return;
268 boost::system::error_code ignored_ec;
269 if (!m_cancel_timer_called && m_timer.cancel(ignored_ec) > 0)
270 {
271 callback_t& cb = m_cb;
272 uint64_t timeout = m_timeout;
274 int command = m_command;
275 m_timer.expires_from_now(boost::posix_time::milliseconds(m_timeout));
276 m_timer.async_wait([&con, cb, command, timeout](const boost::system::error_code& ec)
277 {
278 if(ec == boost::asio::error::operation_aborted)
279 return;
280 MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
283 con.close(false);
284 con.finish_outer_call();
285 });
286 }
287 }
288 };
290 std::list<boost::shared_ptr<invoke_response_handler_base> > m_invoke_response_handlers;
291
292 template<class callback_t>
293 bool add_invoke_response_handler(const callback_t &cb, uint64_t timeout, async_protocol_handler& con, int command)
294 {
297 {
298 MERROR("Adding response handler to a released object");
299 return false;
300 }
301 boost::shared_ptr<invoke_response_handler_base> handler(boost::make_shared<anvoke_handler<callback_t>>(cb, timeout, con, command));
302 m_invoke_response_handlers.push_back(handler);
303 return handler->is_timer_started();
304 }
305 template<class callback_t> friend struct anvoke_handler;
306public:
309 t_connection_context& conn_context):
311 m_pservice_endpoint(psnd_hndlr),
313 m_connection_context(conn_context),
314 m_max_packet_size(config.m_initial_max_packet_size),
315 m_cache_in_buffer(4 * 1024),
317 {
318 m_close_called = 0;
319 m_protocol_released = false;
320 m_wait_count = 0;
323 m_invoke_buf_ready = false;
325 }
327 {
328 try
329 {
330
332 {
333 m_config.del_connection(this);
334 }
335
336 for (size_t i = 0; i < 60 * 1000 / 100 && 0 != m_wait_count; ++i)
337 {
339 }
340 CHECK_AND_ASSERT_MES_NO_RET(0 == m_wait_count, "Failed to wait for operation completion. m_wait_count = " << m_wait_count.load());
341
342 MTRACE(m_connection_context << "~async_protocol_handler()");
343
344 }
345 catch (...) { /* ignore */ }
346 }
347
349 {
350 MTRACE(m_connection_context << "[levin_protocol] -->> start_outer_call");
351 if(!m_pservice_endpoint->add_ref())
352 {
353 MERROR(m_connection_context << "[levin_protocol] -->> start_outer_call failed");
354 return false;
355 }
356 ++m_wait_count;
357 return true;
358 }
360 {
361 MTRACE(m_connection_context << "[levin_protocol] <<-- finish_outer_call");
362 --m_wait_count;
363 m_pservice_endpoint->release();
364 return true;
365 }
366
368 {
369 decltype(m_invoke_response_handlers) local_invoke_response_handlers;
371 local_invoke_response_handlers.swap(m_invoke_response_handlers);
372 m_protocol_released = true;
374
375 // Never call callback inside critical section, that can cause deadlock. Callback can be called when
376 // invoke_response_handler_base is cancelled
377 std::for_each(local_invoke_response_handlers.begin(), local_invoke_response_handlers.end(), [](const boost::shared_ptr<invoke_response_handler_base>& pinv_resp_hndlr) {
378 pinv_resp_hndlr->cancel();
379 });
380
381 return true;
382 }
383
384 bool close(const bool wait_for_shutdown)
385 {
387
388 m_pservice_endpoint->close(wait_for_shutdown);
389 return true;
390 }
391
393 {
394 m_connection_context = contxt;
395 }
396
398 {
401
402 m_pservice_endpoint->request_callback();
403 }
404
406 {
407 m_config.m_pcommands_handler->callback(m_connection_context);
408 }
409
410 virtual bool handle_recv(const void* ptr, size_t cb)
411 {
413 return false; //closing connections
414
415 if(!m_config.m_pcommands_handler)
416 {
417 MERROR(m_connection_context << "Commands handler not set!");
418 return false;
419 }
420
421 // these should never fail, but do runtime check for safety
422 const uint64_t max_packet_size = m_max_packet_size;
423 CHECK_AND_ASSERT_MES(max_packet_size >= m_cache_in_buffer.size(), false, "Bad m_cache_in_buffer.size()");
424 CHECK_AND_ASSERT_MES(max_packet_size - m_cache_in_buffer.size() >= m_fragment_buffer.size(), false, "Bad m_cache_in_buffer.size() + m_fragment_buffer.size()");
425
426 // flipped to subtraction; prevent overflow since m_max_packet_size is variable and public
427 if(cb > max_packet_size - m_cache_in_buffer.size() - m_fragment_buffer.size())
428 {
429 MWARNING(m_connection_context << "Maximum packet size exceed!, m_max_packet_size = " << max_packet_size
430 << ", packet received " << m_cache_in_buffer.size() + cb
431 << ", connection will be closed.");
432 return false;
433 }
434
435 m_cache_in_buffer.append((const char*)ptr, cb);
436
437 bool is_continue = true;
438 while(is_continue)
439 {
440 switch(m_state)
441 {
443 if(m_cache_in_buffer.size() < m_current_head.m_cb)
444 {
445 is_continue = false;
446 if(cb >= MIN_BYTES_WANTED)
447 {
449 if (!m_invoke_response_handlers.empty())
450 {
451 //async call scenario
452 boost::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front();
453 response_handler->reset_timer();
454 MDEBUG(m_connection_context << "LEVIN_PACKET partial msg received. len=" << cb << ", current total " << m_cache_in_buffer.size() << "/" << m_current_head.m_cb << " (" << (100.0f * m_cache_in_buffer.size() / (m_current_head.m_cb ? m_current_head.m_cb : 1)) << "%)");
455 }
456 }
457 break;
458 }
459
460 {
461 std::string temp{};
462 epee::span<const uint8_t> buff_to_invoke = m_cache_in_buffer.carve((std::string::size_type)m_current_head.m_cb);
464
465 // abstract_tcp_server2.h manages max bandwidth for a p2p link
467 {
468 // special noise/fragment command
469 static constexpr const uint32_t both_flags = (LEVIN_PACKET_BEGIN | LEVIN_PACKET_END);
470 if ((m_current_head.m_flags & both_flags) == both_flags)
471 break; // noise message, skip to next message
472
474 m_fragment_buffer.clear();
475
476 m_fragment_buffer.append(reinterpret_cast<const char*>(buff_to_invoke.data()), buff_to_invoke.size());
477 if (!(m_current_head.m_flags & LEVIN_PACKET_END))
478 break; // skip to next message
479
480 if (m_fragment_buffer.size() < sizeof(bucket_head2))
481 {
482 MERROR(m_connection_context << "Fragmented data too small for levin header");
483 return false;
484 }
485
486 temp.swap(m_fragment_buffer);
487 std::memcpy(std::addressof(m_current_head), std::addressof(temp[0]), sizeof(bucket_head2));
488 const std::uint64_t inner_size = SWAP64LE(m_current_head.m_cb);
489 buff_to_invoke = {reinterpret_cast<const uint8_t*>(temp.data()) + sizeof(bucket_head2), temp.size() - sizeof(bucket_head2)};
490 if (buff_to_invoke.size() < inner_size)
491 {
492 MERROR(m_connection_context << "Invalid fragmented buffer size: " << buff_to_invoke.size() << " vs " << inner_size);
493 return false;
494 }
495
496 buff_to_invoke = {buff_to_invoke.data(), std::size_t(inner_size)};
497
498 const size_t max_bytes = m_connection_context.get_max_bytes(m_current_head.m_command);
499 if(buff_to_invoke.size() > std::min<size_t>(max_packet_size, max_bytes))
500 {
501 MERROR(m_connection_context << "Maximum packet size exceed!, m_max_packet_size = " << std::min<size_t>(max_packet_size, max_bytes)
502 << ", packet header received " << m_current_head.m_cb << ", command " << m_current_head.m_command
503 << ", connection will be closed.");
504 return false;
505 }
506 }
507
509
510 MDEBUG(m_connection_context << "LEVIN_PACKET_RECEIVED. [len=" << m_current_head.m_cb
511 << ", flags" << m_current_head.m_flags
512 << ", r?=" << m_current_head.m_have_to_return_data
513 <<", cmd = " << m_current_head.m_command
514 << ", v=" << m_current_head.m_protocol_version);
515
516 if(is_response)
517 {//response to some invoke
518
520 if(!m_invoke_response_handlers.empty())
521 {//async call scenario
522 boost::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front();
523 bool timer_cancelled = response_handler->cancel_timer();
524 // Don't pop handler, to avoid destroying it
525 if(timer_cancelled)
526 m_invoke_response_handlers.pop_front();
527 invoke_response_handlers_guard.unlock();
528
529 if(timer_cancelled)
530 response_handler->handle(m_current_head.m_return_code, buff_to_invoke, m_connection_context);
531 }
532 else
533 {
534 invoke_response_handlers_guard.unlock();
535 //use sync call scenario
537 {
538 MERROR(m_connection_context << "no active invoke when response came, wtf?");
539 return false;
540 }else
541 {
543 m_local_inv_buff = std::string((const char*)buff_to_invoke.data(), buff_to_invoke.size());
544 buff_to_invoke = epee::span<const uint8_t>((const uint8_t*)NULL, 0);
545 m_invoke_result_code = m_current_head.m_return_code;
547 m_invoke_buf_ready = true;
548 }
549 }
550 }else
551 {
552 if(m_current_head.m_have_to_return_data)
553 {
554 levin::message_writer return_message{32 * 1024};
555 const uint32_t return_code = m_config.m_pcommands_handler->invoke(
556 m_current_head.m_command, buff_to_invoke, return_message.buffer, m_connection_context
557 );
558
559 // peer_id remains unset if dropped
560 if (m_current_head.m_command == m_connection_context.handshake_command() && m_connection_context.handshake_complete())
561 m_max_packet_size = m_config.m_max_packet_size;
562
563 if(!send_message(return_message.finalize_response(m_current_head.m_command, return_code)))
564 return false;
565 }
566 else
567 {
568 const int notify_result = m_config.m_pcommands_handler->notify(
569 m_current_head.m_command, buff_to_invoke, m_connection_context
570 );
571 if(notify_result < 0)
572 return false;
573 }
574 }
575 // reuse small buffer
576 if (!temp.empty() && temp.capacity() <= 64 * 1024)
577 {
578 temp.clear();
579 m_fragment_buffer = std::move(temp);
580 }
581 }
582 break;
584 {
585 if(m_cache_in_buffer.size() < sizeof(bucket_head2))
586 {
587 if(m_cache_in_buffer.size() >= sizeof(uint64_t))
588 {
589 std::uint64_t levin_sig;
590 memcpy(&levin_sig, m_cache_in_buffer.span(sizeof(std::uint64_t)).data(), sizeof(std::uint64_t));
591 if (SWAP64LE(LEVIN_SIGNATURE) != levin_sig)
592 {
593 MWARNING(m_connection_context << "Signature mismatch, connection will be closed");
594 return false;
595 }
596 }
597 is_continue = false;
598 break;
599 }
600
601 memcpy(&m_current_head, m_cache_in_buffer.span(sizeof(bucket_head2)).data(), sizeof(bucket_head2));
602#if BYTE_ORDER != LITTLE_ENDIAN
603 m_current_head.m_signature = SWAP64LE(m_current_head.m_signature);
605 m_current_head.m_command = SWAP32LE(m_current_head.m_command);
606 m_current_head.m_return_code = SWAP32LE(m_current_head.m_return_code);
607 m_current_head.m_flags = SWAP32LE(m_current_head.m_flags);
608 m_current_head.m_protocol_version = SWAP32LE(m_current_head.m_protocol_version);
609#endif
610 if(LEVIN_SIGNATURE != m_current_head.m_signature)
611 {
612 LOG_ERROR_CC(m_connection_context, "Signature mismatch, connection will be closed");
613 return false;
614 }
615
616 m_cache_in_buffer.erase(sizeof(bucket_head2));
618 m_oponent_protocol_ver = m_current_head.m_protocol_version;
619 const size_t max_bytes = m_connection_context.get_max_bytes(m_current_head.m_command);
620 if(m_current_head.m_cb > std::min<size_t>(max_packet_size, max_bytes))
621 {
622 LOG_ERROR_CC(m_connection_context, "Maximum packet size exceed!, m_max_packet_size = " << std::min<size_t>(max_packet_size, max_bytes)
623 << ", packet header received " << m_current_head.m_cb << ", command " << m_current_head.m_command
624 << ", connection will be closed.");
625 return false;
626 }
627 }
628 break;
629 default:
630 LOG_ERROR_CC(m_connection_context, "Undefined state in levin_server_impl::connection_handler, m_state=" << m_state);
631 return false;
632 }
633 }
634
635 return true;
636 }
637
639 {
641 {
643 m_config.add_connection(this);
644 }
645 return true;
646 }
647
648 template<class callback_t>
649 bool async_invoke(int command, message_writer in_msg, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
650 {
653
655 timeout = m_config.m_invoke_timeout;
656
657 int err_code = LEVIN_OK;
658 do
659 {
661
662 m_invoke_buf_ready = false;
664
665 if (command == m_connection_context.handshake_command())
666 m_max_packet_size = m_config.m_max_packet_size;
667
668 if(!send_message(in_msg.finalize_invoke(command)))
669 {
670 LOG_ERROR_CC(m_connection_context, "Failed to do_send");
671 err_code = LEVIN_ERROR_CONNECTION;
672 break;
673 }
674
675 if(!add_invoke_response_handler(cb, timeout, *this, command))
676 {
678 break;
679 }
681 } while (false);
682
683 if (LEVIN_OK != err_code)
684 {
685 epee::span<const uint8_t> stub_buff = nullptr;
686 // Never call callback inside critical section, that can cause deadlock
687 cb(err_code, stub_buff, m_connection_context);
688 return false;
689 }
690
691 return true;
692 }
693
694 int invoke(int command, message_writer in_msg, std::string& buff_out)
695 {
698
700
701 m_invoke_buf_ready = false;
702
703 if (command == m_connection_context.handshake_command())
704 m_max_packet_size = m_config.m_max_packet_size;
705
706 if (!send_message(in_msg.finalize_invoke(command)))
707 {
708 LOG_ERROR_CC(m_connection_context, "Failed to send request");
710 }
711
712 uint64_t ticks_start = misc_utils::get_tick_count();
713 size_t prev_size = 0;
714
716 {
717 if(m_cache_in_buffer.size() - prev_size >= MIN_BYTES_WANTED)
718 {
719 prev_size = m_cache_in_buffer.size();
720 ticks_start = misc_utils::get_tick_count();
721 }
722 if(misc_utils::get_tick_count() - ticks_start > m_config.m_invoke_timeout)
723 {
724 MWARNING(m_connection_context << "invoke timeout (" << m_config.m_invoke_timeout << "), closing connection ");
725 close();
727 }
728 if(!m_pservice_endpoint->call_run_once_service_io())
730 }
731
734
736 buff_out.swap(m_local_inv_buff);
737 m_local_inv_buff.clear();
739
741 }
742
749 bool send(byte_slice message)
750 {
753 );
754
755 if (!send_message(std::move(message)))
756 {
757 LOG_ERROR_CC(m_connection_context, "Failed to send message, dropping it");
758 return false;
759 }
760 return true;
761 }
762 //------------------------------------------------------------------------------------------
763 boost::uuids::uuid get_connection_id() {return m_connection_context.m_connection_id;}
764 //------------------------------------------------------------------------------------------
765 t_connection_context& get_context_ref() {return m_connection_context;}
766};
767//------------------------------------------------------------------------------------------
768template<class t_connection_context>
776//------------------------------------------------------------------------------------------
777template<class t_connection_context>
779{
780 std::vector<typename connections_map::mapped_type> connections;
781
782 auto scope_exit_handler = misc_utils::create_scope_leave_handler([&connections]{
783 for (auto &aph: connections)
784 aph->finish_outer_call();
785 });
786
788 for (auto& c: m_connects)
789 {
790 if (c.second->m_connection_context.m_is_income == incoming)
791 if (c.second->start_outer_call())
792 connections.push_back(c.second);
793 }
794
795 // close random connections from the provided set
796 // TODO or better just keep removing random elements (performance)
797 unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
798 shuffle(connections.begin(), connections.end(), std::default_random_engine(seed));
799 for (size_t i = 0; i < connections.size() && i < count; ++i)
800 m_connects.erase(connections[i]->get_connection_id());
801
803
804 for (size_t i = 0; i < connections.size() && i < count; ++i)
805 connections[i]->close(false);
806}
807//------------------------------------------------------------------------------------------
808template<class t_connection_context>
813//------------------------------------------------------------------------------------------
814template<class t_connection_context>
819//------------------------------------------------------------------------------------------
820template<class t_connection_context>
828//------------------------------------------------------------------------------------------
829template<class t_connection_context>
831{
832 auto it = m_connects.find(connection_id);
833 return it == m_connects.end() ? 0 : it->second;
834}
835//------------------------------------------------------------------------------------------
836template<class t_connection_context>
847//------------------------------------------------------------------------------------------
848template<class t_connection_context>
849int async_protocol_handler_config<t_connection_context>::invoke(int command, message_writer in_msg, std::string& buff_out, boost::uuids::uuid connection_id)
850{
852 int r = find_and_lock_connection(connection_id, aph);
853 return LEVIN_OK == r ? aph->invoke(command, std::move(in_msg), buff_out) : r;
854}
855//------------------------------------------------------------------------------------------
856template<class t_connection_context> template<class callback_t>
857int async_protocol_handler_config<t_connection_context>::invoke_async(int command, message_writer in_msg, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout)
858{
860 int r = find_and_lock_connection(connection_id, aph);
861 return LEVIN_OK == r ? aph->async_invoke(command, std::move(in_msg), cb, timeout) : r;
862}
863//------------------------------------------------------------------------------------------
864template<class t_connection_context> template<class callback_t>
866{
867 std::vector<typename connections_map::mapped_type> conn;
868
869 auto scope_exit_handler = misc_utils::create_scope_leave_handler([&conn]{
870 for (auto &aph: conn)
871 aph->finish_outer_call();
872 });
873
875 conn.reserve(m_connects.size());
876 for (auto &e: m_connects)
877 if (e.second->start_outer_call())
878 conn.push_back(e.second);
880
881 for (auto &aph: conn)
882 if (!cb(aph->get_context_ref()))
883 return false;
884
885 return true;
886}
887//------------------------------------------------------------------------------------------
888template<class t_connection_context> template<class callback_t>
889bool async_protocol_handler_config<t_connection_context>::for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb)
890{
892 if (find_and_lock_connection(connection_id, aph) != LEVIN_OK)
893 return false;
894 auto scope_exit_handler = misc_utils::create_scope_leave_handler(
896 if(!cb(aph->get_context_ref()))
897 return false;
898 return true;
899}
900//------------------------------------------------------------------------------------------
901template<class t_connection_context>
907//------------------------------------------------------------------------------------------
908template<class t_connection_context>
910{
912 size_t count = 0;
913 for (const auto &c: m_connects)
914 if (!c.second->m_connection_context.m_is_income)
915 ++count;
916 return count;
917}
918//------------------------------------------------------------------------------------------
919template<class t_connection_context>
921{
923 size_t count = 0;
924 for (const auto &c: m_connects)
925 if (c.second->m_connection_context.m_is_income)
926 ++count;
927 return count;
928}
929//------------------------------------------------------------------------------------------
930template<class t_connection_context>
938//------------------------------------------------------------------------------------------
939template<class t_connection_context>
940bool async_protocol_handler_config<t_connection_context>::send(byte_slice message, const boost::uuids::uuid& connection_id)
941{
943 int r = find_and_lock_connection(connection_id, aph);
944 return LEVIN_OK == r ? aph->send(std::move(message)) : false;
945}
946//------------------------------------------------------------------------------------------
947template<class t_connection_context>
948bool async_protocol_handler_config<t_connection_context>::close(boost::uuids::uuid connection_id, const bool wait_for_shutdown)
949{
951 if (find_and_lock_connection(connection_id, aph) != LEVIN_OK)
952 return false;
953 auto scope_exit_handler = misc_utils::create_scope_leave_handler(
955 if (!aph->close(wait_for_shutdown))
956 return false;
958 m_connects.erase(connection_id);
959 return true;
960}
961//------------------------------------------------------------------------------------------
962template<class t_connection_context>
964{
967 if(0 == aph)
968 return false;
969 aph->update_connection_context(contxt);
970 return true;
971}
972//------------------------------------------------------------------------------------------
973template<class t_connection_context>
975{
977 int r = find_and_lock_connection(connection_id, aph);
978 if(LEVIN_OK == r)
979 {
980 aph->request_callback();
981 return true;
982 }
983 else
984 {
985 return false;
986 }
987}
988}
989}
Definition byte_slice.h:69
Definition syncobj.h:125
Definition syncobj.h:82
Definition levin_protocol_handler_async.h:81
async_protocol_handler_config()
Definition levin_protocol_handler_async.h:122
bool request_callback(boost::uuids::uuid connection_id)
Definition levin_protocol_handler_async.h:974
size_t get_connections_count()
Definition levin_protocol_handler_async.h:902
bool send(epee::byte_slice message, const boost::uuids::uuid &connection_id)
Definition levin_protocol_handler_async.h:940
bool close(boost::uuids::uuid connection_id, const bool wait_for_shutdown)
Definition levin_protocol_handler_async.h:948
virtual ~async_protocol_handler_config()
Definition levin_protocol_handler_async.h:124
int find_and_lock_connection(boost::uuids::uuid connection_id, async_protocol_handler< detail::p2p_context > *&aph)
async_protocol_handler< t_connection_context > * find_connection(boost::uuids::uuid connection_id) const
Definition levin_protocol_handler_async.h:830
void(*) m_pcommands_handler_destroy(levin_commands_handler< detail::p2p_context > *)
Definition levin_protocol_handler_async.h:95
bool for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb)
Definition levin_protocol_handler_async.h:889
bool foreach_connection(const callback_t &cb)
Definition levin_protocol_handler_async.h:865
levin_commands_handler< detail::p2p_context > * m_pcommands_handler
Definition levin_protocol_handler_async.h:94
boost::unordered_map< boost::uuids::uuid, async_protocol_handler< t_connection_context > * > connections_map
Definition levin_protocol_handler_async.h:82
uint64_t m_max_packet_size
Definition levin_protocol_handler_async.h:102
t_connection_context connection_context
Definition levin_protocol_handler_async.h:100
void delete_connections(size_t count, bool incoming)
Definition levin_protocol_handler_async.h:778
void del_out_connections(size_t count)
Definition levin_protocol_handler_async.h:809
void set_handler(levin_commands_handler< t_connection_context > *handler, void(*destroy)(levin_commands_handler< t_connection_context > *)=NULL)
Definition levin_protocol_handler_async.h:931
uint64_t m_invoke_timeout
Definition levin_protocol_handler_async.h:103
bool update_connection_context(const t_connection_context &contxt)
Definition levin_protocol_handler_async.h:963
critical_section m_connects_lock
Definition levin_protocol_handler_async.h:83
void add_connection(async_protocol_handler< t_connection_context > *pc)
Definition levin_protocol_handler_async.h:821
size_t get_out_connections_count()
Definition levin_protocol_handler_async.h:909
void del_in_connections(size_t count)
Definition levin_protocol_handler_async.h:815
int invoke(int command, message_writer in_msg, std::string &buff_out, boost::uuids::uuid connection_id)
Definition levin_protocol_handler_async.h:849
int invoke_async(int command, message_writer in_msg, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout=LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
Definition levin_protocol_handler_async.h:857
void del_connection(async_protocol_handler< t_connection_context > *pc)
Definition levin_protocol_handler_async.h:769
connections_map m_connects
Definition levin_protocol_handler_async.h:84
size_t get_in_connections_count()
Definition levin_protocol_handler_async.h:920
uint64_t m_initial_max_packet_size
Definition levin_protocol_handler_async.h:101
Definition levin_protocol_handler_async.h:135
std::string m_local_inv_buff
Definition levin_protocol_handler_async.h:173
bool send_message(byte_slice message)
Definition levin_protocol_handler_async.h:138
void handle_qued_callback()
Definition levin_protocol_handler_async.h:405
std::atomic< uint32_t > m_wait_count
Definition levin_protocol_handler_async.h:177
bool close(const bool wait_for_shutdown)
Definition levin_protocol_handler_async.h:384
critical_section m_call_lock
Definition levin_protocol_handler_async.h:175
std::string m_fragment_buffer
Definition levin_protocol_handler_async.h:136
int32_t m_oponent_protocol_ver
Definition levin_protocol_handler_async.h:188
bool after_init_connection()
Definition levin_protocol_handler_async.h:638
bool async_invoke(int command, message_writer in_msg, const callback_t &cb, size_t timeout=LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
Definition levin_protocol_handler_async.h:649
bool release_protocol()
Definition levin_protocol_handler_async.h:367
bool add_invoke_response_handler(const callback_t &cb, uint64_t timeout, async_protocol_handler &con, int command)
Definition levin_protocol_handler_async.h:293
std::atomic< uint64_t > m_max_packet_size
Definition levin_protocol_handler_async.h:183
bool send(byte_slice message)
Definition levin_protocol_handler_async.h:749
net_utils::i_service_endpoint * m_pservice_endpoint
Definition levin_protocol_handler_async.h:180
critical_section m_invoke_response_handlers_lock
Definition levin_protocol_handler_async.h:289
void update_connection_context(const connection_context &contxt)
Definition levin_protocol_handler_async.h:392
virtual bool handle_recv(const void *ptr, size_t cb)
Definition levin_protocol_handler_async.h:410
t_connection_context connection_context
Definition levin_protocol_handler_async.h:158
void request_callback()
Definition levin_protocol_handler_async.h:397
critical_section m_local_inv_buff_lock
Definition levin_protocol_handler_async.h:172
virtual ~async_protocol_handler()
Definition levin_protocol_handler_async.h:326
t_connection_context & get_context_ref()
Definition levin_protocol_handler_async.h:765
std::atomic< bool > m_invoke_buf_ready
Definition levin_protocol_handler_async.h:168
std::list< boost::shared_ptr< invoke_response_handler_base > > m_invoke_response_handlers
Definition levin_protocol_handler_async.h:290
bool m_connection_initialized
Definition levin_protocol_handler_async.h:189
stream_state m_state
Definition levin_protocol_handler_async.h:186
stream_state
Definition levin_protocol_handler_async.h:162
@ stream_state_body
Definition levin_protocol_handler_async.h:164
@ stream_state_head
Definition levin_protocol_handler_async.h:163
bool start_outer_call()
Definition levin_protocol_handler_async.h:348
test_connection_context & m_connection_context
Definition levin_protocol_handler_async.h:182
config_type & m_config
Definition levin_protocol_handler_async.h:181
boost::uuids::uuid get_connection_id()
Definition levin_protocol_handler_async.h:763
volatile int m_invoke_result_code
Definition levin_protocol_handler_async.h:170
async_protocol_handler_config< t_connection_context > config_type
Definition levin_protocol_handler_async.h:159
bucket_head2 m_current_head
Definition levin_protocol_handler_async.h:179
async_protocol_handler(net_utils::i_service_endpoint *psnd_hndlr, config_type &config, t_connection_context &conn_context)
Definition levin_protocol_handler_async.h:307
net_utils::buffer m_cache_in_buffer
Definition levin_protocol_handler_async.h:185
std::atomic< bool > m_protocol_released
Definition levin_protocol_handler_async.h:167
bool finish_outer_call()
Definition levin_protocol_handler_async.h:359
int invoke(int command, message_writer in_msg, std::string &buff_out)
Definition levin_protocol_handler_async.h:694
std::atomic< uint32_t > m_close_called
Definition levin_protocol_handler_async.h:178
Provides space for levin (p2p) header, so that payload can be sent without copy.
Definition levin_base.h:132
byte_slice finalize_invoke(uint32_t command)
Definition levin_base.h:151
byte_slice finalize_response(uint32_t command, uint32_t return_code)
Definition levin_base.h:153
byte_stream buffer
Has space for levin header until a finalize method is used.
Definition levin_base.h:159
bucket_head2 header
Definition levin_base.h:135
Definition buffer.h:47
Non-owning sequence of data. Does not deep copy.
Definition span.h:55
constexpr std::size_t size() const noexcept
Definition span.h:109
constexpr pointer data() const noexcept
Definition span.h:108
const uint8_t seed[32]
Definition code-generator.cpp:37
std::unique_ptr< test_connection > conn(new test_connection(io_service, m_handler_config))
void * memcpy(void *a, const void *b, size_t c)
Definition glibc_compat.cpp:16
#define false
#define SWAP64LE
Definition int-util.h:285
#define SWAP32LE
Definition int-util.h:277
#define LEVIN_PACKET_RESPONSE
Definition levin_base.h:80
#define LEVIN_PROTOCOL_VER_1
Definition levin_base.h:86
#define LEVIN_ERROR_CONNECTION
Definition levin_base.h:103
#define LEVIN_INITIAL_MAX_PACKET_SIZE
Definition levin_base.h:76
#define LEVIN_PACKET_END
Definition levin_base.h:82
#define LEVIN_PACKET_REQUEST
Definition levin_base.h:79
#define LEVIN_DEFAULT_MAX_PACKET_SIZE
Definition levin_base.h:77
#define LEVIN_OK
Definition levin_base.h:102
#define LEVIN_ERROR_CONNECTION_DESTROYED
Definition levin_base.h:105
#define LEVIN_PACKET_BEGIN
Definition levin_base.h:81
#define LEVIN_ERROR_CONNECTION_NOT_FOUND
Definition levin_base.h:104
#define LEVIN_SIGNATURE
Definition levin_base.h:38
#define LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED
Definition levin_base.h:75
#define LEVIN_ERROR_CONNECTION_TIMEDOUT
Definition levin_base.h:106
#define MIN_BYTES_WANTED
Definition levin_protocol_handler_async.h:50
void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, const char *category)
Definition levin_protocol_handler_async.h:54
Definition cryptonote_config.h:221
Definition levin_base.h:44
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
Definition misc_language.h:80
uint64_t get_tick_count()
Definition time_helper.h:82
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
TODO: (mj-xmr) This will be reduced in an another PR.
Definition byte_slice.h:40
#define LOG_ERROR_CC(ct, message)
Definition net_utils_base.h:473
unsigned int uint32_t
Definition stdint.h:126
signed int int32_t
Definition stdint.h:123
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
bool m_timer_started
Definition levin_protocol_handler_async.h:228
async_protocol_handler & m_con
Definition levin_protocol_handler_async.h:226
callback_t m_cb
Definition levin_protocol_handler_async.h:225
uint64_t m_timeout
Definition levin_protocol_handler_async.h:231
virtual bool handle(int res, const epee::span< const uint8_t > buff, typename async_protocol_handler::connection_context &context)
Definition levin_protocol_handler_async.h:233
virtual void cancel()
Definition levin_protocol_handler_async.h:245
boost::asio::deadline_timer m_timer
Definition levin_protocol_handler_async.h:227
virtual ~anvoke_handler()
Definition levin_protocol_handler_async.h:223
anvoke_handler(const callback_t &cb, uint64_t timeout, async_protocol_handler &con, int command)
Definition levin_protocol_handler_async.h:202
virtual bool is_timer_started() const
Definition levin_protocol_handler_async.h:241
int m_command
Definition levin_protocol_handler_async.h:232
virtual bool cancel_timer()
Definition levin_protocol_handler_async.h:254
bool m_timer_cancelled
Definition levin_protocol_handler_async.h:230
bool m_cancel_timer_called
Definition levin_protocol_handler_async.h:229
virtual void reset_timer()
Definition levin_protocol_handler_async.h:264
Definition levin_protocol_handler_async.h:192
virtual bool handle(int res, const epee::span< const uint8_t > buff, connection_context &context)=0
Definition levin_base.h:63
uint32_t m_command
Definition levin_base.h:67
uint32_t m_protocol_version
Definition levin_base.h:70
uint32_t m_flags
Definition levin_base.h:69
uint64_t m_cb
Definition levin_base.h:65
uint8_t m_have_to_return_data
Definition levin_base.h:66
Definition levin_base.h:91
Definition net_utils_base.h:446
virtual bool do_send(byte_slice message)=0
#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