20 #ifndef RIPPLE_SERVER_BASEWSPEER_H_INCLUDED
21 #define RIPPLE_SERVER_BASEWSPEER_H_INCLUDED
23 #include <ripple/basics/safe_cast.h>
24 #include <ripple/beast/utility/rngfill.h>
25 #include <ripple/crypto/csprng.h>
26 #include <ripple/protocol/BuildInfo.h>
27 #include <ripple/server/impl/BasePeer.h>
28 #include <ripple/server/impl/LowestLayer.h>
29 #include <boost/beast/core/multi_buffer.hpp>
30 #include <boost/beast/http/message.hpp>
31 #include <boost/beast/websocket.hpp>
39 template <
class Handler,
class Impl>
53 boost::beast::multi_buffer
rb_;
54 boost::beast::multi_buffer
wb_;
60 boost::beast::websocket::close_reason
cr_;
67 void(boost::beast::websocket::frame_type, boost::beast::string_view)>
71 template <
class Body,
class Headers>
75 boost::asio::executor
const& executor,
78 boost::beast::http::request<Body, Headers>&&
request,
100 boost::asio::ip::tcp::endpoint
const&
113 close(boost::beast::websocket::close_reason
const& reason)
override;
122 return *
static_cast<Impl*
>(
this);
157 boost::beast::websocket::frame_type kind,
158 boost::beast::string_view payload);
163 template <
class String>
170 template <
class Handler,
class Impl>
171 template <
class Body,
class Headers>
175 boost::asio::executor
const& executor,
178 boost::beast::http::request<Body, Headers>&& request,
180 :
BasePeer<Handler, Impl>(port, handler, executor, remote_address, journal)
181 , request_(
std::move(request))
182 , timer_(
std::move(timer))
183 , payload_(
"12345678")
187 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);
198 &BaseWSPeer::on_ping_pong,
200 std::placeholders::_1,
201 std::placeholders::_2);
202 impl().ws_.control_callback(control_callback_);
204 close_on_timer_ =
true;
205 impl().ws_.set_option(
206 boost::beast::websocket::stream_base::decorator([](
auto& res) {
208 boost::beast::http::field::server,
209 BuildInfo::getFullVersionString());
211 impl().ws_.async_accept(
216 &BaseWSPeer::on_ws_handshake,
217 impl().shared_from_this(),
218 std::placeholders::_1)));
221 template <
class Handler,
class Impl>
225 if (!strand_.running_in_this_thread())
229 &BaseWSPeer::send, impl().shared_from_this(), std::move(w)));
232 if (wq_.size() > port().ws_queue_limit)
234 cr_.code =
safe_cast<decltype(cr_.code)>(
235 boost::beast::websocket::close_code::policy_error);
236 cr_.reason =
"Policy error: client is too slow.";
237 JLOG(this->j_.
info()) << cr_.reason;
238 wq_.erase(
std::next(wq_.begin()), wq_.end());
242 wq_.emplace_back(std::move(w));
247 template <
class Handler,
class Impl>
251 close(boost::beast::websocket::close_reason{});
254 template <
class Handler,
class Impl>
257 boost::beast::websocket::close_reason
const& reason)
259 if (!strand_.running_in_this_thread())
260 return post(strand_, [
self = impl().shared_from_this(), reason] {
268 impl().ws_.async_close(
272 [
self = impl().shared_from_this()](
273 boost::beast::error_code
const& ec) {
283 template <
class Handler,
class Impl>
287 if (!strand_.running_in_this_thread())
290 std::bind(&BaseWSPeer::complete, impl().shared_from_this()));
294 template <
class Handler,
class Impl>
299 return fail(ec,
"on_ws_handshake");
300 close_on_timer_ =
false;
304 template <
class Handler,
class Impl>
308 if (!strand_.running_in_this_thread())
311 std::bind(&BaseWSPeer::do_write, impl().shared_from_this()));
315 template <
class Handler,
class Impl>
320 return fail(ec,
"write");
321 auto& w = *wq_.front();
322 auto const result = w.prepare(
323 65536,
std::bind(&BaseWSPeer::do_write, impl().shared_from_this()));
324 if (boost::indeterminate(result.first))
328 impl().ws_.async_write_some(
329 static_cast<bool>(result.first),
334 &BaseWSPeer::on_write,
335 impl().shared_from_this(),
336 std::placeholders::_1)));
338 impl().ws_.async_write_some(
339 static_cast<bool>(result.first),
344 &BaseWSPeer::on_write_fin,
345 impl().shared_from_this(),
346 std::placeholders::_1)));
349 template <
class Handler,
class Impl>
354 return fail(ec,
"write_fin");
358 impl().ws_.async_close(
363 &BaseWSPeer::on_close,
364 impl().shared_from_this(),
365 std::placeholders::_1)));
367 else if (!wq_.empty())
371 template <
class Handler,
class Impl>
375 if (!strand_.running_in_this_thread())
378 std::bind(&BaseWSPeer::do_read, impl().shared_from_this()));
379 impl().ws_.async_read(
384 &BaseWSPeer::on_read,
385 impl().shared_from_this(),
386 std::placeholders::_1)));
389 template <
class Handler,
class Impl>
393 if (ec == boost::beast::websocket::error::closed)
396 return fail(ec,
"read");
397 auto const& data = rb_.data();
401 this->handler_.onWSMessage(impl().shared_from_this(), b);
402 rb_.consume(rb_.size());
405 template <
class Handler,
class Impl>
412 template <
class Handler,
class Impl>
420 timer_.expires_from_now(
421 remote_endpoint().address().is_loopback() ? timeoutLocal : timeout, ec);
423 return fail(ec,
"start_timer");
424 timer_.async_wait(bind_executor(
428 impl().shared_from_this(),
429 std::placeholders::_1)));
433 template <
class Handler,
class Impl>
441 template <
class Handler,
class Impl>
445 if (ec == boost::asio::error::operation_aborted)
447 ping_active_ =
false;
453 template <
class Handler,
class Impl>
456 boost::beast::websocket::frame_type kind,
457 boost::beast::string_view payload)
459 if (kind == boost::beast::websocket::frame_type::pong)
461 boost::beast::string_view p(payload_.begin());
464 close_on_timer_ =
false;
465 JLOG(this->j_.
trace()) <<
"got matching pong";
469 JLOG(this->j_.
trace()) <<
"got pong";
474 template <
class Handler,
class Impl>
478 if (ec == boost::asio::error::operation_aborted)
482 if (!close_on_timer_ || !ping_active_)
485 close_on_timer_ =
true;
489 impl().ws_.async_ping(
494 &BaseWSPeer::on_ping,
495 impl().shared_from_this(),
496 std::placeholders::_1)));
497 JLOG(this->j_.
trace()) <<
"sent ping";
500 ec = boost::system::errc::make_error_code(
501 boost::system::errc::timed_out);
506 template <
class Handler,
class Impl>
507 template <
class String>
511 assert(strand_.running_in_this_thread());
514 if (!ec_ && ec != boost::asio::error::operation_aborted)
517 JLOG(this->j_.
trace()) << what <<
": " << ec.message();