rippled
short_read_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4 
5  Copyright 2014 Ripple Labs Inc.
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/make_SSLContext.h>
21 #include <ripple/beast/core/CurrentThreadName.h>
22 #include <ripple/beast/unit_test.h>
23 #include <test/jtx/envconfig.h>
24 
25 #include <boost/asio.hpp>
26 #include <boost/asio/ssl.hpp>
27 #include <boost/utility/in_place_factory.hpp>
28 
29 #include <cassert>
30 #include <condition_variable>
31 #include <functional>
32 #include <memory>
33 #include <optional>
34 #include <thread>
35 #include <utility>
36 
37 namespace ripple {
38 /*
39 
40 Findings from the test:
41 
42 If the remote host calls async_shutdown then the local host's
43 async_read will complete with eof.
44 
45 If both hosts call async_shutdown then the calls to async_shutdown
46 will complete with eof.
47 
48 */
49 
50 class short_read_test : public beast::unit_test::suite
51 {
52 private:
53  using io_context_type = boost::asio::io_context;
54  using strand_type = boost::asio::io_context::strand;
55  using timer_type =
56  boost::asio::basic_waitable_timer<std::chrono::steady_clock>;
57  using acceptor_type = boost::asio::ip::tcp::acceptor;
58  using socket_type = boost::asio::ip::tcp::socket;
59  using stream_type = boost::asio::ssl::stream<socket_type&>;
60  using error_code = boost::system::error_code;
61  using endpoint_type = boost::asio::ip::tcp::endpoint;
62  using address_type = boost::asio::ip::address;
63 
69 
70  template <class Streambuf>
71  static void
72  write(Streambuf& sb, std::string const& s)
73  {
74  using boost::asio::buffer;
75  using boost::asio::buffer_copy;
76  using boost::asio::buffer_size;
77  boost::asio::const_buffers_1 buf(s.data(), s.size());
78  sb.commit(buffer_copy(sb.prepare(buffer_size(buf)), buf));
79  }
80 
81  //--------------------------------------------------------------------------
82 
83  class Base
84  {
85  protected:
86  class Child
87  {
88  private:
90 
91  public:
92  explicit Child(Base& base) : base_(base)
93  {
94  }
95 
96  virtual ~Child()
97  {
98  base_.remove(this);
99  }
100 
101  virtual void
102  close() = 0;
103  };
104 
105  private:
109  bool closed_ = false;
110 
111  public:
113  {
114  // Derived class must call wait() in the destructor
115  assert(list_.empty());
116  }
117 
118  void
120  {
121  std::lock_guard lock(mutex_);
122  list_.emplace(child.get(), child);
123  }
124 
125  void
126  remove(Child* child)
127  {
128  std::lock_guard lock(mutex_);
129  list_.erase(child);
130  if (list_.empty())
131  cond_.notify_one();
132  }
133 
134  void
136  {
138  {
139  std::lock_guard lock(mutex_);
140  v.reserve(list_.size());
141  if (closed_)
142  return;
143  closed_ = true;
144  for (auto const& c : list_)
145  {
146  if (auto p = c.second.lock())
147  {
148  p->close();
149  // Must destroy shared_ptr outside the
150  // lock otherwise deadlock from the
151  // managed object's destructor.
152  v.emplace_back(std::move(p));
153  }
154  }
155  }
156  }
157 
158  void
160  {
162  while (!list_.empty())
163  cond_.wait(lock);
164  }
165  };
166 
167  //--------------------------------------------------------------------------
168 
169  class Server : public Base
170  {
171  private:
174 
175  struct Acceptor : Child, std::enable_shared_from_this<Acceptor>
176  {
182 
183  explicit Acceptor(Server& server)
184  : Child(server)
185  , server_(server)
186  , test_(server_.test_)
187  , acceptor_(
190  beast::IP::Address::from_string(
191  test::getEnvLocalhostAddr()),
192  0))
195  {
196  acceptor_.listen();
197  server_.endpoint_ = acceptor_.local_endpoint();
198  }
199 
200  void
201  close() override
202  {
203  if (!strand_.running_in_this_thread())
204  return post(
205  strand_,
207  acceptor_.close();
208  }
209 
210  void
211  run()
212  {
213  acceptor_.async_accept(
214  socket_,
215  bind_executor(
216  strand_,
217  std::bind(
220  std::placeholders::_1)));
221  }
222 
223  void
224  fail(std::string const& what, error_code ec)
225  {
226  if (acceptor_.is_open())
227  {
228  if (ec != boost::asio::error::operation_aborted)
229  test_.log << what << ": " << ec.message() << std::endl;
230  acceptor_.close();
231  }
232  }
233 
234  void
236  {
237  if (ec)
238  return fail("accept", ec);
239  auto const p =
240  std::make_shared<Connection>(server_, std::move(socket_));
241  server_.add(p);
242  p->run();
243  acceptor_.async_accept(
244  socket_,
245  bind_executor(
246  strand_,
247  std::bind(
250  std::placeholders::_1)));
251  }
252  };
253 
254  struct Connection : Child, std::enable_shared_from_this<Connection>
255  {
262  boost::asio::streambuf buf_;
263 
264  Connection(Server& server, socket_type&& socket)
265  : Child(server)
266  , server_(server)
267  , test_(server_.test_)
268  , socket_(std::move(socket))
272  {
273  }
274 
275  void
276  close() override
277  {
278  if (!strand_.running_in_this_thread())
279  return post(
280  strand_,
282  if (socket_.is_open())
283  {
284  socket_.close();
285  timer_.cancel();
286  }
287  }
288 
289  void
290  run()
291  {
292  timer_.expires_from_now(std::chrono::seconds(3));
293  timer_.async_wait(bind_executor(
294  strand_,
295  std::bind(
298  std::placeholders::_1)));
299  stream_.async_handshake(
300  stream_type::server,
301  bind_executor(
302  strand_,
303  std::bind(
306  std::placeholders::_1)));
307  }
308 
309  void
310  fail(std::string const& what, error_code ec)
311  {
312  if (socket_.is_open())
313  {
314  if (ec != boost::asio::error::operation_aborted)
315  test_.log << "[server] " << what << ": " << ec.message()
316  << std::endl;
317  socket_.close();
318  timer_.cancel();
319  }
320  }
321 
322  void
324  {
325  if (ec == boost::asio::error::operation_aborted)
326  return;
327  if (ec)
328  return fail("timer", ec);
329  test_.log << "[server] timeout" << std::endl;
330  socket_.close();
331  }
332 
333  void
335  {
336  if (ec)
337  return fail("handshake", ec);
338 #if 1
339  boost::asio::async_read_until(
340  stream_,
341  buf_,
342  "\n",
343  bind_executor(
344  strand_,
345  std::bind(
348  std::placeholders::_1,
349  std::placeholders::_2)));
350 #else
351  close();
352 #endif
353  }
354 
355  void
356  on_read(error_code ec, std::size_t bytes_transferred)
357  {
358  if (ec == boost::asio::error::eof)
359  {
360  server_.test_.log << "[server] read: EOF" << std::endl;
361  return stream_.async_shutdown(bind_executor(
362  strand_,
363  std::bind(
366  std::placeholders::_1)));
367  }
368  if (ec)
369  return fail("read", ec);
370 
371  buf_.commit(bytes_transferred);
372  buf_.consume(bytes_transferred);
373  write(buf_, "BYE\n");
374  boost::asio::async_write(
375  stream_,
376  buf_.data(),
377  bind_executor(
378  strand_,
379  std::bind(
382  std::placeholders::_1,
383  std::placeholders::_2)));
384  }
385 
386  void
387  on_write(error_code ec, std::size_t bytes_transferred)
388  {
389  buf_.consume(bytes_transferred);
390  if (ec)
391  return fail("write", ec);
392  stream_.async_shutdown(bind_executor(
393  strand_,
394  std::bind(
397  std::placeholders::_1)));
398  }
399 
400  void
402  {
403  if (ec)
404  return fail("shutdown", ec);
405  socket_.close();
406  timer_.cancel();
407  }
408  };
409 
410  public:
411  explicit Server(short_read_test& test) : test_(test)
412  {
413  auto const p = std::make_shared<Acceptor>(*this);
414  add(p);
415  p->run();
416  }
417 
419  {
420  close();
421  wait();
422  }
423 
424  endpoint_type const&
425  endpoint() const
426  {
427  return endpoint_;
428  }
429  };
430 
431  //--------------------------------------------------------------------------
432  class Client : public Base
433 
434  {
435  private:
437 
438  struct Connection : Child, std::enable_shared_from_this<Connection>
439  {
446  boost::asio::streambuf buf_;
448 
449  Connection(Client& client, endpoint_type const& ep)
450  : Child(client)
451  , client_(client)
452  , test_(client_.test_)
457  , ep_(ep)
458  {
459  }
460 
461  void
462  close() override
463  {
464  if (!strand_.running_in_this_thread())
465  return post(
466  strand_,
468  if (socket_.is_open())
469  {
470  socket_.close();
471  timer_.cancel();
472  }
473  }
474 
475  void
476  run(endpoint_type const& ep)
477  {
478  timer_.expires_from_now(std::chrono::seconds(3));
479  timer_.async_wait(bind_executor(
480  strand_,
481  std::bind(
484  std::placeholders::_1)));
485  socket_.async_connect(
486  ep,
487  bind_executor(
488  strand_,
489  std::bind(
492  std::placeholders::_1)));
493  }
494 
495  void
496  fail(std::string const& what, error_code ec)
497  {
498  if (socket_.is_open())
499  {
500  if (ec != boost::asio::error::operation_aborted)
501  test_.log << "[client] " << what << ": " << ec.message()
502  << std::endl;
503  socket_.close();
504  timer_.cancel();
505  }
506  }
507 
508  void
510  {
511  if (ec == boost::asio::error::operation_aborted)
512  return;
513  if (ec)
514  return fail("timer", ec);
515  test_.log << "[client] timeout";
516  socket_.close();
517  }
518 
519  void
521  {
522  if (ec)
523  return fail("connect", ec);
524  stream_.async_handshake(
525  stream_type::client,
526  bind_executor(
527  strand_,
528  std::bind(
531  std::placeholders::_1)));
532  }
533 
534  void
536  {
537  if (ec)
538  return fail("handshake", ec);
539  write(buf_, "HELLO\n");
540 
541 #if 1
542  boost::asio::async_write(
543  stream_,
544  buf_.data(),
545  bind_executor(
546  strand_,
547  std::bind(
550  std::placeholders::_1,
551  std::placeholders::_2)));
552 #else
553  stream_.async_shutdown(bind_executor(
554  strand_,
555  std::bind(
558  std::placeholders::_1)));
559 #endif
560  }
561 
562  void
563  on_write(error_code ec, std::size_t bytes_transferred)
564  {
565  buf_.consume(bytes_transferred);
566  if (ec)
567  return fail("write", ec);
568 #if 1
569  boost::asio::async_read_until(
570  stream_,
571  buf_,
572  "\n",
573  bind_executor(
574  strand_,
575  std::bind(
578  std::placeholders::_1,
579  std::placeholders::_2)));
580 #else
581  stream_.async_shutdown(bind_executor(
582  strand_,
583  std::bind(
586  std::placeholders::_1)));
587 #endif
588  }
589 
590  void
591  on_read(error_code ec, std::size_t bytes_transferred)
592  {
593  if (ec)
594  return fail("read", ec);
595  buf_.commit(bytes_transferred);
596  stream_.async_shutdown(bind_executor(
597  strand_,
598  std::bind(
601  std::placeholders::_1)));
602  }
603 
604  void
606  {
607  if (ec)
608  return fail("shutdown", ec);
609  socket_.close();
610  timer_.cancel();
611  }
612  };
613 
614  public:
615  Client(short_read_test& test, endpoint_type const& ep) : test_(test)
616  {
617  auto const p = std::make_shared<Connection>(*this, ep);
618  add(p);
619  p->run(ep);
620  }
621 
623  {
624  close();
625  wait();
626  }
627  };
628 
629 public:
631  : work_(io_context_.get_executor())
632  , thread_(std::thread([this]() {
633  beast::setCurrentThreadName("io_context");
634  this->io_context_.run();
635  }))
637  {
638  }
639 
641  {
642  work_.reset();
643  thread_.join();
644  }
645 
646  void
647  run() override
648  {
649  Server s(*this);
650  Client c(*this, s.endpoint());
651  c.wait();
652  pass();
653  }
654 };
655 
656 BEAST_DEFINE_TESTSUITE(short_read, overlay, ripple);
657 
658 } // namespace ripple
ripple::short_read_test::Client::Client
Client(short_read_test &test, endpoint_type const &ep)
Definition: short_read_test.cpp:615
ripple::short_read_test::Base::mutex_
std::mutex mutex_
Definition: short_read_test.cpp:106
ripple::short_read_test::Client::Connection::fail
void fail(std::string const &what, error_code ec)
Definition: short_read_test.cpp:496
ripple::short_read_test::Client::Connection::timer_
timer_type timer_
Definition: short_read_test.cpp:445
ripple::short_read_test
Definition: short_read_test.cpp:50
std::bind
T bind(T... args)
ripple::short_read_test::Server::Connection
Definition: short_read_test.cpp:254
std::string
STL class.
ripple::short_read_test::Server
Definition: short_read_test.cpp:169
std::shared_ptr< boost::asio::ssl::context >
ripple::short_read_test::Client::Connection::on_handshake
void on_handshake(error_code ec)
Definition: short_read_test.cpp:535
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
utility
ripple::short_read_test::Server::Acceptor::Acceptor
Acceptor(Server &server)
Definition: short_read_test.cpp:183
ripple::short_read_test::Client::~Client
~Client()
Definition: short_read_test.cpp:622
ripple::short_read_test::Server::Acceptor::strand_
strand_type strand_
Definition: short_read_test.cpp:181
ripple::short_read_test::Client::Connection::test_
short_read_test & test_
Definition: short_read_test.cpp:441
functional
ripple::short_read_test::Server::Acceptor::close
void close() override
Definition: short_read_test.cpp:201
ripple::short_read_test::timer_type
boost::asio::basic_waitable_timer< std::chrono::steady_clock > timer_type
Definition: short_read_test.cpp:56
ripple::short_read_test::Server::Connection::on_handshake
void on_handshake(error_code ec)
Definition: short_read_test.cpp:334
std::vector::reserve
T reserve(T... args)
ripple::short_read_test::Server::Acceptor::on_accept
void on_accept(error_code ec)
Definition: short_read_test.cpp:235
ripple::short_read_test::Server::Connection::fail
void fail(std::string const &what, error_code ec)
Definition: short_read_test.cpp:310
std::vector
STL class.
ripple::short_read_test::error_code
boost::system::error_code error_code
Definition: short_read_test.cpp:60
std::string::size
T size(T... args)
ripple::short_read_test::work_
std::optional< boost::asio::executor_work_guard< boost::asio::executor > > work_
Definition: short_read_test.cpp:66
ripple::make_SSLContext
std::shared_ptr< boost::asio::ssl::context > make_SSLContext(std::string const &cipherList)
Create a self-signed SSL context that allows anonymous Diffie Hellman.
Definition: make_SSLContext.cpp:364
ripple::short_read_test::thread_
std::thread thread_
Definition: short_read_test.cpp:67
ripple::short_read_test::Client::Connection::on_timer
void on_timer(error_code ec)
Definition: short_read_test.cpp:509
ripple::short_read_test::endpoint_type
boost::asio::ip::tcp::endpoint endpoint_type
Definition: short_read_test.cpp:61
std::chrono::seconds
ripple::short_read_test::Client::test_
short_read_test & test_
Definition: short_read_test.cpp:436
ripple::short_read_test::Server::Acceptor::test_
short_read_test & test_
Definition: short_read_test.cpp:178
ripple::short_read_test::Client::Connection::stream_
stream_type stream_
Definition: short_read_test.cpp:443
ripple::short_read_test::socket_type
boost::asio::ip::tcp::socket socket_type
Definition: short_read_test.cpp:58
std::lock_guard
STL class.
ripple::short_read_test::Base::remove
void remove(Child *child)
Definition: short_read_test.cpp:126
ripple::short_read_test::Base::Child
Definition: short_read_test.cpp:86
ripple::from_string
bool from_string(RangeSet< T > &rs, std::string const &s)
Convert the given styled string to a RangeSet.
Definition: RangeSet.h:123
ripple::short_read_test::context_
std::shared_ptr< boost::asio::ssl::context > context_
Definition: short_read_test.cpp:68
ripple::short_read_test::Base::~Base
~Base()
Definition: short_read_test.cpp:112
ripple::short_read_test::Server::Connection::Connection
Connection(Server &server, socket_type &&socket)
Definition: short_read_test.cpp:264
ripple::short_read_test::strand_type
boost::asio::io_context::strand strand_type
Definition: short_read_test.cpp:54
ripple::short_read_test::Server::Acceptor
Definition: short_read_test.cpp:175
std::optional::reset
T reset(T... args)
ripple::short_read_test::Base::cond_
std::condition_variable cond_
Definition: short_read_test.cpp:107
ripple::short_read_test::Client::Connection::on_connect
void on_connect(error_code ec)
Definition: short_read_test.cpp:520
ripple::short_read_test::Base::Child::base_
Base & base_
Definition: short_read_test.cpp:89
ripple::short_read_test::Server::Connection::on_write
void on_write(error_code ec, std::size_t bytes_transferred)
Definition: short_read_test.cpp:387
ripple::short_read_test::Server::Acceptor::server_
Server & server_
Definition: short_read_test.cpp:177
ripple::short_read_test::Server::endpoint_
endpoint_type endpoint_
Definition: short_read_test.cpp:173
ripple::short_read_test::Server::Connection::server_
Server & server_
Definition: short_read_test.cpp:256
std::enable_shared_from_this< Acceptor >::shared_from_this
T shared_from_this(T... args)
ripple::short_read_test::Server::Acceptor::acceptor_
acceptor_type acceptor_
Definition: short_read_test.cpp:179
thread
ripple::short_read_test::Server::Connection::timer_
timer_type timer_
Definition: short_read_test.cpp:261
ripple::short_read_test::Server::Connection::socket_
socket_type socket_
Definition: short_read_test.cpp:258
ripple::short_read_test::Server::Connection::close
void close() override
Definition: short_read_test.cpp:276
ripple::short_read_test::Client::Connection::client_
Client & client_
Definition: short_read_test.cpp:440
std::unique_lock
STL class.
ripple::short_read_test::write
static void write(Streambuf &sb, std::string const &s)
Definition: short_read_test.cpp:72
ripple::short_read_test::Base::add
void add(std::shared_ptr< Child > const &child)
Definition: short_read_test.cpp:119
std::enable_shared_from_this
ripple::short_read_test::Base::Child::Child
Child(Base &base)
Definition: short_read_test.cpp:92
ripple::short_read_test::Server::Acceptor::run
void run()
Definition: short_read_test.cpp:211
ripple::short_read_test::Server::endpoint
endpoint_type const & endpoint() const
Definition: short_read_test.cpp:425
ripple::short_read_test::Server::Connection::on_shutdown
void on_shutdown(error_code ec)
Definition: short_read_test.cpp:401
ripple::short_read_test::Client::Connection::on_read
void on_read(error_code ec, std::size_t bytes_transferred)
Definition: short_read_test.cpp:591
ripple::short_read_test::Base::Child::~Child
virtual ~Child()
Definition: short_read_test.cpp:96
ripple::short_read_test::Client::Connection
Definition: short_read_test.cpp:438
std::condition_variable::wait
T wait(T... args)
ripple::short_read_test::Client::Connection::run
void run(endpoint_type const &ep)
Definition: short_read_test.cpp:476
ripple::short_read_test::Base::closed_
bool closed_
Definition: short_read_test.cpp:109
std::map
STL class.
memory
ripple::short_read_test::Server::Server
Server(short_read_test &test)
Definition: short_read_test.cpp:411
ripple::short_read_test::Client::Connection::on_shutdown
void on_shutdown(error_code ec)
Definition: short_read_test.cpp:605
std::condition_variable::notify_one
T notify_one(T... args)
ripple::short_read_test::Client::Connection::on_write
void on_write(error_code ec, std::size_t bytes_transferred)
Definition: short_read_test.cpp:563
ripple::short_read_test::Client::Connection::buf_
boost::asio::streambuf buf_
Definition: short_read_test.cpp:446
ripple::short_read_test::address_type
boost::asio::ip::address address_type
Definition: short_read_test.cpp:62
ripple::short_read_test::~short_read_test
~short_read_test()
Definition: short_read_test.cpp:640
ripple::short_read_test::Server::Acceptor::fail
void fail(std::string const &what, error_code ec)
Definition: short_read_test.cpp:224
beast::setCurrentThreadName
void setCurrentThreadName(std::string_view name)
Changes the name of the caller thread.
Definition: CurrentThreadName.cpp:119
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::short_read_test::Client::Connection::ep_
endpoint_type const & ep_
Definition: short_read_test.cpp:447
ripple::short_read_test::Server::Acceptor::socket_
socket_type socket_
Definition: short_read_test.cpp:180
ripple::short_read_test::Base::list_
std::map< Child *, std::weak_ptr< Child > > list_
Definition: short_read_test.cpp:108
ripple::short_read_test::Client::Connection::close
void close() override
Definition: short_read_test.cpp:462
std::endl
T endl(T... args)
ripple::short_read_test::Server::Connection::buf_
boost::asio::streambuf buf_
Definition: short_read_test.cpp:262
ripple::short_read_test::acceptor_type
boost::asio::ip::tcp::acceptor acceptor_type
Definition: short_read_test.cpp:57
ripple::short_read_test::Server::~Server
~Server()
Definition: short_read_test.cpp:418
std
STL namespace.
cassert
ripple::short_read_test::Server::Connection::strand_
strand_type strand_
Definition: short_read_test.cpp:260
condition_variable
ripple::short_read_test::Server::Connection::on_read
void on_read(error_code ec, std::size_t bytes_transferred)
Definition: short_read_test.cpp:356
ripple::short_read_test::Base::wait
void wait()
Definition: short_read_test.cpp:159
ripple::short_read_test::run
void run() override
Definition: short_read_test.cpp:647
ripple::short_read_test::Client::Connection::Connection
Connection(Client &client, endpoint_type const &ep)
Definition: short_read_test.cpp:449
optional
std::mutex
STL class.
std::size_t
ripple::short_read_test::io_context_type
boost::asio::io_context io_context_type
Definition: short_read_test.cpp:53
ripple::short_read_test::Server::test_
short_read_test & test_
Definition: short_read_test.cpp:172
ripple::short_read_test::Client
Definition: short_read_test.cpp:432
ripple::short_read_test::Server::Connection::on_timer
void on_timer(error_code ec)
Definition: short_read_test.cpp:323
ripple::short_read_test::Base::Child::close
virtual void close()=0
ripple::short_read_test::Base::close
void close()
Definition: short_read_test.cpp:135
ripple::short_read_test::short_read_test
short_read_test()
Definition: short_read_test.cpp:630
ripple::short_read_test::Client::Connection::strand_
strand_type strand_
Definition: short_read_test.cpp:444
ripple::short_read_test::Base
Definition: short_read_test.cpp:83
std::string::data
T data(T... args)
ripple::short_read_test::io_context_
io_context_type io_context_
Definition: short_read_test.cpp:64
ripple::short_read_test::Server::Connection::run
void run()
Definition: short_read_test.cpp:290
ripple::short_read_test::stream_type
boost::asio::ssl::stream< socket_type & > stream_type
Definition: short_read_test.cpp:59
ripple::short_read_test::Server::Connection::test_
short_read_test & test_
Definition: short_read_test.cpp:257
ripple::short_read_test::Server::Connection::stream_
stream_type stream_
Definition: short_read_test.cpp:259
std::thread::join
T join(T... args)
ripple::short_read_test::Client::Connection::socket_
socket_type socket_
Definition: short_read_test.cpp:442
beast
Definition: base_uint.h:641