From 09f9720ebb7d6997e53110e822ba55c66d5ee2e6 Mon Sep 17 00:00:00 2001 From: seelabs Date: Wed, 29 Mar 2017 15:22:15 -0400 Subject: [PATCH 1/6] Correctly calculate Escrow and PayChan identifiers: This change fixes a technical flaw that resulted from using 32-bit space identifiers instead of the protocol-defined 16-bit values. Details: https://ripple.com/build/ledger-format/#tree-format --- src/ripple/protocol/impl/Indexes.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ripple/protocol/impl/Indexes.cpp b/src/ripple/protocol/impl/Indexes.cpp index c328395c1b..2c4251e193 100644 --- a/src/ripple/protocol/impl/Indexes.cpp +++ b/src/ripple/protocol/impl/Indexes.cpp @@ -317,7 +317,7 @@ escrow (AccountID const& source, std::uint32_t seq) { sha512_half_hasher h; using beast::hash_append; - hash_append(h, spaceEscrow); + hash_append(h, std::uint16_t(spaceEscrow)); hash_append(h, source); hash_append(h, seq); return { ltESCROW, static_cast(h) }; @@ -328,7 +328,7 @@ payChan (AccountID const& source, AccountID const& dst, std::uint32_t seq) { sha512_half_hasher h; using beast::hash_append; - hash_append(h, spaceXRPUChannel); + hash_append(h, std::uint16_t(spaceXRPUChannel)); hash_append(h, source); hash_append(h, dst); hash_append(h, seq); From 128f7cefb19e8fe92c5c86b5dee8c984a5c625b5 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 24 Feb 2017 19:14:03 -0500 Subject: [PATCH 2/6] Send a websocket ping before timing out in server: This fixes a problem where idle websocket client connections could be disconnected due to inactivity. --- src/ripple/server/impl/BasePeer.h | 3 +- src/ripple/server/impl/BaseWSPeer.h | 95 ++++++++++++++++++++++++---- src/ripple/server/impl/PlainWSPeer.h | 17 ----- src/ripple/server/impl/SSLWSPeer.h | 29 --------- 4 files changed, 84 insertions(+), 60 deletions(-) diff --git a/src/ripple/server/impl/BasePeer.h b/src/ripple/server/impl/BasePeer.h index 77874949cd..e7eac1adeb 100644 --- a/src/ripple/server/impl/BasePeer.h +++ b/src/ripple/server/impl/BasePeer.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ BasePeer(Port const& port, Handler& handler, , sink_(journal.sink(), [] { - static int id = 0; + static std::atomic id{0}; return "##" + std::to_string(++id) + " "; }()) , j_(sink_) diff --git a/src/ripple/server/impl/BaseWSPeer.h b/src/ripple/server/impl/BaseWSPeer.h index a1acb8e33f..24e83309f7 100644 --- a/src/ripple/server/impl/BaseWSPeer.h +++ b/src/ripple/server/impl/BaseWSPeer.h @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include #include @@ -60,6 +62,9 @@ private: bool do_close_ = false; beast::websocket::close_reason cr_; waitable_timer timer_; + bool close_on_timer_ = false; + bool ping_active_ = false; + beast::websocket::ping_data payload_; public: template @@ -152,16 +157,19 @@ protected: void on_close(error_code const& ec); - virtual - void - do_close() = 0; - void start_timer(); void cancel_timer(); + void + on_ping(error_code const& ec); + + void + on_ping_pong(bool is_pong, + beast::websocket::ping_data const& payload); + void on_timer(error_code ec); }; @@ -195,7 +203,12 @@ run() &BaseWSPeer::run, impl().shared_from_this())); impl().ws_.set_option(beast::websocket::decorate(identity{})); impl().ws_.set_option(port().pmd_options); + impl().ws_.set_option(beast::websocket::ping_callback{ + std::bind(&BaseWSPeer::on_ping_pong, this, + std::placeholders::_1, std::placeholders::_2)}); using namespace beast::asio; + start_timer(); + close_on_timer_ = true; impl().ws_.async_accept(request_, strand_.wrap(std::bind( &BaseWSPeer::on_ws_handshake, impl().shared_from_this(), placeholders::error))); @@ -212,12 +225,17 @@ send(std::shared_ptr w) return strand_.post(std::bind( &BaseWSPeer::send, impl().shared_from_this(), std::move(w))); + if(do_close_) + return; if(wq_.size() >= limit) { + JLOG(this->j_.info()) << + "closing slow client"; cr_.code = static_cast(4000); cr_.reason = "Client is too slow."; - do_close_ = true; + static_assert(limit >= 1, ""); wq_.erase(std::next(wq_.begin()), wq_.end()); + close(); return; } wq_.emplace_back(std::move(w)); @@ -233,9 +251,8 @@ close() if(! strand_.running_in_this_thread()) return strand_.post(std::bind( &BaseWSPeer::close, impl().shared_from_this())); - if(wq_.size() > 0) - do_close_ = true; - else + do_close_ = true; + if(wq_.empty()) impl().ws_.async_close({}, strand_.wrap(std::bind( &BaseWSPeer::on_close, impl().shared_from_this(), beast::asio::placeholders::error))); @@ -259,6 +276,7 @@ on_ws_handshake(error_code const& ec) { if(ec) return fail(ec, "on_ws_handshake"); + close_on_timer_ = false; do_read(); } @@ -278,7 +296,6 @@ void BaseWSPeer:: on_write(error_code const& ec) { - cancel_timer(); if(ec) return fail(ec, "write"); auto& w = *wq_.front(); @@ -329,7 +346,6 @@ do_read() impl().ws_.async_read(op_, rb_, strand_.wrap( std::bind(&BaseWSPeer::on_read, impl().shared_from_this(), placeholders::error))); - cancel_timer(); } template @@ -338,7 +354,7 @@ BaseWSPeer:: on_read(error_code const& ec) { if(ec == beast::websocket::error::closed) - return do_close(); + return on_close({}); if(ec) return fail(ec, "read"); auto const& data = rb_.data(); @@ -355,7 +371,7 @@ void BaseWSPeer:: on_close(error_code const& ec) { - // great + cancel_timer(); } template @@ -387,7 +403,41 @@ cancel_timer() timer_.cancel(ec); } -// Called when session times out +template +void +BaseWSPeer:: +on_ping(error_code const& ec) +{ + if(ec == boost::asio::error::operation_aborted) + return; + ping_active_ = false; + if(! ec) + return; + fail(ec, "on_ping"); +} + +template +void +BaseWSPeer:: +on_ping_pong(bool is_pong, + beast::websocket::ping_data const& payload) +{ + if(is_pong) + { + if(payload == payload_) + { + close_on_timer_ = false; + JLOG(this->j_.trace()) << + "got matching pong"; + } + else + { + JLOG(this->j_.trace()) << + "got pong"; + } + } +} + template void BaseWSPeer:: @@ -396,10 +446,29 @@ on_timer(error_code ec) if(ec == boost::asio::error::operation_aborted) return; if(! ec) + { + if(! close_on_timer_ || !ping_active_) + { + start_timer(); + ping_active_ = true; + // cryptographic is probably overkill.. + beast::rngfill(payload_.begin(), + payload_.size(), crypto_prng()); + impl().ws_.async_ping(payload_, + strand_.wrap(std::bind( + &BaseWSPeer::on_ping, + impl().shared_from_this(), + std::placeholders::_1))); + JLOG(this->j_.trace()) << + "sent pong"; + return; + } ec = boost::system::errc::make_error_code( boost::system::errc::timed_out); + } fail(ec, "timer"); } + } // ripple #endif diff --git a/src/ripple/server/impl/PlainWSPeer.h b/src/ripple/server/impl/PlainWSPeer.h index 8e84140a54..18f8ae4cad 100644 --- a/src/ripple/server/impl/PlainWSPeer.h +++ b/src/ripple/server/impl/PlainWSPeer.h @@ -30,7 +30,6 @@ class PlainWSPeer : public BaseWSPeer> , public std::enable_shared_from_this> { -private: friend class BasePeer; friend class BaseWSPeer; @@ -51,10 +50,6 @@ public: beast::http::request&& request, socket_type&& socket, beast::Journal journal); - -private: - void - do_close() override; }; //------------------------------------------------------------------------------ @@ -75,18 +70,6 @@ PlainWSPeer( { } -template -void -PlainWSPeer:: -do_close() -{ - error_code ec; - auto& sock = ws_.next_layer(); - sock.shutdown(socket_type::shutdown_both, ec); - if(ec) - return this->fail(ec, "do_close"); -} - } // ripple #endif diff --git a/src/ripple/server/impl/SSLWSPeer.h b/src/ripple/server/impl/SSLWSPeer.h index 2f208217ee..383ebfd284 100644 --- a/src/ripple/server/impl/SSLWSPeer.h +++ b/src/ripple/server/impl/SSLWSPeer.h @@ -34,7 +34,6 @@ class SSLWSPeer : public BaseWSPeer> , public std::enable_shared_from_this> { -private: friend class BasePeer; friend class BaseWSPeer; @@ -58,13 +57,6 @@ public: std::unique_ptr< beast::asio::ssl_bundle>&& ssl_bundle, beast::Journal journal); - -private: - void - do_close() override; - - void - on_shutdown(error_code ec); }; //------------------------------------------------------------------------------ @@ -88,27 +80,6 @@ SSLWSPeer( { } -template -void -SSLWSPeer:: -do_close() -{ - //start_timer(); - using namespace beast::asio; - ws_.next_layer().async_shutdown( - this->strand_.wrap(std::bind(&SSLWSPeer::on_shutdown, - this->shared_from_this(), placeholders::error))); -} - -template -void -SSLWSPeer:: -on_shutdown(error_code ec) -{ - //cancel_timer(); - ws_.lowest_layer().close(ec); -} - } // ripple #endif From 8b43d67a73af0b0e574b0375e50216756cfc5d8c Mon Sep 17 00:00:00 2001 From: Miguel Portilla Date: Fri, 24 Mar 2017 17:36:19 -0400 Subject: [PATCH 3/6] Cancel websocket timer on failure: This fixes a problem where the timeout timer would not be canceled with some errors. fix #2026 --- src/ripple/server/impl/BasePeer.h | 25 +------------------- src/ripple/server/impl/BaseWSPeer.h | 36 +++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/ripple/server/impl/BasePeer.h b/src/ripple/server/impl/BasePeer.h index e7eac1adeb..ba4efc6079 100644 --- a/src/ripple/server/impl/BasePeer.h +++ b/src/ripple/server/impl/BasePeer.h @@ -50,7 +50,6 @@ protected: boost::asio::io_service::work work_; boost::asio::io_service::strand strand_; - error_code ec_; public: BasePeer(Port const& port, Handler& handler, @@ -61,11 +60,6 @@ public: void close() override; -protected: - template - void - fail(error_code ec, String const& what); - private: Impl& impl() @@ -87,7 +81,7 @@ BasePeer(Port const& port, Handler& handler, , remote_address_(remote_address) , sink_(journal.sink(), [] - { + { static std::atomic id{0}; return "##" + std::to_string(++id) + " "; }()) @@ -109,23 +103,6 @@ close() impl().ws_.lowest_layer().close(ec); } -template -template -void -BasePeer:: -fail(error_code ec, String const& what) -{ - assert(strand_.running_in_this_thread()); - if(! ec_ && - ec != boost::asio::error::operation_aborted) - { - ec_ = ec; - JLOG(j_.trace()) << - what << ": " << ec.message(); - impl().ws_.lowest_layer().close(ec); - } -} - } // ripple #endif diff --git a/src/ripple/server/impl/BaseWSPeer.h b/src/ripple/server/impl/BaseWSPeer.h index 24e83309f7..124026e5af 100644 --- a/src/ripple/server/impl/BaseWSPeer.h +++ b/src/ripple/server/impl/BaseWSPeer.h @@ -42,15 +42,8 @@ protected: using error_code = boost::system::error_code; using endpoint_type = boost::asio::ip::tcp::endpoint; using waitable_timer = boost::asio::basic_waitable_timer ; - using BasePeer::fail; using BasePeer::strand_; - enum - { - // Max seconds without completing a message - timeoutSeconds = 30 - }; - private: friend class BasePeer; @@ -65,6 +58,7 @@ private: bool close_on_timer_ = false; bool ping_active_ = false; beast::websocket::ping_data payload_; + error_code ec_; public: template @@ -172,6 +166,10 @@ protected: void on_timer(error_code ec); + + template + void + fail(error_code ec, String const& what); }; //------------------------------------------------------------------------------ @@ -447,9 +445,10 @@ on_timer(error_code ec) return; if(! ec) { - if(! close_on_timer_ || !ping_active_) + if(! close_on_timer_ || ! ping_active_) { start_timer(); + close_on_timer_ = true; ping_active_ = true; // cryptographic is probably overkill.. beast::rngfill(payload_.begin(), @@ -460,7 +459,7 @@ on_timer(error_code ec) impl().shared_from_this(), std::placeholders::_1))); JLOG(this->j_.trace()) << - "sent pong"; + "sent ping"; return; } ec = boost::system::errc::make_error_code( @@ -469,6 +468,25 @@ on_timer(error_code ec) fail(ec, "timer"); } +template +template +void +BaseWSPeer:: +fail(error_code ec, String const& what) +{ + assert(strand_.running_in_this_thread()); + + cancel_timer(); + if(! ec_ && + ec != boost::asio::error::operation_aborted) + { + ec_ = ec; + JLOG(this->j_.trace()) << + what << ": " << ec.message(); + impl().ws_.lowest_layer().close(ec); + } +} + } // ripple #endif From 0d4fe469c6b0ba47645b53930e74248ff789fe75 Mon Sep 17 00:00:00 2001 From: seelabs Date: Wed, 29 Mar 2017 15:41:43 -0400 Subject: [PATCH 4/6] Set version to 0.60.1 --- src/ripple/protocol/impl/BuildInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ripple/protocol/impl/BuildInfo.cpp b/src/ripple/protocol/impl/BuildInfo.cpp index d7c4e09041..0d8e2aab29 100644 --- a/src/ripple/protocol/impl/BuildInfo.cpp +++ b/src/ripple/protocol/impl/BuildInfo.cpp @@ -33,7 +33,7 @@ char const* const versionString = // The build version number. You must edit this for each release // and follow the format described at http://semver.org/ // - "0.60.0" + "0.60.1" #if defined(DEBUG) || defined(SANITIZER) "+" From 4ff40d4954dfaa237c8b708c2126cb39566776da Mon Sep 17 00:00:00 2001 From: seelabs Date: Thu, 30 Mar 2017 11:39:19 -0400 Subject: [PATCH 5/6] Enforce rippling constraints between offers and direct steps --- src/ripple/app/paths/impl/DirectStep.cpp | 15 +++++++++++++-- src/ripple/ledger/View.h | 3 +++ src/ripple/ledger/impl/View.cpp | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/ripple/app/paths/impl/DirectStep.cpp b/src/ripple/app/paths/impl/DirectStep.cpp index 9144050094..61e8977312 100644 --- a/src/ripple/app/paths/impl/DirectStep.cpp +++ b/src/ripple/app/paths/impl/DirectStep.cpp @@ -589,6 +589,7 @@ TER DirectStepI::check (StrandContext const& ctx) const return temBAD_PATH; } + auto sleLine = ctx.view.read (keylet::line (src_, dst_, currency_)); { auto sleSrc = ctx.view.read (keylet::account (src_)); if (!sleSrc) @@ -599,8 +600,6 @@ TER DirectStepI::check (StrandContext const& ctx) const return terNO_ACCOUNT; } - auto sleLine = ctx.view.read (keylet::line (src_, dst_, currency_)); - if (!sleLine) { JLOG (j_.trace()) << "DirectStepI: No credit line. " << *this; @@ -637,6 +636,18 @@ TER DirectStepI::check (StrandContext const& ctx) const if (ter != tesSUCCESS) return ter; } + + if (fix1449(ctx.view.info().parentCloseTime)) + { + if (ctx.prevStep->bookStepBook()) + { + auto const noRippleSrcToDst = + ((*sleLine)[sfFlags] & + ((src_ > dst_) ? lsfHighNoRipple : lsfLowNoRipple)); + if (noRippleSrcToDst) + return terNO_RIPPLE; + } + } } { diff --git a/src/ripple/ledger/View.h b/src/ripple/ledger/View.h index 95d77dacd5..d6717b5a27 100644 --- a/src/ripple/ledger/View.h +++ b/src/ripple/ledger/View.h @@ -347,6 +347,9 @@ bool amendmentRIPD1298 (NetClock::time_point const closeTime); NetClock::time_point const& amendmentRIPD1443SoTime (); bool amendmentRIPD1443 (NetClock::time_point const closeTime); +NetClock::time_point const& fix1449SoTime (); +bool fix1449 (NetClock::time_point const closeTime); + } // ripple #endif diff --git a/src/ripple/ledger/impl/View.cpp b/src/ripple/ledger/impl/View.cpp index 89aadb0890..d2bd90caa7 100644 --- a/src/ripple/ledger/impl/View.cpp +++ b/src/ripple/ledger/impl/View.cpp @@ -86,6 +86,20 @@ bool amendmentRIPD1443 (NetClock::time_point const closeTime) return closeTime > amendmentRIPD1443SoTime(); } +NetClock::time_point const& fix1449SoTime () +{ + using namespace std::chrono_literals; + // Thurs, Mar 30, 2017 01:00:00pm PDT + static NetClock::time_point const soTime{544219200s}; + + return soTime; +} + +bool fix1449 (NetClock::time_point const closeTime) +{ + return closeTime > fix1449SoTime(); +} + // VFALCO NOTE A copy of the other one for now /** Maximum number of entries in a directory page A change would be protocol-breaking. From 7cd4d7889779e6418270c8af89386194efbef24b Mon Sep 17 00:00:00 2001 From: seelabs Date: Thu, 30 Mar 2017 14:25:41 -0400 Subject: [PATCH 6/6] Set version to 0.60.2 --- src/ripple/protocol/impl/BuildInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ripple/protocol/impl/BuildInfo.cpp b/src/ripple/protocol/impl/BuildInfo.cpp index 0d8e2aab29..5ec608a70e 100644 --- a/src/ripple/protocol/impl/BuildInfo.cpp +++ b/src/ripple/protocol/impl/BuildInfo.cpp @@ -33,7 +33,7 @@ char const* const versionString = // The build version number. You must edit this for each release // and follow the format described at http://semver.org/ // - "0.60.1" + "0.60.2" #if defined(DEBUG) || defined(SANITIZER) "+"