Electroneum
net_helper.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 
28 
29 
30 #pragma once
31 
32 //#include <Winsock2.h>
33 //#include <Ws2tcpip.h>
34 #include <string>
35 #include <boost/version.hpp>
36 #include <boost/asio/io_service.hpp>
37 #include <boost/asio/ip/tcp.hpp>
38 #include <boost/asio/read.hpp>
39 #include <boost/asio/ssl.hpp>
40 #include <boost/asio/steady_timer.hpp>
41 #include <boost/thread/future.hpp>
42 #include <boost/lambda/bind.hpp>
43 #include <boost/lambda/lambda.hpp>
44 #include <boost/interprocess/detail/atomic.hpp>
45 #include <boost/system/error_code.hpp>
46 #include <functional>
47 #include "net/net_utils_base.h"
48 #include "net/net_ssl.h"
49 #include "misc_language.h"
50 
51 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
52 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "net"
53 
54 #ifndef MAKE_IP
55 #define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
56 #endif
57 
58 
59 namespace epee
60 {
61 namespace net_utils
62 {
64  {
65  boost::unique_future<boost::asio::ip::tcp::socket>
66  operator()(const std::string& addr, const std::string& port, boost::asio::steady_timer&) const;
67  };
68 
69 
71  {
72  enum try_connect_result_t
73  {
74  CONNECT_SUCCESS,
75  CONNECT_FAILURE,
76  CONNECT_NO_SSL,
77  };
78 
79 
80 
81  struct handler_obj
82  {
83  handler_obj(boost::system::error_code& error, size_t& bytes_transferred):ref_error(error), ref_bytes_transferred(bytes_transferred)
84  {}
85  handler_obj(const handler_obj& other_obj):ref_error(other_obj.ref_error), ref_bytes_transferred(other_obj.ref_bytes_transferred)
86  {}
87 
88  boost::system::error_code& ref_error;
89  size_t& ref_bytes_transferred;
90 
91  void operator()(const boost::system::error_code& error, // Result of operation.
92  std::size_t bytes_transferred // Number of bytes read.
93  )
94  {
95  ref_error = error;
96  ref_bytes_transferred = bytes_transferred;
97  }
98  };
99 
100  public:
101  inline
103  m_io_service(),
104  m_ctx(boost::asio::ssl::context::tlsv12),
106  m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx)),
108  m_initialized(true),
109  m_connected(false),
111  m_shutdowned(0),
112  m_bytes_sent(0),
114  {
115  }
116 
131  using connect_func = boost::unique_future<boost::asio::ip::tcp::socket>(const std::string&, const std::string&, boost::asio::steady_timer&);
132 
133  inline
135  {
136  //profile_tools::local_coast lc("~blocked_mode_client()", 3);
137  try { shutdown(); }
138  catch(...) { /* ignore */ }
139  }
140 
141  inline void set_ssl(ssl_options_t ssl_options)
142  {
143  if (ssl_options)
144  m_ctx = ssl_options.create_context();
145  else
146  m_ctx = boost::asio::ssl::context(boost::asio::ssl::context::tlsv12);
147  m_ssl_options = std::move(ssl_options);
148  }
149 
150  inline
151  bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout)
152  {
153  return connect(addr, std::to_string(port), timeout);
154  }
155 
156  inline
157  try_connect_result_t try_connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, epee::net_utils::ssl_support_t ssl_support)
158  {
159  m_deadline.expires_from_now(timeout);
160  boost::unique_future<boost::asio::ip::tcp::socket> connection = m_connector(addr, port, m_deadline);
161  for (;;)
162  {
163  m_io_service.reset();
164  m_io_service.run_one();
165 
166  if (connection.is_ready())
167  break;
168  }
169 
170  m_ssl_socket->next_layer() = connection.get();
171  m_deadline.cancel();
172  if (m_ssl_socket->next_layer().is_open())
173  {
174  m_connected = true;
175  m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
176  // SSL Options
178  {
179  if (!m_ssl_options.handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, addr))
180  {
182  {
183  boost::system::error_code ignored_ec;
184  m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
185  m_ssl_socket->next_layer().close();
186  m_connected = false;
187  return CONNECT_NO_SSL;
188  }
189  else
190  {
191  MWARNING("Failed to establish SSL connection");
192  m_connected = false;
193  return CONNECT_FAILURE;
194  }
195  }
196  }
197  return CONNECT_SUCCESS;
198  }else
199  {
200  MWARNING("Some problems at connect, expected open socket");
201  return CONNECT_FAILURE;
202  }
203 
204  }
205 
206  inline
207  bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout)
208  {
209  m_connected = false;
210  try
211  {
212  m_ssl_socket->next_layer().close();
213 
214  // Set SSL options
215  // disable sslv2
216  m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx));
217 
218  // Get a list of endpoints corresponding to the server name.
219 
220  try_connect_result_t try_connect_result = try_connect(addr, port, timeout, m_ssl_options.support);
221  if (try_connect_result == CONNECT_FAILURE)
222  return false;
224  {
225  if (try_connect_result == CONNECT_NO_SSL)
226  {
227  MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
229  if (try_connect(addr, port, timeout, m_ssl_options.support) != CONNECT_SUCCESS)
230  return false;
231  }
232  }
233  }
234  catch(const boost::system::system_error& er)
235  {
236  MDEBUG("Some problems at connect, message: " << er.what());
237  return false;
238  }
239  catch(...)
240  {
241  MDEBUG("Some fatal problems.");
242  return false;
243  }
244 
245  return true;
246  }
248  void set_connector(std::function<connect_func> connector)
249  {
250  m_connector = std::move(connector);
251  }
252 
253  inline
254  bool disconnect()
255  {
256  try
257  {
258  if(m_connected)
259  {
260  m_connected = false;
261  if(m_ssl_options)
262  shutdown_ssl();
263  m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
264  }
265  }
266  catch(const boost::system::system_error& /*er*/)
267  {
268  //LOG_ERROR("Some problems at disconnect, message: " << er.what());
269  return false;
270  }
271  catch(...)
272  {
273  //LOG_ERROR("Some fatal problems.");
274  return false;
275  }
276  return true;
277  }
278 
279 
280  inline
281  bool send(const std::string& buff, std::chrono::milliseconds timeout)
282  {
283 
284  try
285  {
286  m_deadline.expires_from_now(timeout);
287 
288  // Set up the variable that receives the result of the asynchronous
289  // operation. The error code is set to would_block to signal that the
290  // operation is incomplete. Asio guarantees that its asynchronous
291  // operations will never fail with would_block, so any other value in
292  // ec indicates completion.
293  boost::system::error_code ec = boost::asio::error::would_block;
294 
295  // Start the asynchronous operation itself. The boost::lambda function
296  // object is used as a callback and will update the ec variable when the
297  // operation completes. The blocking_udp_client.cpp example shows how you
298  // can use boost::bind rather than boost::lambda.
299  async_write(buff.c_str(), buff.size(), ec);
300 
301  // Block until the asynchronous operation has completed.
302  while (ec == boost::asio::error::would_block)
303  {
304  m_io_service.reset();
305  m_io_service.run_one();
306  }
307 
308  if (ec)
309  {
310  LOG_PRINT_L3("Problems at write: " << ec.message());
311  m_connected = false;
312  return false;
313  }else
314  {
315  m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
316  m_bytes_sent += buff.size();
317  }
318  }
319 
320  catch(const boost::system::system_error& er)
321  {
322  LOG_ERROR("Some problems at connect, message: " << er.what());
323  return false;
324  }
325  catch(...)
326  {
327  LOG_ERROR("Some fatal problems.");
328  return false;
329  }
330 
331  return true;
332  }
333 
334  inline
335  bool send(const void* data, size_t sz)
336  {
337  try
338  {
339  /*
340  m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
341 
342  // Set up the variable that receives the result of the asynchronous
343  // operation. The error code is set to would_block to signal that the
344  // operation is incomplete. Asio guarantees that its asynchronous
345  // operations will never fail with would_block, so any other value in
346  // ec indicates completion.
347  boost::system::error_code ec = boost::asio::error::would_block;
348 
349  // Start the asynchronous operation itself. The boost::lambda function
350  // object is used as a callback and will update the ec variable when the
351  // operation completes. The blocking_udp_client.cpp example shows how you
352  // can use boost::bind rather than boost::lambda.
353  boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
354 
355  // Block until the asynchronous operation has completed.
356  while (ec == boost::asio::error::would_block)
357  {
358  m_io_service.run_one();
359  }
360  */
361  boost::system::error_code ec;
362 
363  size_t writen = write(data, sz, ec);
364 
365  if (!writen || ec)
366  {
367  LOG_PRINT_L3("Problems at write: " << ec.message());
368  m_connected = false;
369  return false;
370  }else
371  {
372  m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
373  m_bytes_sent += sz;
374  }
375  }
376 
377  catch(const boost::system::system_error& er)
378  {
379  LOG_ERROR("Some problems at send, message: " << er.what());
380  m_connected = false;
381  return false;
382  }
383  catch(...)
384  {
385  LOG_ERROR("Some fatal problems.");
386  return false;
387  }
388 
389  return true;
390  }
391 
392  bool is_connected(bool *ssl = NULL)
393  {
394  if (!m_connected || !m_ssl_socket->next_layer().is_open())
395  return false;
396  if (ssl)
398  return true;
399  }
400 
401  inline
402  bool recv(std::string& buff, std::chrono::milliseconds timeout)
403  {
404 
405  try
406  {
407  // Set a deadline for the asynchronous operation. Since this function uses
408  // a composed operation (async_read_until), the deadline applies to the
409  // entire operation, rather than individual reads from the socket.
410  m_deadline.expires_from_now(timeout);
411 
412  // Set up the variable that receives the result of the asynchronous
413  // operation. The error code is set to would_block to signal that the
414  // operation is incomplete. Asio guarantees that its asynchronous
415  // operations will never fail with would_block, so any other value in
416  // ec indicates completion.
417  //boost::system::error_code ec = boost::asio::error::would_block;
418 
419  // Start the asynchronous operation itself. The boost::lambda function
420  // object is used as a callback and will update the ec variable when the
421  // operation completes. The blocking_udp_client.cpp example shows how you
422  // can use boost::bind rather than boost::lambda.
423 
424  boost::system::error_code ec = boost::asio::error::would_block;
425  size_t bytes_transfered = 0;
426 
427  handler_obj hndlr(ec, bytes_transfered);
428 
429  static const size_t max_size = 16384;
430  buff.resize(max_size);
431 
432  async_read(&buff[0], max_size, boost::asio::transfer_at_least(1), hndlr);
433 
434  // Block until the asynchronous operation has completed.
435  while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
436  {
437  m_io_service.reset();
438  m_io_service.run_one();
439  }
440 
441 
442  if (ec)
443  {
444  MTRACE("READ ENDS: Connection err_code " << ec.value());
445  if(ec == boost::asio::error::eof)
446  {
447  MTRACE("Connection err_code eof.");
448  //connection closed there, empty
449  buff.clear();
450  return true;
451  }
452 
453  MDEBUG("Problems at read: " << ec.message());
454  m_connected = false;
455  return false;
456  }else
457  {
458  MTRACE("READ ENDS: Success. bytes_tr: " << bytes_transfered);
459  m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
460  }
461 
462  /*if(!bytes_transfered)
463  return false;*/
464 
465  m_bytes_received += bytes_transfered;
466  buff.resize(bytes_transfered);
467  return true;
468  }
469 
470  catch(const boost::system::system_error& er)
471  {
472  LOG_ERROR("Some problems at read, message: " << er.what());
473  m_connected = false;
474  return false;
475  }
476  catch(...)
477  {
478  LOG_ERROR("Some fatal problems at read.");
479  return false;
480  }
481 
482 
483 
484  return false;
485 
486  }
487 
488  inline bool recv_n(std::string& buff, int64_t sz, std::chrono::milliseconds timeout)
489  {
490 
491  try
492  {
493  // Set a deadline for the asynchronous operation. Since this function uses
494  // a composed operation (async_read_until), the deadline applies to the
495  // entire operation, rather than individual reads from the socket.
496  m_deadline.expires_from_now(timeout);
497 
498  // Set up the variable that receives the result of the asynchronous
499  // operation. The error code is set to would_block to signal that the
500  // operation is incomplete. Asio guarantees that its asynchronous
501  // operations will never fail with would_block, so any other value in
502  // ec indicates completion.
503  //boost::system::error_code ec = boost::asio::error::would_block;
504 
505  // Start the asynchronous operation itself. The boost::lambda function
506  // object is used as a callback and will update the ec variable when the
507  // operation completes. The blocking_udp_client.cpp example shows how you
508  // can use boost::bind rather than boost::lambda.
509 
510  buff.resize(static_cast<size_t>(sz));
511  boost::system::error_code ec = boost::asio::error::would_block;
512  size_t bytes_transfered = 0;
513 
514 
515  handler_obj hndlr(ec, bytes_transfered);
516  async_read((char*)buff.data(), buff.size(), boost::asio::transfer_at_least(buff.size()), hndlr);
517 
518  // Block until the asynchronous operation has completed.
519  while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
520  {
521  m_io_service.run_one();
522  }
523 
524  if (ec)
525  {
526  LOG_PRINT_L3("Problems at read: " << ec.message());
527  m_connected = false;
528  return false;
529  }else
530  {
531  m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
532  }
533 
534  m_bytes_received += bytes_transfered;
535  if(bytes_transfered != buff.size())
536  {
537  LOG_ERROR("Transferred mismatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size());
538  return false;
539  }
540 
541  return true;
542  }
543 
544  catch(const boost::system::system_error& er)
545  {
546  LOG_ERROR("Some problems at read, message: " << er.what());
547  m_connected = false;
548  return false;
549  }
550  catch(...)
551  {
552  LOG_ERROR("Some fatal problems at read.");
553  return false;
554  }
555 
556 
557 
558  return false;
559  }
560 
561  bool shutdown()
562  {
563  m_deadline.cancel();
564  boost::system::error_code ec;
566  shutdown_ssl();
567  m_ssl_socket->next_layer().cancel(ec);
568  if(ec)
569  MDEBUG("Problems at cancel: " << ec.message());
570  m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
571  if(ec)
572  MDEBUG("Problems at shutdown: " << ec.message());
573  m_ssl_socket->next_layer().close(ec);
574  if(ec)
575  MDEBUG("Problems at close: " << ec.message());
576  boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1);
577  m_connected = false;
578  return true;
579  }
580 
581  boost::asio::io_service& get_io_service()
582  {
583  return m_io_service;
584  }
585 
587  {
588  return m_ssl_socket->next_layer();
589  }
590 
592  {
593  return m_bytes_sent;
594  }
595 
597  {
598  return m_bytes_received;
599  }
600 
601  private:
602 
603  void check_deadline()
604  {
605  // Check whether the deadline has passed. We compare the deadline against
606  // the current time since a new asynchronous operation may have moved the
607  // deadline before this actor had a chance to run.
608  if (m_deadline.expires_at() <= std::chrono::steady_clock::now())
609  {
610  // The deadline has passed. The socket is closed so that any outstanding
611  // asynchronous operations are cancelled. This allows the blocked
612  // connect(), read_line() or write_line() functions to return.
613  LOG_PRINT_L3("Timed out socket");
614  m_connected = false;
615  m_ssl_socket->next_layer().close();
616 
617  // There is no longer an active deadline. The expiry is set to positive
618  // infinity so that the actor takes no action until a new deadline is set.
619  m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
620  }
621 
622  // Put the actor back to sleep.
623  m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this));
624  }
625 
626  void shutdown_ssl() {
627  // ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
628  boost::system::error_code ec = boost::asio::error::would_block;
629  m_deadline.expires_from_now(std::chrono::milliseconds(2000));
630  m_ssl_socket->async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
631  while (ec == boost::asio::error::would_block)
632  {
633  m_io_service.reset();
634  m_io_service.run_one();
635  }
636  // Ignore "short read" error
637  if (ec.category() == boost::asio::error::get_ssl_category() &&
638  ec.value() !=
639 #if BOOST_VERSION >= 106200
640  boost::asio::ssl::error::stream_truncated
641 #else // older Boost supports only OpenSSL 1.0, so 1.0-only macros are appropriate
642  ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)
643 #endif
644  )
645  MDEBUG("Problems at ssl shutdown: " << ec.message());
646  }
647 
648  protected:
649  bool write(const void* data, size_t sz, boost::system::error_code& ec)
650  {
651  bool success;
653  success = boost::asio::write(*m_ssl_socket, boost::asio::buffer(data, sz), ec);
654  else
655  success = boost::asio::write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), ec);
656  return success;
657  }
658 
659  void async_write(const void* data, size_t sz, boost::system::error_code& ec)
660  {
662  boost::asio::async_write(*m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
663  else
664  boost::asio::async_write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
665  }
666 
667  void async_read(char* buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj& hndlr)
668  {
670  boost::asio::async_read(m_ssl_socket->next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
671  else
672  boost::asio::async_read(*m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
673 
674  }
675 
676  protected:
677  boost::asio::io_service m_io_service;
679  std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
680  std::function<connect_func> m_connector;
684  boost::asio::steady_timer m_deadline;
686  std::atomic<uint64_t> m_bytes_sent;
687  std::atomic<uint64_t> m_bytes_received;
688  };
689 
690 
691  /************************************************************************/
692  /* */
693  /************************************************************************/
695  {
696  public:
698  {
699 
700  // No deadline is required until the first socket operation is started. We
701  // set the deadline to positive infinity so that the actor takes no action
702  // until a specific deadline is set.
703  m_send_deadline.expires_at(boost::posix_time::pos_infin);
704 
705  // Start the persistent actor that checks for deadline expiry.
706  check_send_deadline();
707  }
709  {
710  m_send_deadline.cancel();
711  }
712 
713  bool shutdown()
714  {
716  m_send_deadline.cancel();
717  return true;
718  }
719 
720  inline
721  bool send(const void* data, size_t sz)
722  {
723  try
724  {
725  /*
726  m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
727 
728  // Set up the variable that receives the result of the asynchronous
729  // operation. The error code is set to would_block to signal that the
730  // operation is incomplete. Asio guarantees that its asynchronous
731  // operations will never fail with would_block, so any other value in
732  // ec indicates completion.
733  boost::system::error_code ec = boost::asio::error::would_block;
734 
735  // Start the asynchronous operation itself. The boost::lambda function
736  // object is used as a callback and will update the ec variable when the
737  // operation completes. The blocking_udp_client.cpp example shows how you
738  // can use boost::bind rather than boost::lambda.
739  boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
740 
741  // Block until the asynchronous operation has completed.
742  while(ec == boost::asio::error::would_block)
743  {
744  m_io_service.run_one();
745  }*/
746 
747  boost::system::error_code ec;
748 
749  size_t writen = write(data, sz, ec);
750 
751  if (!writen || ec)
752  {
753  LOG_PRINT_L3("Problems at write: " << ec.message());
754  return false;
755  }else
756  {
757  m_send_deadline.expires_at(boost::posix_time::pos_infin);
758  }
759  }
760 
761  catch(const boost::system::system_error& er)
762  {
763  LOG_ERROR("Some problems at connect, message: " << er.what());
764  return false;
765  }
766  catch(...)
767  {
768  LOG_ERROR("Some fatal problems.");
769  return false;
770  }
771 
772  return true;
773  }
774 
775 
776  private:
777 
778  boost::asio::deadline_timer m_send_deadline;
779 
780  void check_send_deadline()
781  {
782  // Check whether the deadline has passed. We compare the deadline against
783  // the current time since a new asynchronous operation may have moved the
784  // deadline before this actor had a chance to run.
785  if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
786  {
787  // The deadline has passed. The socket is closed so that any outstanding
788  // asynchronous operations are cancelled. This allows the blocked
789  // connect(), read_line() or write_line() functions to return.
790  LOG_PRINT_L3("Timed out socket");
791  m_ssl_socket->next_layer().close();
792 
793  // There is no longer an active deadline. The expiry is set to positive
794  // infinity so that the actor takes no action until a new deadline is set.
795  m_send_deadline.expires_at(boost::posix_time::pos_infin);
796  }
797 
798  // Put the actor back to sleep.
799  m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this));
800  }
801  };
802 }
803 }
804 
void async_write(const void *data, size_t sz, boost::system::error_code &ec)
Definition: net_helper.h:659
void set_connector(std::function< connect_func > connector)
Change the connection routine (proxy, etc.)
Definition: net_helper.h:248
#define MERROR(x)
Definition: misc_log_ex.h:73
boost::asio::ssl::context m_ctx
Definition: net_helper.h:678
void set_ssl(ssl_options_t ssl_options)
Definition: net_helper.h:141
#define MTRACE(x)
Definition: misc_log_ex.h:77
std::shared_ptr< boost::asio::ssl::stream< boost::asio::ip::tcp::socket > > m_ssl_socket
Definition: net_helper.h:679
::std::string string
Definition: gtest-port.h:1097
bool send(const void *data, size_t sz)
Definition: net_helper.h:335
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
Definition: zmq.h:101
bool send(const void *data, size_t sz)
Definition: net_helper.h:721
boost::unique_future< boost::asio::ip::tcp::socket >(const std::string &, const std::string &, boost::asio::steady_timer &) connect_func
Definition: net_helper.h:131
bool is_connected(bool *ssl=NULL)
Definition: net_helper.h:392
bool connect(const std::string &addr, const std::string &port, std::chrono::milliseconds timeout)
Definition: net_helper.h:207
#define MDEBUG(x)
Definition: misc_log_ex.h:76
unsigned int uint32_t
Definition: stdint.h:126
boost::asio::io_service m_io_service
Definition: net_helper.h:677
bool connect(const std::string &addr, int port, std::chrono::milliseconds timeout)
Definition: net_helper.h:151
Represents a single connection from a client.
bool handshake(boost::asio::ssl::stream< boost::asio::ip::tcp::socket > &socket, boost::asio::ssl::stream_base::handshake_type type, const std::string &host={}) const
Definition: net_ssl.cpp:459
unsigned __int64 uint64_t
Definition: stdint.h:136
boost::asio::steady_timer m_deadline
Definition: net_helper.h:684
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
Definition: zmq.h:98
bool write(const void *data, size_t sz, boost::system::error_code &ec)
Definition: net_helper.h:649
#define LOG_PRINT_L3(x)
Definition: misc_log_ex.h:102
#define MWARNING(x)
Definition: misc_log_ex.h:74
try_connect_result_t try_connect(const std::string &addr, const std::string &port, std::chrono::milliseconds timeout, epee::net_utils::ssl_support_t ssl_support)
Definition: net_helper.h:157
boost::endian::big_uint16_t port
Definition: socks.cpp:60
expect< void > success() noexcept
Definition: expect.h:397
const T & move(const T &t)
Definition: gtest-port.h:1317
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
signed __int64 int64_t
Definition: stdint.h:135
std::function< connect_func > m_connector
Definition: net_helper.h:680
bool recv_n(std::string &buff, int64_t sz, std::chrono::milliseconds timeout)
Definition: net_helper.h:488
std::string to_string(t_connection_type type)
boost::asio::io_service & get_io_service()
Definition: net_helper.h:581
boost::asio::ssl::context create_context() const
Definition: net_ssl.cpp:283
void async_read(char *buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj &hndlr)
Definition: net_helper.h:667
error
Tracks LMDB error codes.
Definition: error.h:44
boost::asio::ip::tcp::socket & get_socket()
Definition: net_helper.h:586
std::atomic< uint64_t > m_bytes_received
Definition: net_helper.h:687
boost::unique_future< boost::asio::ip::tcp::socket > operator()(const std::string &addr, const std::string &port, boost::asio::steady_timer &) const
Definition: net_helper.cpp:8
bool send(const std::string &buff, std::chrono::milliseconds timeout)
Definition: net_helper.h:281
bool recv(std::string &buff, std::chrono::milliseconds timeout)
Definition: net_helper.h:402
std::atomic< uint64_t > m_bytes_sent
Definition: net_helper.h:686