20 #ifndef RIPPLE_SERVER_BASEWSPEER_H_INCLUDED
21 #define RIPPLE_SERVER_BASEWSPEER_H_INCLUDED
23 #include <ripple/basics/safe_cast.h>
24 #include <ripple/server/impl/BasePeer.h>
25 #include <ripple/server/impl/LowestLayer.h>
26 #include <ripple/protocol/BuildInfo.h>
27 #include <ripple/beast/utility/rngfill.h>
28 #include <ripple/crypto/csprng.h>
29 #include <boost/beast/websocket.hpp>
30 #include <boost/beast/core/multi_buffer.hpp>
31 #include <boost/beast/http/message.hpp>
38 template<
class Handler,
class Impl>
54 boost::beast::multi_buffer
rb_;
55 boost::beast::multi_buffer
wb_;
58 boost::beast::websocket::close_reason
cr_;
66 template<
class Body,
class Headers>
70 boost::asio::executor
const& executor,
73 boost::beast::http::request<Body, Headers>&&
request,
95 boost::asio::ip::tcp::endpoint
const&
108 close(boost::beast::websocket::close_reason
const& reason)
override;
117 return *
static_cast<Impl*
>(
this);
152 boost::beast::string_view payload);
157 template<
class String>
164 template <
class Handler,
class Impl>
165 template <
class Body,
class Headers>
169 boost::asio::executor
const& executor,
172 boost::beast::http::request<Body, Headers>&& request,
180 , request_(
std::move(request))
181 , timer_(
std::move(timer))
182 , payload_(
"12345678")
186 template<
class Handler,
class Impl>
191 if(! strand_.running_in_this_thread())
193 strand_,
std::bind(&BaseWSPeer::run, impl().shared_from_this()));
194 impl().ws_.set_option(port().pmd_options);
197 &BaseWSPeer::on_ping_pong,
198 this, std::placeholders::_1, std::placeholders::_2);
199 impl().ws_.control_callback(control_callback_);
201 close_on_timer_ =
true;
202 impl().ws_.async_accept_ex(
205 res.set(boost::beast::http::field::server,
206 BuildInfo::getFullVersionString());
211 &BaseWSPeer::on_ws_handshake,
212 impl().shared_from_this(),
213 std::placeholders::_1)));
216 template<
class Handler,
class Impl>
221 if(! strand_.running_in_this_thread())
225 &BaseWSPeer::send, impl().shared_from_this(), std::move(w)));
228 if(wq_.size() > port().ws_queue_limit)
231 (boost::beast::websocket::close_code::policy_error);
232 cr_.reason =
"Policy error: client is too slow.";
233 JLOG(this->j_.
info()) << cr_.reason;
234 wq_.erase(
std::next(wq_.begin()), wq_.end());
238 wq_.emplace_back(std::move(w));
243 template <
class Handler,
class Impl>
247 close(boost::beast::websocket::close_reason{});
250 template <
class Handler,
class Impl>
253 boost::beast::websocket::close_reason
const& reason)
255 if (!strand_.running_in_this_thread())
256 return post(strand_, [
self = impl().shared_from_this(), reason] {
262 impl().ws_.async_close(
266 [
self = impl().shared_from_this()](
267 boost::beast::error_code
const& ec) {
277 template<
class Handler,
class Impl>
282 if(! strand_.running_in_this_thread())
285 std::bind(&BaseWSPeer::complete, impl().shared_from_this()));
289 template<
class Handler,
class Impl>
295 return fail(ec,
"on_ws_handshake");
296 close_on_timer_ =
false;
300 template<
class Handler,
class Impl>
305 if(! strand_.running_in_this_thread())
308 std::bind(&BaseWSPeer::do_write, impl().shared_from_this()));
312 template<
class Handler,
class Impl>
318 return fail(ec,
"write");
319 auto& w = *wq_.front();
320 auto const result = w.prepare(65536,
322 impl().shared_from_this()));
323 if(boost::indeterminate(result.first))
327 impl().ws_.async_write_some(
328 static_cast<bool>(result.first),
333 &BaseWSPeer::on_write,
334 impl().shared_from_this(),
335 std::placeholders::_1)));
337 impl().ws_.async_write_some(
338 static_cast<bool>(result.first),
343 &BaseWSPeer::on_write_fin,
344 impl().shared_from_this(),
345 std::placeholders::_1)));
348 template<
class Handler,
class Impl>
354 return fail(ec,
"write_fin");
357 impl().ws_.async_close(
362 &BaseWSPeer::on_close,
363 impl().shared_from_this(),
364 std::placeholders::_1)));
365 else if(! wq_.empty())
369 template<
class Handler,
class Impl>
374 if(! strand_.running_in_this_thread())
377 std::bind(&BaseWSPeer::do_read, impl().shared_from_this()));
378 impl().ws_.async_read(
383 &BaseWSPeer::on_read,
384 impl().shared_from_this(),
385 std::placeholders::_1)));
388 template<
class Handler,
class Impl>
393 if(ec == boost::beast::websocket::error::closed)
396 return fail(ec,
"read");
397 auto const& data = rb_.data();
402 this->handler_.onWSMessage(impl().shared_from_this(), b);
403 rb_.consume(rb_.size());
406 template<
class Handler,
class Impl>
414 template<
class Handler,
class Impl>
423 timer_.expires_from_now(
424 remote_endpoint().address().is_loopback() ? timeoutLocal : timeout,
427 return fail(ec,
"start_timer");
428 timer_.async_wait(bind_executor(
432 impl().shared_from_this(),
433 std::placeholders::_1)));
437 template<
class Handler,
class Impl>
446 template<
class Handler,
class Impl>
451 if(ec == boost::asio::error::operation_aborted)
453 ping_active_ =
false;
459 template<
class Handler,
class Impl>
463 boost::beast::string_view payload)
465 if(kind == boost::beast::websocket::frame_type::pong)
467 boost::beast::string_view p(payload_.begin());
470 close_on_timer_ =
false;
471 JLOG(this->j_.
trace()) <<
476 JLOG(this->j_.
trace()) <<
482 template<
class Handler,
class Impl>
487 if(ec == boost::asio::error::operation_aborted)
491 if(! close_on_timer_ || ! ping_active_)
494 close_on_timer_ =
true;
499 impl().ws_.async_ping(
504 &BaseWSPeer::on_ping,
505 impl().shared_from_this(),
506 std::placeholders::_1)));
507 JLOG(this->j_.
trace()) <<
511 ec = boost::system::errc::make_error_code(
512 boost::system::errc::timed_out);
517 template<
class Handler,
class Impl>
518 template<
class String>
523 assert(strand_.running_in_this_thread());
527 ec != boost::asio::error::operation_aborted)
530 JLOG(this->j_.
trace()) <<
531 what <<
": " << ec.message();