BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
websocket.cpp
Go to the documentation of this file.
2 #include <websocketpp/config/asio_client.hpp>
3 #include <websocketpp/config/asio.hpp>
4 #include <websocketpp/server.hpp>
5 #include <websocketpp/config/asio_client.hpp>
6 #include <websocketpp/client.hpp>
7 #include <websocketpp/logger/stub.hpp>
8 
9 #ifdef HAS_ZLIB
10 #include <websocketpp/extensions/permessage_deflate/enabled.hpp>
11 #else
12 #include <websocketpp/extensions/permessage_deflate/disabled.hpp>
13 #endif
14 
15 #include <fc/io/json.hpp>
16 #include <fc/optional.hpp>
17 #include <fc/reflect/variant.hpp>
18 #include <fc/rpc/websocket_api.hpp>
19 #include <fc/variant.hpp>
20 #include <fc/thread/thread.hpp>
21 #include <fc/asio.hpp>
22 
23 #if WIN32
24 #include <wincrypt.h>
25 #endif
26 
27 #ifdef DEFAULT_LOGGER
28 # undef DEFAULT_LOGGER
29 #endif
30 #define DEFAULT_LOGGER "rpc"
31 
32 namespace fc { namespace http {
33 
34  namespace detail {
35 #if WIN32
36  // taken from https://stackoverflow.com/questions/39772878/reliable-way-to-get-root-ca-certificates-on-windows/40710806
37  static void add_windows_root_certs(boost::asio::ssl::context &ctx)
38  {
39  HCERTSTORE hStore = CertOpenSystemStore( 0, "ROOT" );
40  if( hStore == NULL )
41  return;
42 
43  X509_STORE *store = X509_STORE_new();
44  PCCERT_CONTEXT pContext = NULL;
45  while( (pContext = CertEnumCertificatesInStore( hStore, pContext )) != NULL )
46  {
47  X509 *x509 = d2i_X509( NULL, (const unsigned char **)&pContext->pbCertEncoded,
48  pContext->cbCertEncoded);
49  if( x509 != NULL )
50  {
51  X509_STORE_add_cert( store, x509 );
52  X509_free( x509 );
53  }
54  }
55 
56  CertFreeCertificateContext( pContext );
57  CertCloseStore( hStore, 0 );
58 
59  SSL_CTX_set_cert_store( ctx.native_handle(), store );
60  }
61 #endif
62  struct asio_with_stub_log : public websocketpp::config::asio {
63 
65  typedef asio base;
66 
67  typedef base::concurrency_type concurrency_type;
68 
69  typedef base::request_type request_type;
70  typedef base::response_type response_type;
71 
72  typedef base::message_type message_type;
73  typedef base::con_msg_manager_type con_msg_manager_type;
74  typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
75 
76  typedef websocketpp::log::stub elog_type;
77  typedef websocketpp::log::stub alog_type;
78 
79  typedef base::rng_type rng_type;
80 
81  struct transport_config : public base::transport_config {
88  };
89 
90  typedef websocketpp::transport::asio::endpoint<transport_config> transport_type;
91 
92  // permessage_compress extension
94 #ifdef HAS_ZLIB
95  typedef websocketpp::extensions::permessage_deflate::enabled <permessage_deflate_config>
97 #else
98  typedef websocketpp::extensions::permessage_deflate::disabled <permessage_deflate_config>
100 #endif
101  };
102  struct asio_tls_with_stub_log : public websocketpp::config::asio_tls {
103 
105  typedef asio_tls base;
106 
107  typedef base::concurrency_type concurrency_type;
108 
109  typedef base::request_type request_type;
110  typedef base::response_type response_type;
111 
112  typedef base::message_type message_type;
113  typedef base::con_msg_manager_type con_msg_manager_type;
114  typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
115 
116  typedef websocketpp::log::stub elog_type;
117  typedef websocketpp::log::stub alog_type;
118 
119  typedef base::rng_type rng_type;
120 
121  struct transport_config : public base::transport_config {
128  };
129 
130  typedef websocketpp::transport::asio::endpoint<transport_config> transport_type;
131 
132  // permessage_compress extension
134 #ifdef HAS_ZLIB
135  typedef websocketpp::extensions::permessage_deflate::enabled <permessage_deflate_config>
137 #else
138  typedef websocketpp::extensions::permessage_deflate::disabled <permessage_deflate_config>
140 #endif
141  };
142  struct asio_tls_stub_log : public websocketpp::config::asio_tls {
144  typedef asio_tls base;
145 
146  typedef base::concurrency_type concurrency_type;
147 
148  typedef base::request_type request_type;
149  typedef base::response_type response_type;
150 
151  typedef base::message_type message_type;
152  typedef base::con_msg_manager_type con_msg_manager_type;
153  typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
154 
155  typedef websocketpp::log::stub elog_type;
156  typedef websocketpp::log::stub alog_type;
157 
158  typedef base::rng_type rng_type;
159 
160  struct transport_config : public base::transport_config {
167  };
168 
169  typedef websocketpp::transport::asio::endpoint<transport_config> transport_type;
170 
171  // permessage_compress extension
173 #ifdef HAS_ZLIB
174  typedef websocketpp::extensions::permessage_deflate::enabled <permessage_deflate_config>
176 #else
177  typedef websocketpp::extensions::permessage_deflate::disabled <permessage_deflate_config>
179 #endif
180  };
181 
182  template<typename T>
184  {
185  public:
186  websocket_connection_impl( T con ) : _ws_connection(con)
187  {
188  _remote_endpoint = con->get_remote_endpoint();
189  }
190 
192  {
193  }
194 
195  virtual void send_message( const std::string& message )override
196  {
197  ilog( "[OUT] ${remote_endpoint} ${msg}",
198  ("remote_endpoint",_remote_endpoint) ("msg",message) );
199  auto ec = _ws_connection->send( message );
200  FC_ASSERT( !ec, "websocket send failed: ${msg}", ("msg",ec.message() ) );
201  }
202  virtual void close( int64_t code, const std::string& reason )override
203  {
204  _ws_connection->close(code,reason);
205  }
206 
207  virtual std::string get_request_header(const std::string& key)override
208  {
209  return _ws_connection->get_request_header(key);
210  }
211 
213  };
214 
215  template<typename T>
217  {
218  public:
219  possibly_proxied_websocket_connection( T con, const std::string& forward_header_key )
220  : websocket_connection_impl<T>(con)
221  {
222  // By calling the parent's constructor, _remote_endpoint has been initialized.
223  // Now try to extract remote address from the header, if found, overwrite it
224  if( !forward_header_key.empty() )
225  {
226  const std::string value = this->get_request_header( forward_header_key );
227  if( !value.empty() )
228  this->_remote_endpoint = value;
229  }
230  }
231 
233  {
234  }
235  };
236 
237  typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
238 
239  using websocketpp::connection_hdl;
240 
241  template<typename T>
243  {
244  public:
245  generic_websocket_server_impl( const std::string& forward_header_key )
246  :_server_thread( fc::thread::current() ), _forward_header_key( forward_header_key )
247  {
248  _server.clear_access_channels( websocketpp::log::alevel::all );
249  _server.init_asio( &fc::asio::default_io_service() );
250  _server.set_reuse_addr( true );
251  _server.set_open_handler( [this]( connection_hdl hdl ){
252  _server_thread.async( [this, hdl](){
253  auto new_con = std::make_shared<possibly_proxied_websocket_connection<
254  typename websocketpp::server<T>::connection_ptr>>( _server.get_con_from_hdl(hdl),
255  _forward_header_key );
256  _on_connection( _connections[hdl] = new_con );
257  }).wait();
258  });
259  _server.set_message_handler( [this]( connection_hdl hdl,
260  typename websocketpp::server<T>::message_ptr msg ){
261  _server_thread.async( [this,hdl,msg](){
262  auto current_con = _connections.find(hdl);
263  if( current_con == _connections.end() )
264  return;
265  auto payload = msg->get_payload();
266  std::shared_ptr<websocket_connection> con = current_con->second;
267  wlog( "[IN] ${remote_endpoint} ${msg}",
268  ("remote_endpoint",con->get_remote_endpoint_string()) ("msg",payload) );
269  ++_pending_messages;
270  auto f = fc::async([this,con,payload](){
271  if( _pending_messages )
272  --_pending_messages;
273  con->on_message( payload );
274  });
275  if( _pending_messages > 100 )
276  f.wait(); // Note: this is a bit strange, because it forces the server to process all
277  // 100 pending messages (assuming this message is the last one) before
278  // trying to accept a new message.
279  // Ideally the `wait` should be canceled immediately when the number of
280  // pending messages falls below 100. That said, wait on the whole queue,
281  // but not wait on one message.
282  }).wait();
283  });
284 
285  _server.set_socket_init_handler( [this]( websocketpp::connection_hdl hdl,
286  typename websocketpp::server<T>::connection_type::socket_type& s ) {
287  boost::asio::ip::tcp::no_delay option(true);
288  s.lowest_layer().set_option(option);
289  } );
290 
291  _server.set_http_handler( [this]( connection_hdl hdl ){
292  _server_thread.async( [this,hdl](){
293  auto con = _server.get_con_from_hdl(hdl);
294  auto current_con = std::make_shared<possibly_proxied_websocket_connection<
295  typename websocketpp::server<T>::connection_ptr>>( con, _forward_header_key );
296  _on_connection( current_con );
297 
298  con->defer_http_response(); // Note: this can tie up resources if send_http_response() is not
299  // called quickly enough
300  std::string remote_endpoint = current_con->get_remote_endpoint_string();
301  std::string request_body = con->get_request_body();
302  wlog( "[HTTP-IN] ${remote_endpoint} ${msg}",
303  ("remote_endpoint",remote_endpoint) ("msg",request_body) );
304 
305  fc::async([current_con, request_body, con, remote_endpoint] {
306  fc::http::reply response = current_con->on_http(request_body);
307  ilog( "[HTTP-OUT] ${remote_endpoint} ${status} ${msg}",
308  ("remote_endpoint",remote_endpoint)
309  ("status",response.status)
310  ("msg",response.body_as_string) );
311  con->set_body( std::move( response.body_as_string ) );
312  con->set_status( websocketpp::http::status_code::value(response.status) );
313  con->send_http_response();
314  current_con->closed();
315  }, "call on_http");
316  }).wait();
317  });
318 
319  _server.set_close_handler( [this]( connection_hdl hdl ){
320  _server_thread.async( [this,hdl](){
321  if( _connections.find(hdl) != _connections.end() )
322  {
323  _connections[hdl]->closed();
324  _connections.erase( hdl );
325  if( _connections.empty() && _all_connections_closed )
326  _all_connections_closed->set_value();
327  }
328  else
329  {
330  wlog( "unknown connection closed" );
331  }
332  }).wait();
333  });
334 
335  _server.set_fail_handler( [this]( connection_hdl hdl ){
336  _server_thread.async( [this,hdl](){
337  if( _connections.find(hdl) != _connections.end() )
338  {
339  _connections[hdl]->closed();
340  _connections.erase( hdl );
341  if( _connections.empty() && _all_connections_closed )
342  _all_connections_closed->set_value();
343  }
344  else
345  {
346  // if the server is shutting down, assume this hdl is the server socket
347  if( _server_socket_closed )
348  _server_socket_closed->set_value();
349  else
350  wlog( "unknown connection failed" );
351  }
352  }).wait();
353  });
354  }
355 
357  {
358  if( _server.is_listening() )
359  {
360  // _server.stop_listening() may trigger the on_fail callback function (the lambda function set by
361  // _server.set_fail_handler(...) ) for the listening server socket (note: the connection handle
362  // associated with the server socket is not in our connection map),
363  // the on_fail callback function may fire (async) a new task which may run really late
364  // and it will try to access the member variables of this server object,
365  // so we need to wait for it before destructing this object.
366  _server_socket_closed = promise<void>::create();
367  _server.stop_listening();
368  }
369 
370  // Note: since _connections can be modified by lambda functions in set_*_handler, which are running
371  // in other tasks, perhaps we need to wait for them (especially the one in set_open_handler)
372  // being processed. Otherwise `_all_connections_closed.wait()` may hang.
373  if( !_connections.empty() )
374  {
375  _all_connections_closed = promise<void>::create();
376 
377  auto cpy_con = _connections;
378  websocketpp::lib::error_code ec;
379  for( auto& item : cpy_con )
380  _server.close( item.first, 0, "server exit", ec );
381 
382  _all_connections_closed->wait();
383  }
384 
385  if( _server_socket_closed )
386  _server_socket_closed->wait();
387  }
388 
389  typedef std::map<connection_hdl, websocket_connection_ptr, std::owner_less<connection_hdl> > con_map;
390 
391  // Note: std::map is not thread-safe nor task-safe, we may need
392  // to use a mutex or similar to avoid concurrent access.
393  con_map _connections;
395  websocketpp::server<T> _server;
399  uint32_t _pending_messages = 0;
400  std::string _forward_header_key;
401  };
402 
403  class websocket_server_impl : public generic_websocket_server_impl<asio_with_stub_log>
404  {
405  public:
406  websocket_server_impl( const std::string& forward_header_key )
407  : generic_websocket_server_impl( forward_header_key )
408  {}
409 
411  };
412 
414  {
415  public:
416  websocket_tls_server_impl( const string& server_pem, const string& ssl_password,
417  const std::string& forward_header_key )
418  : generic_websocket_server_impl( forward_header_key )
419  {
420  _server.set_tls_init_handler( [this,server_pem,ssl_password]( websocketpp::connection_hdl hdl ) {
421  context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(
422  boost::asio::ssl::context::tlsv12 );
423  try {
424  ctx->set_options( boost::asio::ssl::context::default_workarounds |
425  boost::asio::ssl::context::no_sslv2 |
426  boost::asio::ssl::context::no_sslv3 |
427  boost::asio::ssl::context::no_tlsv1 |
428  boost::asio::ssl::context::no_tlsv1_1 |
429  boost::asio::ssl::context::single_dh_use );
430  ctx->set_password_callback(
431  [ssl_password](std::size_t max_length, boost::asio::ssl::context::password_purpose){
432  return ssl_password;
433  });
434  ctx->use_certificate_chain_file(server_pem);
435  ctx->use_private_key_file(server_pem, boost::asio::ssl::context::pem);
436  } catch (std::exception& e) {
437  std::cout << e.what() << std::endl;
438  }
439  return ctx;
440  });
441  }
442 
444 
445  };
446 
447 
448  template<typename T>
450  {
451  public:
453  :_client_thread( fc::thread::current() )
454  {
455  _client.clear_access_channels( websocketpp::log::alevel::all );
456  _client.set_message_handler( [this]( connection_hdl hdl,
457  typename websocketpp::client<T>::message_ptr msg ){
458  _client_thread.async( [this,msg](){
459  wdump((msg->get_payload()));
460  auto received = msg->get_payload();
461  fc::async( [this,received](){
462  if( _connection )
463  _connection->on_message(received);
464  });
465  }).wait();
466  });
467  _client.set_close_handler( [this]( connection_hdl hdl ){
468  _client_thread.async( [this](){
469  if( _connection ) {
470  _connection->closed();
471  _connection.reset();
472  }
473  } ).wait();
474  if( _closed )
475  _closed->set_value();
476  });
477  _client.set_fail_handler( [this]( connection_hdl hdl ){
478  auto con = _client.get_con_from_hdl(hdl);
479  auto message = con->get_ec().message();
480  if( _connection )
481  {
482  _client_thread.async( [this](){
483  if( _connection ) {
484  _connection->closed();
485  _connection.reset();
486  }
487  } ).wait();
488  }
489  if( _connected && !_connected->ready() )
490  {
491  _connected->set_exception( exception_ptr(
492  new FC_EXCEPTION( exception, "${message}", ("message",message)) ) );
493  }
494  if( _closed )
495  _closed->set_value();
496  });
497 
498  _client.init_asio( &fc::asio::default_io_service() );
499  }
500 
502  {
503  if( _connection )
504  {
505  _connection->close(0, "client closed");
506  _connection.reset();
507  }
508  if( _closed )
509  _closed->wait();
510  }
511 
512  websocket_connection_ptr connect( const std::string& uri, const fc::http::headers& headers )
513  {
514  websocketpp::lib::error_code ec;
515 
516  _uri = uri;
517  _connected = promise<void>::create("websocket::connect");
518 
519  _client.set_open_handler( [this]( websocketpp::connection_hdl hdl ){
520  _hdl = hdl;
521  auto con = _client.get_con_from_hdl(hdl);
522  _connection = std::make_shared<websocket_connection_impl<
523  typename websocketpp::client<T>::connection_ptr>>( con );
524  _closed = promise<void>::create("websocket::closed");
525  _connected->set_value();
526  });
527 
528  auto con = _client.get_connection( uri, ec );
529 
530  for( const fc::http::header& h : headers )
531  {
532  con->append_header( h.key, h.val );
533  }
534 
535  FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) );
536 
537  _client.connect(con);
538  _connected->wait();
539  return _connection;
540  }
541 
545  websocketpp::client<T> _client;
547  std::string _uri;
549  };
550 
551  class websocket_client_impl : public generic_websocket_client_impl<asio_with_stub_log>
552  {};
553 
555  {
556  public:
557  websocket_tls_client_impl( const std::string& ca_filename )
559  {
560  // ca_filename has special values:
561  // "_none" disables cert checking (potentially insecure!)
562  // "_default" uses default CA's provided by OS
563 
564  //
565  // We need ca_filename to be copied into the closure, as the
566  // referenced object might be destroyed by the caller by the time
567  // tls_init_handler() is called. According to [1], capture-by-value
568  // results in the desired behavior (i.e. creation of
569  // a copy which is stored in the closure) on standards compliant compilers,
570  // but some compilers on some optimization levels
571  // are buggy and are not standards compliant in this situation.
572  // Also, keep in mind this is the opinion of a single forum
573  // poster and might be wrong.
574  //
575  // To be safe, the following line explicitly creates a non-reference string
576  // which is captured by value, which should have the
577  // correct behavior on all compilers.
578  //
579  // [1] http://www.cplusplus.com/forum/general/142165/
580  // [2] http://stackoverflow.com/questions/21443023/capturing-a-reference-by-reference-in-a-c11-lambda
581  //
582 
583  std::string ca_filename_copy = ca_filename;
584 
585  _client.set_tls_init_handler( [this,ca_filename_copy](websocketpp::connection_hdl) {
586  context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(
587  boost::asio::ssl::context::tlsv12);
588  try {
589  ctx->set_options( boost::asio::ssl::context::default_workarounds |
590  boost::asio::ssl::context::no_sslv2 |
591  boost::asio::ssl::context::no_sslv3 |
592  boost::asio::ssl::context::no_tlsv1 |
593  boost::asio::ssl::context::no_tlsv1_1 |
594  boost::asio::ssl::context::single_dh_use );
595 
596  setup_peer_verify( ctx, ca_filename_copy );
597  } catch (std::exception& e) {
598  edump((e.what()));
599  std::cout << e.what() << std::endl;
600  }
601  return ctx;
602  });
603 
604  }
606 
607  std::string get_host()const
608  {
609  return websocketpp::uri( _uri ).get_host();
610  }
611 
612  void setup_peer_verify( context_ptr& ctx, const std::string& ca_filename )
613  {
614  if( ca_filename == "_none" )
615  return;
616  ctx->set_verify_mode( boost::asio::ssl::verify_peer );
617  if( ca_filename == "_default" )
618  {
619 #if WIN32
620  add_windows_root_certs( *ctx );
621 #else
622  ctx->set_default_verify_paths();
623 #endif
624  }
625  else
626  ctx->load_verify_file( ca_filename );
627  ctx->set_verify_depth(10);
628  ctx->set_verify_callback( boost::asio::ssl::rfc2818_verification( get_host() ) );
629  }
630 
631  };
632 
633 
634  } // namespace detail
635 
636  websocket_server::websocket_server( const std::string& forward_header_key )
637  :my( new detail::websocket_server_impl( forward_header_key ) ) {}
639 
641  {
642  my->_on_connection = handler;
643  }
644 
645  void websocket_server::listen( uint16_t port )
646  {
647  my->_server.listen(port);
648  }
650  {
651  my->_server.listen( boost::asio::ip::tcp::endpoint(
652  boost::asio::ip::address_v4(uint32_t(ep.get_address())),ep.port()) );
653  }
654 
656  {
657  websocketpp::lib::asio::error_code ec;
658  return my->_server.get_local_endpoint(ec).port();
659  }
660 
662  my->_server.start_accept();
663  }
664 
666  {
667  my->_server.stop_listening();
668  }
669 
671  {
672  auto cpy_con = my->_connections;
673  websocketpp::lib::error_code ec;
674  for( auto& connection : cpy_con )
675  my->_server.close( connection.first, websocketpp::close::status::normal, "Goodbye", ec );
676  }
677 
678  websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password,
679  const std::string& forward_header_key )
680  :my( new detail::websocket_tls_server_impl(server_pem, ssl_password, forward_header_key) )
681  {}
682 
684 
686  {
687  my->_on_connection = handler;
688  }
689 
690  void websocket_tls_server::listen( uint16_t port )
691  {
692  my->_server.listen(port);
693  }
695  {
696  my->_server.listen( boost::asio::ip::tcp::endpoint(
697  boost::asio::ip::address_v4(uint32_t(ep.get_address())),ep.port()) );
698  }
699 
701  {
702  websocketpp::lib::asio::error_code ec;
703  return my->_server.get_local_endpoint(ec).port();
704  }
705 
707  my->_server.start_accept();
708  }
709 
711  {
712  my->_server.stop_listening();
713  }
714 
716  {
717  auto cpy_con = my->_connections;
718  websocketpp::lib::error_code ec;
719  for( auto& connection : cpy_con )
720  my->_server.close( connection.first, websocketpp::close::status::normal, "Goodbye", ec );
721  }
722 
723 
724  websocket_client::websocket_client( const std::string& ca_filename )
725  :my( new detail::websocket_client_impl() ),
726  smy(new detail::websocket_tls_client_impl( ca_filename ))
727  {}
728 
730 
732  { try {
733 
734  FC_ASSERT( uri.substr(0,4) == "wss:" || uri.substr(0,3) == "ws:", "Unsupported protocol" );
735 
736  // WSS
737  if( uri.substr(0,4) == "wss:" )
738  return smy->connect( uri, _headers );
739 
740  // WS
741  return my->connect( uri, _headers );
742 
743  } FC_CAPTURE_AND_RETHROW( (uri) ) }
744 
746  {
747  return connect( uri );
748  }
749 
751  {
752  if( my->_hdl )
753  my->_client.close( *my->_hdl, websocketpp::close::status::normal, "Goodbye" );
754  }
755 
757  {
758  close();
759  if( my->_closed )
760  my->_closed->wait();
761  }
762 
763  void websocket_client::append_header(const std::string& key, const std::string& value)
764  {
765  _headers.emplace_back( key, value );
766  }
767 
768 } } // fc::http
base::con_msg_manager_type con_msg_manager_type
Definition: websocket.cpp:113
std::map< connection_hdl, websocket_connection_ptr, std::owner_less< connection_hdl > > con_map
Definition: websocket.cpp:389
virtual void send_message(const std::string &message) override
Definition: websocket.cpp:195
auto async(Functor &&f, const char *desc FC_TASK_NAME_DEFAULT_ARG, priority prio=priority()) -> fc::future< decltype(f())>
Definition: thread.hpp:227
base::concurrency_type concurrency_type
Definition: websocket.cpp:67
static ptr create(const char *desc FC_TASK_NAME_DEFAULT_ARG)
Definition: future.hpp:114
base::response_type response_type
Definition: websocket.cpp:149
fc::optional< connection_hdl > _hdl
Definition: websocket.cpp:548
websocketpp::transport::asio::endpoint< transport_config > transport_type
Definition: websocket.cpp:130
const auto response
base::concurrency_type concurrency_type
Definition: websocket.cpp:146
websocketpp::transport::asio::tls_socket::endpoint socket_type
Definition: websocket.cpp:127
fc::promise< void >::ptr _server_socket_closed
Promise to wait for the server socket to be closed.
Definition: websocket.cpp:398
T wait(boost::signals2::signal< void(T)> &sig, const microseconds &timeout_us=microseconds::maximum())
Definition: signals.hpp:38
void listen(uint16_t port)
Definition: websocket.cpp:690
base::concurrency_type concurrency_type
Definition: websocket.cpp:107
websocketpp::lib::shared_ptr< boost::asio::ssl::context > context_ptr
Definition: websocket.cpp:237
websocketpp::extensions::permessage_deflate::disabled< permessage_deflate_config > permessage_deflate_type
Definition: websocket.cpp:99
websocket_server_impl(const std::string &forward_header_key)
Definition: websocket.cpp:406
fc::promise< void >::ptr _all_connections_closed
Promise to wait for all connections to be closed.
Definition: websocket.cpp:397
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
Definition: exception.hpp:56
std::shared_ptr< connection > connection_ptr
Definition: connection.hpp:78
void on_connection(const on_connection_handler &handler)
Definition: websocket.cpp:685
on_connection_handler _on_connection
A handler to be called when a new connection is accepted.
Definition: websocket.cpp:396
cout_t & cout
Definition: iostream.cpp:175
#define wlog(FORMAT,...)
Definition: logger.hpp:123
websocketpp::extensions::permessage_deflate::disabled< permessage_deflate_config > permessage_deflate_type
Definition: websocket.cpp:139
void on_connection(const on_connection_handler &handler)
Definition: websocket.cpp:640
std::shared_ptr< websocket_connection > websocket_connection_ptr
Definition: websocket.hpp:47
websocket_connection_ptr connect(const std::string &uri, const fc::http::headers &headers)
Definition: websocket.cpp:512
void setup_peer_verify(context_ptr &ctx, const std::string &ca_filename)
Definition: websocket.cpp:612
websocketpp::server< T > _server
The server.
Definition: websocket.cpp:395
websocket_server(const std::string &forward_header_key)
Definition: websocket.cpp:636
const address & get_address() const
Definition: ip.cpp:72
websocketpp::log::stub elog_type
Definition: websocket.cpp:76
std::shared_ptr< exception > exception_ptr
Definition: exception.hpp:131
websocket_connection_ptr secure_connect(const std::string &uri)
Definition: websocket.cpp:745
#define wdump(SEQ)
Definition: logger.hpp:174
base::endpoint_msg_manager_type endpoint_msg_manager_type
Definition: websocket.cpp:74
#define edump(SEQ)
Definition: logger.hpp:182
uint16_t port() const
Definition: ip.cpp:71
websocketpp::transport::asio::endpoint< transport_config > transport_type
Definition: websocket.cpp:169
std::function< void(const websocket_connection_ptr &)> on_connection_handler
Definition: websocket.hpp:49
websocketpp::log::stub alog_type
Definition: websocket.cpp:77
#define ilog(FORMAT,...)
Definition: logger.hpp:117
virtual std::string get_request_header(const std::string &key) override
Definition: websocket.cpp:207
websocket_connection_ptr connect(const std::string &uri)
Definition: websocket.cpp:731
con_map _connections
Holds accepted connections.
Definition: websocket.cpp:393
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:478
websocketpp::transport::asio::tls_socket::endpoint socket_type
Definition: websocket.cpp:166
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
boost::asio::ip::tcp::endpoint endpoint
Definition: asio.hpp:240
websocketpp::log::stub alog_type
Definition: websocket.cpp:156
fc::thread & _server_thread
The thread that runs the server.
Definition: websocket.cpp:394
base::endpoint_msg_manager_type endpoint_msg_manager_type
Definition: websocket.cpp:153
base::endpoint_msg_manager_type endpoint_msg_manager_type
Definition: websocket.cpp:114
websocket_tls_server_impl(const string &server_pem, const string &ssl_password, const std::string &forward_header_key)
Definition: websocket.cpp:416
websocketpp::transport::asio::basic_socket::endpoint socket_type
Definition: websocket.cpp:87
boost::asio::io_service & default_io_service()
Definition: asio.cpp:182
Definition: api.hpp:15
generic_websocket_server_impl(const std::string &forward_header_key)
Definition: websocket.cpp:245
std::vector< header > headers
Definition: connection.hpp:21
websocket_tls_server(const std::string &server_pem, const std::string &ssl_password, const std::string &forward_header_key)
Definition: websocket.cpp:678
base::con_msg_manager_type con_msg_manager_type
Definition: websocket.cpp:152
std::string body_as_string
Definition: connection.hpp:39
void listen(uint16_t port)
Definition: websocket.cpp:645
websocket_tls_client_impl(const std::string &ca_filename)
Definition: websocket.cpp:557
base::con_msg_manager_type con_msg_manager_type
Definition: websocket.cpp:73
possibly_proxied_websocket_connection(T con, const std::string &forward_header_key)
Definition: websocket.cpp:219
std::string _forward_header_key
A header like "X-Forwarded-For" (XFF) with data IP:port.
Definition: websocket.cpp:400
virtual void close(int64_t code, const std::string &reason) override
Definition: websocket.cpp:202
websocketpp::transport::asio::endpoint< transport_config > transport_type
Definition: websocket.cpp:90
#define FC_EXCEPTION(EXCEPTION_TYPE, FORMAT,...)
Definition: exception.hpp:371
websocketpp::extensions::permessage_deflate::disabled< permessage_deflate_config > permessage_deflate_type
Definition: websocket.cpp:178
void append_header(const std::string &key, const std::string &value)
Definition: websocket.cpp:763
websocket_client(const std::string &ca_filename="_default")
Definition: websocket.cpp:724
websocketpp::log::stub elog_type
Definition: websocket.cpp:155
base::response_type response_type
Definition: websocket.cpp:70