diff --git a/Builds/QtCreator/rippled.pro b/Builds/QtCreator/rippled.pro index a7b6aa401..64414a370 100644 --- a/Builds/QtCreator/rippled.pro +++ b/Builds/QtCreator/rippled.pro @@ -68,6 +68,7 @@ SOURCES += \ ../../src/ripple/http/ripple_http.cpp \ ../../src/ripple/json/ripple_json.cpp \ ../../src/ripple/peerfinder/ripple_peerfinder.cpp \ + ../../src/ripple/resource/ripple_resource.cpp \ ../../src/ripple/rpc/ripple_rpc.cpp \ ../../src/ripple/sophia/ripple_sophia.c \ ../../src/ripple/sslutil/ripple_sslutil.cpp \ diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index 9b4c8d5e9..7875c6daf 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -121,6 +121,43 @@ true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + true true @@ -1656,6 +1693,24 @@ + + + + + + + + + + + + + + + + + + @@ -1836,7 +1891,6 @@ - diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index 4b895c075..497d9fa51 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -238,6 +238,15 @@ {cd1585a6-bc32-477d-88cd-275159dafa83} + + {ec26c9d0-ff17-466b-bf23-a36b8aa60717} + + + {555d2128-108e-4afa-abe5-48d1508edb1e} + + + {28a8ede0-743b-4a9a-bae1-5b2bc03ee44e} + @@ -1092,6 +1101,30 @@ [1] Ripple\types\impl + + [2] Old Ripple\ripple_app\main + + + [1] Ripple\resource + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + @@ -1649,9 +1682,6 @@ [2] Old Ripple\ripple_core\functional - - [2] Old Ripple\ripple_core\functional - [2] Old Ripple\ripple_app\main @@ -2220,6 +2250,63 @@ [1] Ripple\types\api + + [2] Old Ripple\ripple_app\main + + + [1] Ripple\resource + + + [1] Ripple\resource\api + + + [1] Ripple\resource\api + + + [1] Ripple\resource\api + + + [1] Ripple\resource\api + + + [1] Ripple\resource\api + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\api + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\api + + + [1] Ripple\resource\impl + + + [1] Ripple\resource\api + diff --git a/SConstruct b/SConstruct index ba4b92814..265d38e35 100644 --- a/SConstruct +++ b/SConstruct @@ -159,6 +159,7 @@ COMPILED_FILES.extend([ 'src/ripple/http/ripple_http.cpp', 'src/ripple/json/ripple_json.cpp', 'src/ripple/peerfinder/ripple_peerfinder.cpp', + 'src/ripple/resource/ripple_resource.cpp', 'src/ripple/rpc/ripple_rpc.cpp', 'src/ripple/sophia/ripple_sophia.c', 'src/ripple/sslutil/ripple_sslutil.cpp', diff --git a/src/BeastConfig.h b/src/BeastConfig.h index 7c6fd1920..46d9cd03e 100644 --- a/src/BeastConfig.h +++ b/src/BeastConfig.h @@ -178,4 +178,11 @@ #define RIPPLE_USE_RPC_SERVICE_MANAGER 0 #endif +// Here temporarily +// Controls whether or not the new Resource manager replaces the BlackList +// and LoadManager for measuring and controlling access to the server +#ifndef RIPPLE_USE_RESOURCE_MANAGER +#define RIPPLE_USE_RESOURCE_MANAGER 0 +#endif + #endif diff --git a/src/ripple/resource/api/Charge.h b/src/ripple/resource/api/Charge.h new file mode 100644 index 000000000..053c6b39c --- /dev/null +++ b/src/ripple/resource/api/Charge.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_CHARGE_H_INCLUDED +#define RIPPLE_RESOURCE_CHARGE_H_INCLUDED + +#include + +namespace ripple { +namespace Resource { + +/** A consumption charge. */ +class Charge +{ +public: + /** The type used to hold a consumption charge. */ + typedef int value_type; + + /** Create a new charge with no cost (yet). */ + Charge (); + + /** Create a charge with the specified cost and name. */ + Charge (value_type cost, std::string const& label = std::string()); + + /** Return the human readable label associated with the charge. */ + std::string const& label() const; + + /** Return the cost of the charge in Resource::Manager units. */ + value_type cost () const; + + /** Converts this charge into a human readable string. */ + std::string to_string () const; + +private: + value_type m_cost; + std::string m_label; +}; + +std::ostream& operator<< (std::ostream& os, Charge const& v); + +} +} + +#endif diff --git a/src/ripple/resource/api/Consumer.h b/src/ripple/resource/api/Consumer.h new file mode 100644 index 000000000..7fd2717e4 --- /dev/null +++ b/src/ripple/resource/api/Consumer.h @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_CONSUMER_H_INCLUDED +#define RIPPLE_RESOURCE_CONSUMER_H_INCLUDED + +namespace ripple { +namespace Resource { + +class Logic; + +/** An endpoint that consumes resources. */ +class Consumer +{ +private: + friend class Logic; + Consumer (Logic& logic, Entry& entry); + +public: + Consumer (); + ~Consumer (); + Consumer (Consumer const& other); + Consumer& operator= (Consumer const& other); + + /** Return a human readable string uniquely identifying this consumer. */ + std::string label (); + + /** Returns `true` if this is a privileged endpoint. */ + bool admin () const; + + /** Raise the Consumer's privilege level to a Named endpoint. + The reference to the original endpoint descriptor is released. + */ + void elevate (std::string const& name); + + /** Returns the current disposition of this consumer. + This should be checked upon creation to determine if the consumer + should be disconnected immediately. + */ + Disposition disposition() const; + + /** Apply a load charge to the consumer. */ + Disposition charge (Charge const& fee); + + /** Returns `true` if the consumer should be warned. + This consumes the warning. + */ + bool warn(); + + /** Returns `true` if the consumer should be disconnected. */ + bool disconnect(); + + /** Returns the credit balance representing consumption. */ + int balance(); + + // Private: Retrieve the entry associated with the consumer + Entry& entry(); + +private: + Logic* m_logic; + Entry* m_entry; +}; + +} +} + +#endif diff --git a/src/ripple/resource/api/Disposition.h b/src/ripple/resource/api/Disposition.h new file mode 100644 index 000000000..21b5b26b0 --- /dev/null +++ b/src/ripple/resource/api/Disposition.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_DISPOSITION_H_INCLUDED +#define RIPPLE_RESOURCE_DISPOSITION_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** The disposition of a consumer after applying a load charge. */ +enum Disposition +{ + /** No action required. */ + ok + + /** Consumer should be warned that consumption is high. */ + ,warn + + /** Consumer should be disconnected for excess consumption. */ + ,drop +}; + +} +} + +#endif diff --git a/src/ripple/resource/api/Fees.h b/src/ripple/resource/api/Fees.h new file mode 100644 index 000000000..f9b957ea4 --- /dev/null +++ b/src/ripple/resource/api/Fees.h @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_FEES_H_INCLUDED +#define RIPPLE_RESOURCE_FEES_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** Schedule of fees charged for imposing load on the server. */ +/** @{ */ +extern Charge const feeInvalidRequest; // A request that we can immediately tell is invalid +extern Charge const feeRequestNoReply; // A request that we cannot satisfy +extern Charge const feeInvalidSignature; // An object whose signature we had to check and it failed +extern Charge const feeUnwantedData; // Data we have no use for +extern Charge const feeBadProofOfWork; // Proof of work not valid +extern Charge const feeBadData; // Data we have to verify before rejecting + +// RPC loads +extern Charge const feeInvalidRPC; // An RPC request that we can immediately tell is invalid. +extern Charge const feeReferenceRPC; // A default "reference" unspecified load +extern Charge const feeExceptionRPC; // An RPC load that causes an exception +extern Charge const feeLightRPC; // A normal RPC command +extern Charge const feeLowBurdenRPC; // A slightly burdensome RPC load +extern Charge const feeMediumBurdenRPC; // A somewhat burdensome RPC load +extern Charge const feeHighBurdenRPC; // A very burdensome RPC load + +// Good things +extern Charge const feeNewTrustedNote; // A new transaction/validation/proposal we trust +extern Charge const feeNewValidTx; // A new, valid transaction +extern Charge const feeSatisfiedRequest; // Data we requested + +// Requests +extern Charge const feeRequestedData; // A request that is hard to satisfy, disk access +extern Charge const feeCheapQuery; // A query that is trivial, cached data + +// Administrative +extern Charge const feeWarning; // The cost of receiving a warning +extern Charge const feeDrop; // The cost of being dropped for excess load +/** @} */ + +/** Returns an appropriate Charge based on the legacy LoadType. */ +extern Charge legacyFee (LoadType t); + +} +} + +#endif diff --git a/src/ripple/resource/api/Gossip.h b/src/ripple/resource/api/Gossip.h new file mode 100644 index 000000000..a3ee1ea19 --- /dev/null +++ b/src/ripple/resource/api/Gossip.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_GOSSIP_H_INCLUDED +#define RIPPLE_RESOURCE_GOSSIP_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** Data format for exchanging consumption information across peers. */ +struct Gossip +{ + /** Describes a single consumer. */ + struct Item + { + int balance; + IPEndpoint address; + }; + + std::vector items; +}; + +} +} + +#endif diff --git a/src/ripple_core/functional/LoadType.h b/src/ripple/resource/api/LegacyFees.h similarity index 75% rename from src/ripple_core/functional/LoadType.h rename to src/ripple/resource/api/LegacyFees.h index c69ff949a..bf017a07c 100644 --- a/src/ripple_core/functional/LoadType.h +++ b/src/ripple/resource/api/LegacyFees.h @@ -17,36 +17,11 @@ */ //============================================================================== +#ifndef RIPPLE_RESOURCE_LEGACYFEES_H_INCLUDED +#define RIPPLE_RESOURCE_LEGACYFEES_H_INCLUDED -#ifndef RIPPLE_CORE_FUNCTIONAL_LOADTYPE_H_INCLUDED -#define RIPPLE_CORE_FUNCTIONAL_LOADTYPE_H_INCLUDED +namespace ripple { -// types of load that can be placed on the server -/** The type of load placed on the server. -*/ -/* VFALCO TODO - - Remove LT_ from each enum - - Put LoadType into a struct like this: - (Note this is modeled after boost::system::error_code::err_c) - - struct LoadType - { - enum load_c - { - invalidRequest, - //... - } - }; - - // For parameters - typedef LoadType::load_c LoadTypeParam; - - // Example of passing a LoadType: - peer->applyLoadCharge (LoadType::newTransaction); - - // Example function prototype - void applyLoadCharge (LoadTypeParam loadType); -*/ enum LoadType { // Bad things @@ -75,4 +50,6 @@ enum LoadType LT_MAX // MUST BE LAST }; +} + #endif diff --git a/src/ripple/resource/api/Manager.h b/src/ripple/resource/api/Manager.h new file mode 100644 index 000000000..cee8ce62b --- /dev/null +++ b/src/ripple/resource/api/Manager.h @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_MANAGER_H_INCLUDED +#define RIPPLE_RESOURCE_MANAGER_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** Tracks load and resource consumption. */ +class Manager : public PropertyStream::Source +{ +protected: + Manager (); + +public: + static Manager* New (Journal journal); + + virtual ~Manager() { } + + /** Create a new endpoint keyed by inbound IP address. */ + virtual Consumer newInboundEndpoint (IPEndpoint const& address) = 0; + + /** Create a new endpoint keyed by outbound IP address and port. */ + virtual Consumer newOutboundEndpoint (IPEndpoint const& address) = 0; + + /** Create a new endpoint keyed by name. */ + virtual Consumer newAdminEndpoint (std::string const& name) = 0; + + /** Extract packaged consumer information for export. */ + virtual Gossip exportConsumers () = 0; + + /** Import packaged consumer information. + @param origin An identifier that unique labels the origin. + */ + virtual void importConsumers (std::string const& origin, Gossip const& gossip) = 0; +}; + +} +} + +#endif diff --git a/src/ripple/resource/api/Types.h b/src/ripple/resource/api/Types.h new file mode 100644 index 000000000..c788d53e3 --- /dev/null +++ b/src/ripple/resource/api/Types.h @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_TYPES_H_INCLUDED +#define RIPPLE_RESOURCE_TYPES_H_INCLUDED + +namespace ripple { +namespace Resource { + +struct Key; +struct Entry; + +/** Measures seconds from an unspecified fixed reference event in the past. */ +typedef int DiscreteTime; + +} +} + +#endif diff --git a/src/ripple/resource/impl/Charge.cpp b/src/ripple/resource/impl/Charge.cpp new file mode 100644 index 000000000..c792a71a8 --- /dev/null +++ b/src/ripple/resource/impl/Charge.cpp @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +namespace ripple { +namespace Resource { + +Charge::Charge () + : m_cost (0) +{ +} + +Charge::Charge (value_type cost, std::string const& label) + : m_cost (cost) + , m_label (label) +{ +} + +std::string const& Charge::label () const +{ + return m_label; +} + +Charge::value_type Charge::cost() const +{ + return m_cost; +} + +std::string Charge::to_string () const +{ + std::stringstream ss; + ss << m_label << " ($" << m_cost << ")"; + return ss.str(); +} + +std::ostream& operator<< (std::ostream& os, Charge const& v) +{ + os << v.to_string(); + return os; +} + +} +} diff --git a/src/ripple/resource/impl/Consumer.cpp b/src/ripple/resource/impl/Consumer.cpp new file mode 100644 index 000000000..15b9b4acf --- /dev/null +++ b/src/ripple/resource/impl/Consumer.cpp @@ -0,0 +1,129 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace Resource { + +Consumer::Consumer (Logic& logic, Entry& entry) + : m_logic (&logic) + , m_entry (&entry) +{ +} + +Consumer::Consumer () + : m_logic (nullptr) + , m_entry (nullptr) +{ +} + +Consumer::Consumer (Consumer const& other) + : m_logic (other.m_logic) + , m_entry (nullptr) +{ + if (m_logic != nullptr) + { + if (other.m_entry != nullptr) + { + m_entry = other.m_entry; + m_logic->acquire (*m_entry); + } + } +} + +Consumer::~Consumer() +{ + if (m_logic != nullptr) + { + if (m_entry != nullptr) + m_logic->release (*m_entry); + } +} + +Consumer& Consumer::operator= (Consumer const& other) +{ + // remove old ref + if (m_logic != nullptr) + { + if (m_entry != nullptr) + m_logic->release (*m_entry); + } + + m_logic = other.m_logic; + m_entry = other.m_entry; + + // add new ref + if (m_logic != nullptr) + { + if (m_entry != nullptr) + m_logic->acquire (*m_entry); + } + + return *this; +} + +std::string Consumer::label () +{ + if (m_logic == nullptr) + return "(none)"; + + return m_entry->label(); +} + +bool Consumer::admin () const +{ + return m_entry->admin(); +} + +void Consumer::elevate (std::string const& name) +{ + m_entry = &m_logic->elevateToAdminEndpoint (*m_entry, name); +} + +Disposition Consumer::disposition() const +{ + return ok; +} + +Disposition Consumer::charge (Charge const& what) +{ + return m_logic->charge (*m_entry, what); +} + +bool Consumer::warn () +{ + return m_logic->warn (*m_entry); +} + +bool Consumer::disconnect () +{ + return m_logic->disconnect (*m_entry); +} + +int Consumer::balance() +{ + return m_logic->balance (*m_entry); +} + +Entry& Consumer::entry() +{ + return *m_entry; +} + +} +} diff --git a/src/ripple/resource/impl/DecayingSample.h b/src/ripple/resource/impl/DecayingSample.h new file mode 100644 index 000000000..4b603ca6c --- /dev/null +++ b/src/ripple/resource/impl/DecayingSample.h @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_DECAYINGSAMPLE_H_INCLUDED +#define RIPPLE_RESOURCE_DECAYINGSAMPLE_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** Sampling function using exponential decay to provide a continuous value. */ +template +class DecayingSample +{ +public: + typedef Value value_type; + typedef Elapsed elapsed_type; + + /** Create a default constructed sample. */ + DecayingSample () + : m_value (value_type()) + , m_when (elapsed_type()) + { + } + + /** Add a new sample. + The value is first aged according to the specified time. + */ + Value add (value_type value, elapsed_type now) + { + decay (now); + m_value += value; + return m_value / Window; + } + + /** Retrieve the current value in normalized units. + The samples are first aged according to the specified time. + */ + Value value (elapsed_type now) + { + decay (now); + return m_value / Window; + } + +private: + // Apply exponential decay based on the specified time. + void decay (elapsed_type now) + { + if (m_value == value_type()) + return; + + elapsed_type n (now - m_when); + + if (n == 0) + return; + + // A span larger than four times the window decays the + // value to an insignificant amount so just reset it. + // + if (n > 4 * Window) + { + m_value = value_type(); + return; + } + + while (n--) + m_value -= (m_value + Window - 1) / Window; + + m_when = now; + } + + // Current value in exponential units + value_type m_value; + + // Last time the aging function was applied + elapsed_type m_when; +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/Entry.h b/src/ripple/resource/impl/Entry.h new file mode 100644 index 000000000..09147f526 --- /dev/null +++ b/src/ripple/resource/impl/Entry.h @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_ENTRY_H_INCLUDED +#define RIPPLE_RESOURCE_ENTRY_H_INCLUDED + +namespace ripple { +namespace Resource { + +// An entry in the table +struct Entry : public List ::Node +{ + // Dummy argument is necessary for zero-copy construction of elements + Entry (int) + : refcount (0) + , remote_balance (0) + , disposition (ok) + , lastWarningTime (0) + , whenExpires (0) + { + } + + std::string label() const + { + switch (key->kind) + { + case kindInbound: return key->address.to_string(); + case kindOutbound: return key->address.to_string(); + case kindAdmin: return key->name; + default: + bassertfalse; + } + + return "(undefined)"; + } + + // Returns `true` if this connection is privileged + bool admin () const + { + return key->kind == kindAdmin; + } + + // Balance including remote contributions + int balance (DiscreteTime const now) + { + return local_balance.value (now) + remote_balance; + } + + // Add a charge and return normalized balance + // including contributions from imports. + int add (int charge, DiscreteTime const now) + { + return local_balance.add (charge, now) + remote_balance; + } + + // Back pointer to the map key (bit of a hack here) + Key const* key; + + // Number of Consumer references + int refcount; + + // Exponentially decaying balance of resource consumption + DecayingSample local_balance; + + // Normalized balance contribution from imports + int remote_balance; + + // Disposition + Disposition disposition; + + // Time of the last warning + DiscreteTime lastWarningTime; + + // For inactive entries, time after which this entry will be erased + DiscreteTime whenExpires; +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/Fees.cpp b/src/ripple/resource/impl/Fees.cpp new file mode 100644 index 000000000..166fd2fb8 --- /dev/null +++ b/src/ripple/resource/impl/Fees.cpp @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace Resource { + +Charge const feeInvalidRequest ( 10, "malformed request" ); +Charge const feeRequestNoReply ( 1, "unsatisfiable request" ); +Charge const feeInvalidSignature ( 100, "invalid signature" ); +Charge const feeUnwantedData ( 5, "useless data" ); +Charge const feeBadProofOfWork ( 250, "incorrect proof of work"); // DAVID: Check the cost +Charge const feeBadData ( 20, "invalid data" ); + +Charge const feeInvalidRPC ( 10, "malformed RPC" ); +Charge const feeReferenceRPC ( 2, "reference RPC" ); +Charge const feeExceptionRPC ( 10, "exceptioned RPC" ); +Charge const feeLightRPC ( 5, "light RPC" ); // DAVID: Check the cost +Charge const feeLowBurdenRPC ( 10, "low RPC" ); +Charge const feeMediumBurdenRPC ( 20, "medium RPC" ); +Charge const feeHighBurdenRPC ( 50, "heavy RPC" ); + +Charge const feeNewTrustedNote ( 10, "trusted note" ); +Charge const feeNewValidTx ( 2, "valid tx" ); +Charge const feeSatisfiedRequest ( 10, "needed data" ); + +Charge const feeRequestedData ( 5, "costly request" ); +Charge const feeCheapQuery ( 1, "trivial query" ); + +Charge const feeWarning ( 10, "received warning" ); // DAVID: Check the cost +Charge const feeDrop ( 100, "dropped" ); // DAVID: Check the cost + +} +} diff --git a/src/ripple/resource/impl/Import.h b/src/ripple/resource/impl/Import.h new file mode 100644 index 000000000..43c222633 --- /dev/null +++ b/src/ripple/resource/impl/Import.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_IMPORT_H_INCLUDED +#define RIPPLE_RESOURCE_IMPORT_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** A set of imported consumer data from a gossip origin. */ +struct Import +{ + struct Item + { + int balance; + Consumer consumer; + }; + + // Dummy argument required for zero-copy construction + Import (int = 0) + : whenExpires (0) + { + } + + // When the imported data expires + DiscreteTime whenExpires; + + // List of remote entries + std::vector items; +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/Key.h b/src/ripple/resource/impl/Key.h new file mode 100644 index 000000000..69cb60c83 --- /dev/null +++ b/src/ripple/resource/impl/Key.h @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_KEY_H_INCLUDED +#define RIPPLE_RESOURCE_KEY_H_INCLUDED + +namespace ripple { +namespace Resource { + +// The consumer key +struct Key +{ + Kind kind; + IPEndpoint address; + std::string name; + + struct hasher + { + std::size_t operator() (Key const& v) const + { + switch (v.kind) + { + case kindInbound: + case kindOutbound: + return m_addr_hash (v.address); + + case kindAdmin: + return m_name_hash (v.name); + + default: + bassertfalse; + }; + + return 0; + } + + private: + IPEndpoint::hasher m_addr_hash; + boost::hash m_name_hash; + }; + + struct key_equal + { + bool operator() (Key const& lhs, Key const& rhs) const + { + if (lhs.kind != rhs.kind) + return false; + + switch (lhs.kind) + { + case kindInbound: + case kindOutbound: + return lhs.address == rhs.address; + + case kindAdmin: + return lhs.name == rhs.name; + + default: + bassertfalse; + }; + + return false; + } + + private: + }; +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/Kind.h b/src/ripple/resource/impl/Kind.h new file mode 100644 index 000000000..b7c2d71ba --- /dev/null +++ b/src/ripple/resource/impl/Kind.h @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_KIND_H_INCLUDED +#define RIPPLE_RESOURCE_KIND_H_INCLUDED + +namespace ripple { +namespace Resource { + +// Kind of consumer +enum Kind +{ + kindInbound + ,kindOutbound + ,kindAdmin +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/LegacyFees.cpp b/src/ripple/resource/impl/LegacyFees.cpp new file mode 100644 index 000000000..a9a630e09 --- /dev/null +++ b/src/ripple/resource/impl/LegacyFees.cpp @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace Resource { + +Charge legacyFee (LoadType t) +{ + switch (t) + { + case LT_InvalidRequest: return feeInvalidRequest; + case LT_RequestNoReply: return feeRequestNoReply; + case LT_InvalidSignature: return feeInvalidSignature; + case LT_UnwantedData: return feeUnwantedData; + case LT_BadPoW: return feeBadProofOfWork; + case LT_BadData: return feeBadData; + + case LT_RPCInvalid: return feeInvalidRPC; + case LT_RPCReference: return feeReferenceRPC; + case LT_RPCException: return feeExceptionRPC; + +#if 0 + case LT_RPCLight: return feeLightRPC; + case LT_RPCBurdenLow: return feeLowBurdenRPC; + case LT_RPCBurdenMedium: return feeMediumBurdenRPC; + case LT_RPCBurdenHigh: return feeHighBurdenRPC; +#endif + + case LT_NewTrusted: return feeNewTrustedNote; + case LT_NewTransaction: return feeNewValidTx; + case LT_NeededData: return feeSatisfiedRequest; + + case LT_RequestData: return feeRequestedData; + + default: + bassertfalse; + case LT_CheapQuery: return feeCheapQuery; + }; + + return feeInvalidRequest; +}; + +} +} diff --git a/src/ripple/resource/impl/Logic.h b/src/ripple/resource/impl/Logic.h new file mode 100644 index 000000000..70a03c0f5 --- /dev/null +++ b/src/ripple/resource/impl/Logic.h @@ -0,0 +1,543 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_LOGIC_H_INCLUDED +#define RIPPLE_RESOURCE_LOGIC_H_INCLUDED + +namespace ripple { +namespace Resource { + +class Logic +{ +public: + typedef boost::unordered_map Imports; + typedef boost::unordered_map Table; + + struct State + { + // Table of all entries + Table table; + + // List of all active inbound entries + List inbound; + + // List of all active outbound entries + List outbound; + + // List of all active admin entries + List admin; + + // List of all inactve entries + List inactive; + + // All imported gossip data + Imports import_table; + }; + + typedef SharedData SharedState; + + SharedState m_state; + Journal m_journal; + + //-------------------------------------------------------------------------- + + Logic (Journal journal) + : m_journal (journal) + { +#if 1 +#if BEAST_MSVC + if (beast_isRunningUnderDebugger()) + { + m_journal.sink().set_console (true); + m_journal.sink().set_severity (Journal::kLowestSeverity); + } +#endif +#endif + } + + virtual ~Logic () + { + // These have to be cleared before the Logic is destroyed + // since their destructors call back into the class. + // Order matters here as well, the import table has to be + // destroyed before the consumer table. + // + SharedState::UnlockedAccess state (m_state); + state->import_table.clear(); + state->table.clear(); + } + + virtual DiscreteTime get_now () + { + return 0; + } + + Consumer newInboundEndpoint (IPEndpoint const& address) + { + if (isWhitelisted (address)) + return newAdminEndpoint (address.to_string()); + + Key key; + key.kind = kindInbound; + key.address = address; + + Entry* entry (nullptr); + + { + SharedState::Access state (m_state); + std::pair result ( + state->table.emplace (key, 0)); + entry = &result.first->second; + entry->key = &result.first->first; + ++entry->refcount; + if (entry->refcount == 1) + { + if (! result.second) + state->inactive.erase ( + state->inactive.iterator_to (*entry)); + state->inbound.push_back (*entry); + } + } + + m_journal.debug << "New inbound endpoint " << entry->label(); + + return Consumer (*this, *entry); + } + + Consumer newOutboundEndpoint (IPEndpoint const& address) + { + if (isWhitelisted (address)) + return newAdminEndpoint (address.to_string()); + + Key key; + key.kind = kindOutbound; + key.address = address; + + Entry* entry (nullptr); + + { + SharedState::Access state (m_state); + std::pair result ( + state->table.emplace (key, 0)); + entry = &result.first->second; + entry->key = &result.first->first; + ++entry->refcount; + if (entry->refcount == 1) + { + if (! result.second) + state->inactive.erase ( + state->inactive.iterator_to (*entry)); + state->outbound.push_back (*entry); + } + } + + m_journal.debug << "New outbound endpoint " << entry->label(); + + return Consumer (*this, *entry); + } + + Consumer newAdminEndpoint (std::string const& name) + { + Key key; + key.kind = kindAdmin; + key.name = name; + + Entry* entry (nullptr); + + { + SharedState::Access state (m_state); + std::pair result ( + state->table.emplace (key, 0)); + entry = &result.first->second; + entry->key = &result.first->first; + ++entry->refcount; + if (entry->refcount == 1) + { + if (! result.second) + state->inactive.erase ( + state->inactive.iterator_to (*entry)); + state->admin.push_back (*entry); + } + } + + m_journal.debug << "New admin endpoint " << entry->label(); + + return Consumer (*this, *entry); + } + + Entry& elevateToAdminEndpoint (Entry& prior, std::string const& name) + { + Key key; + key.kind = kindAdmin; + key.name = name; + + m_journal.info << "Elevate " << prior.label() << " to " << name; + + Entry* entry (nullptr); + + { + SharedState::Access state (m_state); + Table::iterator iter ( + state->table.find (*prior.key)); + std::pair result ( + state->table.emplace (key, 0)); + entry = &result.first->second; + entry->key = &result.first->first; + ++entry->refcount; + if (entry->refcount == 1) + { + if (! result.second) + state->inactive.erase ( + state->inactive.iterator_to (*entry)); + state->admin.push_back (*entry); + } + + release (prior, state); + } + + return *entry; + } + + Gossip exportConsumers () + { + DiscreteTime const now (get_now()); + + Gossip gossip; + SharedState::Access state (m_state); + + gossip.items.reserve (state->inbound.size()); + + for (List ::iterator iter (state->inbound.begin()); + iter != state->inbound.end(); ++iter) + { + Gossip::Item item; + item.balance = iter->local_balance.value (now); + if (item.balance >= minimumGossipBalance) + { + item.address = iter->key->address; + gossip.items.push_back (item); + } + } + + return gossip; + } + + //-------------------------------------------------------------------------- + + void importConsumers (std::string const& origin, Gossip const& gossip) + { + DiscreteTime const now (get_now()); + + { + SharedState::Access state (m_state); + std::pair result ( + state->import_table.emplace (origin, 0)); + + if (result.second) + { + // This is a new import + Import& next (result.first->second); + next.whenExpires = now + gossipExpirationSeconds; + next.items.reserve (gossip.items.size()); + for (std::vector ::const_iterator iter (gossip.items.begin()); + iter != gossip.items.end(); ++iter) + { + Import::Item item; + item.balance = iter->balance; + item.consumer = newInboundEndpoint (iter->address); + item.consumer.entry().remote_balance += item.balance; + next.items.push_back (item); + } + } + else + { + // Previous import exists so add the new remote + // balances and then deduct the old remote balances. + + Import next; + next.whenExpires = now + gossipExpirationSeconds; + next.items.reserve (gossip.items.size()); + for (std::vector ::const_iterator iter (gossip.items.begin()); + iter != gossip.items.end(); ++iter) + { + Import::Item item; + item.balance = iter->balance; + item.consumer = newInboundEndpoint (iter->address); + item.consumer.entry().remote_balance += item.balance; + next.items.push_back (item); + } + + Import& prev (result.first->second); + for (std::vector ::iterator iter (prev.items.begin()); + iter != prev.items.end(); ++iter) + { + iter->consumer.entry().remote_balance -= iter->balance; + } + + std::swap (next, prev); + } + } + } + + //-------------------------------------------------------------------------- + + bool isWhitelisted (IPEndpoint const& address) + { + if (! address.isPublic()) + return true; + + return false; + } + + // Called periodically to expire entries and groom the table. + // + void periodicActivity () + { + SharedState::Access state (m_state); + + DiscreteTime const now (get_now()); + + for (List ::iterator iter ( + state->inactive.begin()); iter != state->inactive.end();) + { + if (iter->whenExpires <= now) + { + m_journal.debug << "Expired " << iter->label(); + Table::iterator table_iter ( + state->table.find (*iter->key)); + ++iter; + erase (table_iter, state); + } + else + { + break; + } + } + + for (Imports::iterator iter (state->import_table.begin()); + iter != state->import_table.end(); ++iter) + { + Import& import (iter->second); + if (iter->second.whenExpires <= now) + { + for (std::vector ::iterator item_iter (import.items.begin()); + item_iter != import.items.end(); ++item_iter) + { + item_iter->consumer.entry().remote_balance -= item_iter->balance; + } + + iter = state->import_table.erase (iter); + } + } + } + + //-------------------------------------------------------------------------- + + // Returns the disposition based on the balance and thresholds + static Disposition disposition (int balance) + { + if (balance >= dropThreshold) + return Disposition::drop; + + if (balance >= warningThreshold) + return Disposition::warn; + + return Disposition::ok; + } + + void acquire (Entry& entry, SharedState::Access& state) + { + ++entry.refcount; + } + + void release (Entry& entry, SharedState::Access& state) + { + if (--entry.refcount == 0) + { + m_journal.debug << "Inactive " << entry.label(); + switch (entry.key->kind) + { + case kindInbound: + state->inbound.erase ( + state->inbound.iterator_to (entry)); + break; + case kindOutbound: + state->outbound.erase ( + state->outbound.iterator_to (entry)); + break; + case kindAdmin: + state->admin.erase ( + state->admin.iterator_to (entry)); + break; + default: + bassertfalse; + break; + } + state->inactive.push_back (entry); + entry.whenExpires = get_now() + secondsUntilExpiration; + } + } + + void erase (Table::iterator iter, SharedState::Access& state) + { + Entry& entry (iter->second); + bassert (entry.refcount == 0); + state->inactive.erase ( + state->inactive.iterator_to (entry)); + state->table.erase (iter); + } + + Disposition charge (Entry& entry, Charge const& fee, SharedState::Access& state) + { + DiscreteTime const now (get_now()); + int const balance (entry.add (fee.cost(), now)); + m_journal.info << "Charging " << entry.label() << " for " << fee; + return disposition (balance); + } + + bool warn (Entry& entry, SharedState::Access& state) + { + bool notify (false); + DiscreteTime const now (get_now()); + if (entry.balance (now) >= warningThreshold && now != entry.lastWarningTime) + { + charge (entry, feeWarning, state); + notify = true; + entry.lastWarningTime = now; + } + + if (notify) + m_journal.info << "Load warning: " << entry.label(); + + return notify; + } + + bool disconnect (Entry& entry, SharedState::Access& state) + { + bool drop (false); + DiscreteTime const now (get_now()); + if (entry.balance (now) >= dropThreshold) + { + charge (entry, feeDrop, state); + drop = true; + } + return drop; + } + + int balance (Entry& entry, SharedState::Access& state) + { + return entry.balance (get_now()); + } + + //-------------------------------------------------------------------------- + + void acquire (Entry& entry) + { + SharedState::Access state (m_state); + acquire (entry, state); + } + + void release (Entry& entry) + { + SharedState::Access state (m_state); + release (entry, state); + } + + Disposition charge (Entry& entry, Charge const& fee) + { + SharedState::Access state (m_state); + return charge (entry, fee, state); + } + + bool warn (Entry& entry) + { + if (entry.admin()) + return false; + + SharedState::Access state (m_state); + return warn (entry, state); + } + + bool disconnect (Entry& entry) + { + if (entry.admin()) + return false; + + SharedState::Access state (m_state); + return disconnect (entry, state); + } + + int balance (Entry& entry) + { + SharedState::Access state (m_state); + return balance (entry, state); + } + + //-------------------------------------------------------------------------- + + void writeList ( + DiscreteTime const now, + PropertyStream::Set& items, + List & list) + { + for (List ::iterator iter (list.begin()); + iter != list.end(); ++iter) + { + PropertyStream::Map item (items); + if (iter->refcount != 0) + item ["count"] = iter->refcount; + item ["name"] = iter->label(); + item ["balance"] = iter->balance(now); + if (iter->remote_balance != 0) + item ["remote_balance"] = iter->remote_balance; + } + } + + void onWrite (PropertyStream::Map& map) + { + DiscreteTime const now (get_now()); + + SharedState::Access state (m_state); + + { + PropertyStream::Set s ("inbound", map); + writeList (now, s, state->inbound); + } + + { + PropertyStream::Set s ("outbound", map); + writeList (now, s, state->outbound); + } + + { + PropertyStream::Set s ("admin", map); + writeList (now, s, state->admin); + } + + { + PropertyStream::Set s ("inactive", map); + writeList (now, s, state->inactive); + } + } +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/LogicType.h b/src/ripple/resource/impl/LogicType.h new file mode 100644 index 000000000..078c523a3 --- /dev/null +++ b/src/ripple/resource/impl/LogicType.h @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_LOGICTYPE_H_INCLUDED +#define RIPPLE_RESOURCE_LOGICTYPE_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** Provides the Clock required by Logic's get_now(). + This allows the unit tests to provide its own manual clock. +*/ +template +class LogicType : public Logic +{ +public: + explicit LogicType (Journal journal) + : Logic (journal) + { + } + + DiscreteTime get_now () + { + return m_clock(); + } + +private: + Clock m_clock; +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/Manager.cpp b/src/ripple/resource/impl/Manager.cpp new file mode 100644 index 000000000..9b2b4770f --- /dev/null +++ b/src/ripple/resource/impl/Manager.cpp @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace Resource { + +class ManagerImp + : public Manager + , public Thread +{ +public: + Journal m_journal; + LogicType m_logic; + + ManagerImp (Journal journal) + : Thread ("Resource::Manager") + , + m_journal (journal) + , m_logic (journal) + { + startThread (); + } + + ~ManagerImp () + { + stopThread (); + } + + Consumer newInboundEndpoint (IPEndpoint const& address) + { + return m_logic.newInboundEndpoint (address); + } + + Consumer newOutboundEndpoint (IPEndpoint const& address) + { + return m_logic.newOutboundEndpoint (address); + } + + Consumer newAdminEndpoint (std::string const& name) + { + return m_logic.newAdminEndpoint (name); + } + + Gossip exportConsumers () + { + return m_logic.exportConsumers(); + } + + void importConsumers (std::string const& origin, Gossip const& gossip) + { + m_logic.importConsumers (origin, gossip); + } + + //-------------------------------------------------------------------------- + + void onWrite (PropertyStream::Map& map) + { + m_logic.onWrite (map); + } + + //-------------------------------------------------------------------------- + + void run () + { + do + { + m_logic.periodicActivity(); + wait (1000); + } + while (! threadShouldExit ()); + } +}; + +//------------------------------------------------------------------------------ + +Manager::Manager () + : PropertyStream::Source ("resource") +{ +} + +//------------------------------------------------------------------------------ + +Manager* Manager::New (Journal journal) +{ + return new ManagerImp (journal); +} + +} +} diff --git a/src/ripple/resource/impl/SimpleMonotonicClock.h b/src/ripple/resource/impl/SimpleMonotonicClock.h new file mode 100644 index 000000000..88a60824d --- /dev/null +++ b/src/ripple/resource/impl/SimpleMonotonicClock.h @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_SIMPLEMONOTONICCLOCK_H_INCLUDED +#define RIPPLE_RESOURCE_SIMPLEMONOTONICCLOCK_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** Monotonically increasing time value. */ +struct SimpleMonotonicClock +{ + typedef int value_type; + + value_type operator() () const + { + return value_type (RelativeTime::fromStartup().inSeconds()); + } +}; + +} +} + +#endif diff --git a/src/ripple/resource/impl/Tests.cpp b/src/ripple/resource/impl/Tests.cpp new file mode 100644 index 000000000..f963703bc --- /dev/null +++ b/src/ripple/resource/impl/Tests.cpp @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace Resource { + +class Tests : public UnitTest +{ +public: + // A manually operated clock + class TestClock + { + public: + static int& now() + { + static int when (0); + return when; + } + + int operator() () const + { + return now(); + } + }; + + void createGossip (Gossip& gossip) + { + int const v (10 + random().nextInt (10)); + int const n (10 + random().nextInt (10)); + gossip.items.reserve (n); + for (int i = 0; i < n; ++i) + { + Gossip::Item item; + item.balance = 100 + random().nextInt (500); + item.address = IPEndpoint (IPEndpoint::V4 ( + 207, 127, 82, v + i)); + gossip.items.push_back (item); + } + } + + void testImports () + { + beginTestCase ("Imports"); + + ScopedPointer logic ( + new LogicType (journal())); + + Gossip g[5]; + + for (int i = 0; i < 5; ++i) + createGossip (g[i]); + + for (int i = 0; i < 5; ++i) + logic->importConsumers (String::fromNumber (i).toStdString(), g[i]); + + pass(); + } + + void testImport () + { + beginTestCase ("Import"); + + ScopedPointer logic ( + new LogicType (journal())); + + Gossip g; + Gossip::Item item; + item.balance = 100; + item.address = IPEndpoint (IPEndpoint::V4 (207, 127, 82, 1)); + g.items.push_back (item); + + logic->importConsumers ("g", g); + + pass(); + } + + void testCharges () + { + beginTestCase ("Charge"); + ScopedPointer logic ( + new LogicType (journal())); + + { + IPEndpoint address (IPEndpoint::from_string ("207.127.82.1")); + Consumer c (logic->newInboundEndpoint (address)); + logMessage ("Charging " + c.label() + " 10,000 units"); + c.charge (10000); + for (int i = 0; i < 128; ++i) + { + logMessage ( + "Time = " + String::fromNumber (TestClock::now()) + + ", Balance = " + String::fromNumber (c.balance())); + ++TestClock::now(); + } + } + + { + IPEndpoint address (IPEndpoint::from_string ("207.127.82.2")); + Consumer c (logic->newInboundEndpoint (address)); + logMessage ("Charging " + c.label() + " 1000 units per second"); + for (int i = 0; i < 128; ++i) + { + c.charge (1000); + logMessage ( + "Time = " + String::fromNumber (TestClock::now()) + + ", Balance = " + String::fromNumber (c.balance())); + ++TestClock::now(); + } + } + + pass(); + } + + void runTest () + { + //testCharges(); + testImports(); + //testImport(); + } + + Tests () : UnitTest ("ResourceManager", "ripple", runManual) + { + } +}; + +static Tests tests; + +} +} diff --git a/src/ripple/resource/impl/Tuning.h b/src/ripple/resource/impl/Tuning.h new file mode 100644 index 000000000..24a1b08e7 --- /dev/null +++ b/src/ripple/resource/impl/Tuning.h @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_TUNING_H_INCLUDED +#define RIPPLE_RESOURCE_TUNING_H_INCLUDED + +namespace ripple { +namespace Resource { + +/** Tunable constants. */ +enum +{ + // Balance at which a warning is issued + warningThreshold = 1000 + + // Balance at which the consumer is disconnected + ,dropThreshold = 5000 + + // The number of seconds until an inactive table item is removed + ,secondsUntilExpiration = 300 + + // The number of seconds in the exponential decay window + // (This should be a power of two) + ,decayWindowSeconds = 32 + + // The minimum balance required in order to include a load source in gossip + ,minimumGossipBalance = 100 + + // Number of seconds until imported gossip expires + ,gossipExpirationSeconds = 30 +}; + +} +} + +#endif diff --git a/src/ripple/resource/ripple_resource.cpp b/src/ripple/resource/ripple_resource.cpp new file mode 100644 index 000000000..25d8c0d88 --- /dev/null +++ b/src/ripple/resource/ripple_resource.cpp @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "ripple_resource.h" + +#include "beast/modules/beast_core/system/BeforeBoost.h" +#include + +#include "impl/Fees.cpp" +# include "impl/Kind.h" +# include "impl/Key.h" +# include "impl/DecayingSample.h" +# include "impl/Tuning.h" +# include "impl/Entry.h" +# include "impl/Import.h" +#include "impl/SimpleMonotonicClock.h" +#include "impl/Charge.cpp" +# include "impl/Logic.h" +# include "impl/LogicType.h" +#include "impl/Consumer.cpp" +#include "impl/LegacyFees.cpp" +#include "impl/Manager.cpp" +#include "impl/Tests.cpp" diff --git a/src/ripple/resource/ripple_resource.h b/src/ripple/resource/ripple_resource.h new file mode 100644 index 000000000..fd36c58c9 --- /dev/null +++ b/src/ripple/resource/ripple_resource.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RESOURCE_H_INCLUDED +#define RIPPLE_RESOURCE_H_INCLUDED + +#include "beast/modules/beast_core/beast_core.h" + +namespace ripple { +using namespace beast; +} + +# include "api/Types.h" +# include "api/Disposition.h" +# include "api/Charge.h" +# include "api/LegacyFees.h" +# include "api/Fees.h" +# include "api/Consumer.h" +# include "api/Gossip.h" +#include "api/Manager.h" + +#endif diff --git a/src/ripple/testoverlay/ripple_testoverlay.cpp b/src/ripple/testoverlay/ripple_testoverlay.cpp index 5aac668dc..d69aa1c79 100644 --- a/src/ripple/testoverlay/ripple_testoverlay.cpp +++ b/src/ripple/testoverlay/ripple_testoverlay.cpp @@ -17,13 +17,11 @@ */ //============================================================================== - #include "BeastConfig.h" #include "ripple_testoverlay.h" -namespace ripple -{ +namespace ripple { #include "impl/TestOverlay.cpp" diff --git a/src/ripple_app/ledger/InboundLedgers.cpp b/src/ripple_app/ledger/InboundLedgers.cpp index 452815d57..e0caa175d 100644 --- a/src/ripple_app/ledger/InboundLedgers.cpp +++ b/src/ripple_app/ledger/InboundLedgers.cpp @@ -128,7 +128,10 @@ void InboundLedgers::gotLedgerData (Job&, LedgerHash hash, WriteLog (lsTRACE, InboundLedger) << "Got data for ledger we're not acquiring"; if (peer) + { + peer->charge (Resource::feeInvalidRequest); peer->applyLoadCharge (LT_InvalidRequest); + } return; } @@ -143,6 +146,7 @@ void InboundLedgers::gotLedgerData (Job&, LedgerHash hash, if (packet.nodes_size () < 1) { WriteLog (lsWARNING, InboundLedger) << "Got empty base data"; + peer->charge (Resource::feeInvalidRequest); peer->applyLoadCharge (LT_InvalidRequest); return; } @@ -150,6 +154,7 @@ void InboundLedgers::gotLedgerData (Job&, LedgerHash hash, if (!ledger->takeBase (packet.nodes (0).nodedata ())) { WriteLog (lsWARNING, InboundLedger) << "Got invalid base data"; + peer->charge (Resource::feeInvalidRequest); peer->applyLoadCharge (LT_InvalidRequest); return; } @@ -185,6 +190,7 @@ void InboundLedgers::gotLedgerData (Job&, LedgerHash hash, if (packet.nodes ().size () <= 0) { WriteLog (lsINFO, InboundLedger) << "Got response with no nodes"; + peer->charge (Resource::feeInvalidRequest); peer->applyLoadCharge (LT_InvalidRequest); return; } @@ -196,6 +202,7 @@ void InboundLedgers::gotLedgerData (Job&, LedgerHash hash, if (!node.has_nodeid () || !node.has_nodedata ()) { WriteLog (lsWARNING, InboundLedger) << "Got bad node"; + peer->charge (Resource::feeInvalidRequest); peer->applyLoadCharge (LT_InvalidRequest); return; } @@ -223,6 +230,7 @@ void InboundLedgers::gotLedgerData (Job&, LedgerHash hash, } WriteLog (lsWARNING, InboundLedger) << "Not sure what ledger data we got"; + peer->charge (Resource::feeInvalidRequest); peer->applyLoadCharge (LT_InvalidRequest); } diff --git a/src/ripple_app/main/Application.cpp b/src/ripple_app/main/Application.cpp index 8ef799823..ed6a2442d 100644 --- a/src/ripple_app/main/Application.cpp +++ b/src/ripple_app/main/Application.cpp @@ -42,6 +42,8 @@ class HTTPServerLog; template <> char const* LogPartition::getPartitionName () { return "RPCServer"; } class LoadManagerLog; template <> char const* LogPartition::getPartitionName () { return "LoadManager"; } +class ResourceManagerLog; +template <> char const* LogPartition::getPartitionName () { return "ResourceManager"; } // //------------------------------------------------------------------------------ @@ -71,6 +73,9 @@ public: , m_tempNodeCache ("NodeCache", 16384, 90) , m_sleCache ("LedgerEntryCache", 4096, 120) + , m_resourceManager (add (Resource::Manager::New ( + LogJournal::get ()))) + , m_rpcServiceManager (RPC::Manager::New ( LogJournal::get ())) @@ -472,7 +477,8 @@ public: // the creation of the peer SSL context and Peers object into // the conditional. // - m_peers = add (Peers::New (m_mainIoPool, m_mainIoPool, m_peerSSLContext->get ())); + m_peers = add (Peers::New (m_mainIoPool, *m_resourceManager, + m_mainIoPool, m_peerSSLContext->get ())); // If we're not in standalone mode, // prepare ourselves for networking @@ -483,6 +489,7 @@ public: // m_peerDoors.add (PeerDoor::New ( m_mainIoPool, + *m_resourceManager, PeerDoor::sslRequired, getConfig ().PEER_IP, getConfig ().peerListeningPort, @@ -494,6 +501,7 @@ public: // Also listen on a PROXY-only port. m_peerDoors.add (PeerDoor::New ( m_mainIoPool, + *m_resourceManager, PeerDoor::sslAndPROXYRequired, getConfig ().PEER_IP, getConfig ().peerPROXYListeningPort, @@ -523,8 +531,10 @@ public: // if (!getConfig ().WEBSOCKET_IP.empty () && getConfig ().WEBSOCKET_PORT) { - m_wsPrivateDoor = WSDoor::New (getOPs(), getConfig ().WEBSOCKET_IP, - getConfig ().WEBSOCKET_PORT, false, m_wsSSLContext->get ()); + m_wsPrivateDoor = WSDoor::New (*m_resourceManager, + getOPs(), getConfig ().WEBSOCKET_IP, + getConfig ().WEBSOCKET_PORT, false, + m_wsSSLContext->get ()); if (m_wsPrivateDoor == nullptr) { @@ -541,8 +551,10 @@ public: // if (!getConfig ().WEBSOCKET_PUBLIC_IP.empty () && getConfig ().WEBSOCKET_PUBLIC_PORT) { - m_wsPublicDoor = WSDoor::New (getOPs(), getConfig ().WEBSOCKET_PUBLIC_IP, - getConfig ().WEBSOCKET_PUBLIC_PORT, true, m_wsSSLContext->get ()); + m_wsPublicDoor = WSDoor::New (*m_resourceManager, + getOPs(), getConfig ().WEBSOCKET_PUBLIC_IP, + getConfig ().WEBSOCKET_PUBLIC_PORT, true, + m_wsSSLContext->get ()); if (m_wsPublicDoor == nullptr) { @@ -839,6 +851,7 @@ private: LocalCredentials m_localCredentials; TransactionMaster m_txMaster; + ScopedPointer m_resourceManager; ScopedPointer m_rpcServiceManager; // These are Stoppable-related diff --git a/src/ripple_app/main/LoadManager.cpp b/src/ripple_app/main/LoadManager.cpp index a3f4202f5..a61fd519a 100644 --- a/src/ripple_app/main/LoadManager.cpp +++ b/src/ripple_app/main/LoadManager.cpp @@ -102,6 +102,16 @@ public: , mDeadLock (0) , mCosts (LT_MAX) { +#if 0 +#if BEAST_MSVC + if (beast_isRunningUnderDebugger()) + { + m_journal.sink().set_console (true); + m_journal.sink().set_severity (Journal::kLowestSeverity); + } +#endif +#endif + /** Flags indicating the type of load. Utilization may include any combination of: diff --git a/src/ripple_app/main/LoadManager.h b/src/ripple_app/main/LoadManager.h index 067d07eca..43d5347ed 100644 --- a/src/ripple_app/main/LoadManager.h +++ b/src/ripple_app/main/LoadManager.h @@ -17,9 +17,8 @@ */ //============================================================================== - -#ifndef RIPPLE_LOADMANAGER_H_INCLUDEd -#define RIPPLE_LOADMANAGER_H_INCLUDEd +#ifndef RIPPLE_LOADMANAGER_H_INCLUDED +#define RIPPLE_LOADMANAGER_H_INCLUDED /** Manages load sources. diff --git a/src/ripple_app/peers/Peer.cpp b/src/ripple_app/peers/Peer.cpp index 37b586b91..570d35cc0 100644 --- a/src/ripple_app/peers/Peer.cpp +++ b/src/ripple_app/peers/Peer.cpp @@ -35,8 +35,9 @@ class PeerImp : public Peer , public CountedObject { private: - // This is up here to prevent warnings about order of initializations + // These is up here to prevent warnings about order of initializations // + Resource::Manager& m_resourceManager; bool m_isInbound; public: @@ -59,12 +60,13 @@ public: return *m_socket; } - PeerImp (boost::asio::io_service& io_service, - boost::asio::ssl::context& ssl_context, - uint64 peerID, - bool inbound, - MultiSocket::Flag flags) - : m_isInbound (inbound) + PeerImp (Resource::Manager& resourceManager, + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context, + uint64 peerID, bool inbound, + MultiSocket::Flag flags) + : m_resourceManager (resourceManager) + , m_isInbound (inbound) , m_socket (MultiSocket::New ( io_service, ssl_context, flags.asBits ())) , m_strand (io_service) @@ -118,7 +120,8 @@ private: bool m_remoteAddressSet; IPEndpoint m_remoteAddress; - + Resource::Consumer m_usage; + public: static char const* getCountedObjectName () { return "Peer"; } @@ -160,6 +163,11 @@ public: void sendGetPeers (); + void charge (Resource::Charge const& fee) + { + m_usage.charge (fee); + } + void applyLoadCharge (LoadType); Json::Value getJson (); @@ -300,24 +308,6 @@ private: } else { - boost::asio::ip::address addr (getNativeSocket().remote_endpoint().address()); - - if (addr.is_v4()) - { - boost::asio::ip::address_v4::bytes_type bytes (addr.to_v4().to_bytes()); - m_remoteAddress = IPEndpoint (IPEndpoint::V4 ( - bytes[0], bytes[1], bytes[2], bytes[3]), 0); - if (! m_isInbound) - m_remoteAddress = m_remoteAddress.withPort ( - getNativeSocket().remote_endpoint().port()); - } - else - { - // TODO: Support ipv6 - bassertfalse; - } - m_remoteAddressSet = true; - if (m_socket->getFlags ().set (MultiSocket::Flag::proxy) && m_isInbound) { MultiSocket::ProxyInfo const proxyInfo (m_socket->getProxyInfo ()); @@ -336,6 +326,11 @@ private: mIpPort.first = proxyInfo.sourceAddress.toString ().toStdString (); mIpPort.second = proxyInfo.sourcePort; + if (m_isInbound) + m_usage = m_resourceManager.newInboundEndpoint (m_remoteAddress); + else + m_usage = m_resourceManager.newOutboundEndpoint (m_remoteAddress); + // Must compute mCookieHash before receiving a hello. sendHello (); startReadHeader (); @@ -359,6 +354,29 @@ private: } else { + boost::asio::ip::address addr (getNativeSocket().remote_endpoint().address()); + + if (addr.is_v4()) + { + boost::asio::ip::address_v4::bytes_type bytes (addr.to_v4().to_bytes()); + m_remoteAddress = IPEndpoint (IPEndpoint::V4 ( + bytes[0], bytes[1], bytes[2], bytes[3]), 0); + if (! m_isInbound) + m_remoteAddress = m_remoteAddress.withPort ( + getNativeSocket().remote_endpoint().port()); + } + else + { + // TODO: Support ipv6 + bassertfalse; + } + m_remoteAddressSet = true; + + if (m_isInbound) + m_usage = m_resourceManager.newInboundEndpoint (m_remoteAddress); + else + m_usage = m_resourceManager.newOutboundEndpoint (m_remoteAddress); + // Must compute mCookieHash before receiving a hello. sendHello (); startReadHeader (); @@ -1221,6 +1239,7 @@ static void checkTransaction (Job&, int flags, SerializedTransaction::pointer st if (tx->getStatus () == INVALID) { getApp().getHashRouter ().setFlag (stx->getTransactionID (), SF_BAD); + Peer::charge (peer, Resource::feeInvalidSignature); Peer::applyLoadCharge (peer, LT_InvalidSignature); return; } @@ -1234,6 +1253,7 @@ static void checkTransaction (Job&, int flags, SerializedTransaction::pointer st catch (...) { getApp().getHashRouter ().setFlag (stx->getTransactionID (), SF_BAD); + Peer::charge (peer, Resource::feeInvalidRequest); Peer::applyLoadCharge (peer, LT_InvalidRequest); } @@ -1261,6 +1281,7 @@ void PeerImp::recvTransaction (protocol::TMTransaction& packet, Application::Sco // we have seen this transaction recently if (isSetBit (flags, SF_BAD)) { + charge (Resource::feeInvalidSignature); applyLoadCharge (LT_InvalidSignature); return; } @@ -1325,6 +1346,7 @@ static void checkPropose (Job& job, boost::shared_ptr pa Peer::pointer p = peer.lock (); WriteLog (lsWARNING, Peer) << "proposal with previous ledger fails signature check: " << (p ? p->getIP () : std::string ("???")); + Peer::charge (peer, Resource::feeInvalidSignature); Peer::applyLoadCharge (peer, LT_InvalidSignature); return; } @@ -1369,6 +1391,7 @@ void PeerImp::recvPropose (const boost::shared_ptr& pack (set.signature ().size () < 56) || (set.nodepubkey ().size () > 128) || (set.signature ().size () > 128)) { WriteLog (lsWARNING, Peer) << "Received proposal is malformed"; + charge (Resource::feeInvalidSignature); applyLoadCharge (LT_InvalidSignature); return; } @@ -1376,6 +1399,7 @@ void PeerImp::recvPropose (const boost::shared_ptr& pack if (set.has_previousledger () && (set.previousledger ().size () != 32)) { WriteLog (lsWARNING, Peer) << "Received proposal is malformed"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -1437,6 +1461,7 @@ void PeerImp::recvHaveTxSet (protocol::TMHaveTransactionSet& packet) if (packet.hash ().size () != (256 / 8)) { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -1452,7 +1477,10 @@ void PeerImp::recvHaveTxSet (protocol::TMHaveTransactionSet& packet) addTxSet (hash); if (!getApp().getOPs ().hasTXSet (shared_from_this (), hash, packet.status ())) + { + charge (Resource::feeUnwantedData); applyLoadCharge (LT_UnwantedData); + } } static void checkValidation (Job&, SerializedValidation::pointer val, bool isTrusted, bool isCluster, @@ -1467,6 +1495,7 @@ static void checkValidation (Job&, SerializedValidation::pointer val, bool isTru if (!isCluster && !val->isValid (signingHash)) { WriteLog (lsWARNING, Peer) << "Validation is invalid"; + Peer::charge (peer, Resource::feeInvalidRequest); Peer::applyLoadCharge (peer, LT_InvalidRequest); return; } @@ -1505,6 +1534,7 @@ static void checkValidation (Job&, SerializedValidation::pointer val, bool isTru catch (...) { WriteLog (lsWARNING, Peer) << "Exception processing validation"; + Peer::charge (peer, Resource::feeInvalidRequest); Peer::applyLoadCharge (peer, LT_InvalidRequest); } @@ -1519,6 +1549,7 @@ void PeerImp::recvValidation (const boost::shared_ptr& p if (packet->validation ().size () < 50) { WriteLog (lsWARNING, Peer) << "Too small validation from peer"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -1535,6 +1566,7 @@ void PeerImp::recvValidation (const boost::shared_ptr& p if (closeTime > (120 + val->getFieldU32(sfSigningTime))) { WriteLog (lsTRACE, Peer) << "Validation is more than two minutes old"; + charge (Resource::feeUnwantedData); applyLoadCharge (LT_UnwantedData); return; } @@ -1558,6 +1590,7 @@ void PeerImp::recvValidation (const boost::shared_ptr& p catch (...) { WriteLog (lsWARNING, Peer) << "Exception processing validation"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); } @@ -1568,6 +1601,7 @@ void PeerImp::recvCluster (protocol::TMCluster& packet) { if (!mCluster) { + charge (Resource::feeUnwantedData); applyLoadCharge(LT_UnwantedData); return; } @@ -1863,6 +1897,7 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet) // this is an answer to a proof of work we requested if (packet.response ().size () != (256 / 8)) { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -1881,7 +1916,10 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet) // return error message // WRITEME if (r != powTOOEASY) + { + charge (Resource::feeBadProofOfWork); applyLoadCharge (LT_BadPoW); + } return; } @@ -1901,6 +1939,7 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet) if ((packet.challenge ().size () != (256 / 8)) || (packet.target ().size () != (256 / 8))) { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -1912,6 +1951,7 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet) if (!pow->isValid ()) { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2009,6 +2049,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, Application::ScopedL if ((!packet.has_ledgerhash () || packet.ledgerhash ().size () != 32)) { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); WriteLog (lsWARNING, Peer) << "invalid request for TX candidate set data"; return; @@ -2045,6 +2086,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, Application::ScopedL } WriteLog (lsERROR, Peer) << "We do not have the map our peer wants " << getIP (); + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2073,6 +2115,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, Application::ScopedL if (packet.ledgerhash ().size () != 32) { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); WriteLog (lsWARNING, Peer) << "Invalid request"; return; @@ -2129,6 +2172,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, Application::ScopedL } else { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); WriteLog (lsWARNING, Peer) << "Can't figure out what ledger they want"; return; @@ -2136,6 +2180,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, Application::ScopedL if ((!ledger) || (packet.has_ledgerseq () && (packet.ledgerseq () != ledger->getLedgerSeq ()))) { + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); if (ShouldLog (lsWARNING, Peer)) @@ -2216,6 +2261,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, Application::ScopedL if ((!map) || (packet.nodeids_size () == 0)) { WriteLog (lsWARNING, Peer) << "Can't find map or empty request"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2229,6 +2275,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, Application::ScopedL if (!mn.isValid ()) { WriteLog (lsWARNING, Peer) << "Request for invalid node: " << logMe; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2290,6 +2337,7 @@ void PeerImp::recvLedger (const boost::shared_ptr& packe if (packet.nodes ().size () <= 0) { WriteLog (lsWARNING, Peer) << "Ledger/TXset data with no nodes"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2306,6 +2354,7 @@ void PeerImp::recvLedger (const boost::shared_ptr& packe else { WriteLog (lsINFO, Peer) << "Unable to route TX/ledger data reply"; + charge (Resource::feeUnwantedData); applyLoadCharge (LT_UnwantedData); } @@ -2317,6 +2366,7 @@ void PeerImp::recvLedger (const boost::shared_ptr& packe if (packet.ledgerhash ().size () != 32) { WriteLog (lsWARNING, Peer) << "TX candidate reply with invalid hash size"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2336,6 +2386,7 @@ void PeerImp::recvLedger (const boost::shared_ptr& packe if (!node.has_nodeid () || !node.has_nodedata () || (node.nodeid ().size () != 33)) { WriteLog (lsWARNING, Peer) << "LedgerData request with invalid node ID"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2347,17 +2398,25 @@ void PeerImp::recvLedger (const boost::shared_ptr& packe SHAMapAddNode san = getApp().getOPs ().gotTXData (shared_from_this (), hash, nodeIDs, nodeData); if (san.isInvalid ()) + { + charge (Resource::feeUnwantedData); applyLoadCharge (LT_UnwantedData); + } return; } if (getApp().getInboundLedgers ().awaitLedgerData (hash)) + { getApp().getJobQueue ().addJob (jtLEDGER_DATA, "gotLedgerData", BIND_TYPE (&InboundLedgers::gotLedgerData, &getApp().getInboundLedgers (), P_1, hash, packet_ptr, boost::weak_ptr (shared_from_this ()))); + } else + { + charge (Resource::feeUnwantedData); applyLoadCharge (LT_UnwantedData); + } } void PeerImp::ledgerRange (uint32& minSeq, uint32& maxSeq) const @@ -2570,6 +2629,7 @@ void PeerImp::doFetchPack (const boost::shared_ptr& if (packet->ledgerhash ().size () != 32) { WriteLog (lsWARNING, Peer) << "FetchPack hash size malformed"; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2582,6 +2642,7 @@ void PeerImp::doFetchPack (const boost::shared_ptr& if (!haveLedger) { WriteLog (lsINFO, Peer) << "Peer requests fetch pack for ledger we don't have: " << hash; + charge (Resource::feeRequestNoReply); applyLoadCharge (LT_RequestNoReply); return; } @@ -2589,6 +2650,7 @@ void PeerImp::doFetchPack (const boost::shared_ptr& if (!haveLedger->isClosed ()) { WriteLog (lsWARNING, Peer) << "Peer requests fetch pack from open ledger: " << hash; + charge (Resource::feeInvalidRequest); applyLoadCharge (LT_InvalidRequest); return; } @@ -2598,6 +2660,7 @@ void PeerImp::doFetchPack (const boost::shared_ptr& if (!wantLedger) { WriteLog (lsINFO, Peer) << "Peer requests fetch pack for ledger whose predecessor we don't have: " << hash; + charge (Resource::feeRequestNoReply); applyLoadCharge (LT_RequestNoReply); return; } @@ -2692,9 +2755,10 @@ Json::Value PeerImp::getJson () //------------------------------------------------------------------------------ -Peer::pointer Peer::New (boost::asio::io_service& io_service, - boost::asio::ssl::context& ssl_context, uint64 id, - bool inbound, bool requirePROXYHandshake) +Peer::pointer Peer::New (Resource::Manager& resourceManager, + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context, uint64 id, + bool inbound, bool requirePROXYHandshake) { MultiSocket::Flag flags; @@ -2714,12 +2778,19 @@ Peer::pointer Peer::New (boost::asio::io_service& io_service, bassert (! requirePROXYHandshake); } - return Peer::pointer (new PeerImp ( + return Peer::pointer (new PeerImp (resourceManager, io_service, ssl_context, id, inbound, flags)); } //------------------------------------------------------------------------------ +void Peer::charge (boost::weak_ptr & peer, Resource::Charge const& fee) +{ + Peer::pointer p (peer.lock()); + if (p != nullptr) + p->charge (fee); +} + void Peer::applyLoadCharge (boost::weak_ptr & peerToPunish, LoadType loadThatWasImposed) { @@ -2730,3 +2801,4 @@ void Peer::applyLoadCharge (boost::weak_ptr & peerToPunish, p->applyLoadCharge (loadThatWasImposed); } } + diff --git a/src/ripple_app/peers/Peer.h b/src/ripple_app/peers/Peer.h index acedb07d6..386ec801b 100644 --- a/src/ripple_app/peers/Peer.h +++ b/src/ripple_app/peers/Peer.h @@ -17,10 +17,14 @@ */ //============================================================================== - #ifndef RIPPLE_PEER_H_INCLUDED #define RIPPLE_PEER_H_INCLUDED +namespace Resource { +class Charge; +class Manager; +} + // VFALCO TODO Couldn't this be a struct? typedef std::pair IPAndPortNumber; @@ -35,7 +39,8 @@ public: typedef pointer const& ref; public: - static pointer New (boost::asio::io_service& io_service, + static pointer New (Resource::Manager& resourceManager, + boost::asio::io_service& io_service, boost::asio::ssl::context& ctx, uint64 id, bool inbound, @@ -63,14 +68,15 @@ public: virtual void sendGetPeers () = 0; - virtual void applyLoadCharge (LoadType) = 0; - // VFALCO NOTE what's with this odd parameter passing? Why the static member? // /** Adjust this peer's load balance based on the type of load imposed. @note Formerly named punishPeer */ + virtual void charge (Resource::Charge const& fee) = 0; + static void charge (boost::weak_ptr & peer, Resource::Charge const& fee); + virtual void applyLoadCharge (LoadType) = 0; static void applyLoadCharge (boost::weak_ptr & peerTOCharge, LoadType loadThatWasImposed); virtual Json::Value getJson () = 0; diff --git a/src/ripple_app/peers/PeerDoor.cpp b/src/ripple_app/peers/PeerDoor.cpp index 76886c0a1..55bf5580c 100644 --- a/src/ripple_app/peers/PeerDoor.cpp +++ b/src/ripple_app/peers/PeerDoor.cpp @@ -25,9 +25,11 @@ class PeerDoorImp , public LeakChecked { public: - PeerDoorImp (Stoppable& parent, Kind kind, std::string const& ip, int port, - boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) + PeerDoorImp (Stoppable& parent, Resource::Manager& resourceManager, + Kind kind, std::string const& ip, int port, + boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) : PeerDoor (parent) + , m_resourceManager (resourceManager) , m_kind (kind) , m_ssl_context (ssl_context) , mAcceptor (io_service, boost::asio::ip::tcp::endpoint ( @@ -56,8 +58,8 @@ public: bool const requirePROXYHandshake (m_kind == sslAndPROXYRequired); Peer::pointer new_connection (Peer::New ( - mAcceptor.get_io_service (), m_ssl_context, - getApp().getPeers ().assignPeerId (), + m_resourceManager, mAcceptor.get_io_service (), + m_ssl_context, getApp().getPeers ().assignPeerId (), isInbound, requirePROXYHandshake)); mAcceptor.async_accept (new_connection->getNativeSocket (), @@ -123,6 +125,7 @@ public: } private: + Resource::Manager& m_resourceManager; Kind m_kind; boost::asio::ssl::context& m_ssl_context; boost::asio::ip::tcp::acceptor mAcceptor; @@ -138,8 +141,12 @@ PeerDoor::PeerDoor (Stoppable& parent) //------------------------------------------------------------------------------ -PeerDoor* PeerDoor::New (Stoppable& parent, Kind kind, std::string const& ip, int port, - boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) +PeerDoor* PeerDoor::New (Stoppable& parent, + Resource::Manager& resourceManager, + Kind kind, std::string const& ip, int port, + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context) { - return new PeerDoorImp (parent, kind, ip, port, io_service, ssl_context); + return new PeerDoorImp (parent, resourceManager, + kind, ip, port, io_service, ssl_context); } diff --git a/src/ripple_app/peers/PeerDoor.h b/src/ripple_app/peers/PeerDoor.h index 2629edad2..77cfe200b 100644 --- a/src/ripple_app/peers/PeerDoor.h +++ b/src/ripple_app/peers/PeerDoor.h @@ -17,10 +17,13 @@ */ //============================================================================== - #ifndef RIPPLE_PEERDOOR_H_INCLUDED #define RIPPLE_PEERDOOR_H_INCLUDED +namespace Resource { +class Manager; +} + /** Handles incoming connections from peers. */ class PeerDoor : public Stoppable { @@ -36,8 +39,11 @@ public: sslAndPROXYRequired }; - static PeerDoor* New (Stoppable& parent, Kind kind, std::string const& ip, int port, - boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context); + static PeerDoor* New (Stoppable& parent, + Resource::Manager& resourceManager, + Kind kind, std::string const& ip, int port, + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context); //virtual boost::asio::ssl::context& getSSLContext () = 0; }; diff --git a/src/ripple_app/peers/Peers.cpp b/src/ripple_app/peers/Peers.cpp index 509fadaf3..9fefb0993 100644 --- a/src/ripple_app/peers/Peers.cpp +++ b/src/ripple_app/peers/Peers.cpp @@ -42,6 +42,7 @@ public: typedef std::map::value_type vtPeer; typedef boost::unordered_map::value_type vtConMap; + Resource::Manager& m_resourceManager; ScopedPointer m_peerFinder; boost::asio::io_service& m_io_service; @@ -88,9 +89,11 @@ public: //-------------------------------------------------------------------------- PeersImp (Stoppable& parent, - boost::asio::io_service& io_service, - boost::asio::ssl::context& ssl_context) + Resource::Manager& resourceManager, + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context) : Stoppable ("Peers", parent) + , m_resourceManager (resourceManager) , m_peerFinder (add (PeerFinder::Manager::New ( *this, *this, LogJournal::get ()))) , m_io_service (io_service) @@ -193,6 +196,7 @@ public: if (peer->isConnected() && PeerFinder::PeerID (peer->getNodePublic()) == id) { + peer->charge (Resource::feeUnwantedData); peer->applyLoadCharge (LT_UnwantedData); break; } @@ -639,7 +643,7 @@ Peer::pointer PeersImp::peerConnect (const std::string& strIp, int iPort) bool const isInbound (false); bool const requirePROXYHandshake (false); - ppResult = Peer::New (m_io_service, m_ssl_context, + ppResult = Peer::New (m_resourceManager, m_io_service, m_ssl_context, ++mLastPeer, isInbound, requirePROXYHandshake); mIpMap [pipPeer] = ppResult; @@ -1093,9 +1097,10 @@ Peers::Peers () } Peers* Peers::New (Stoppable& parent, + Resource::Manager& resourceManager, boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) { - return new PeersImp (parent, io_service, ssl_context); + return new PeersImp (parent, resourceManager, io_service, ssl_context); } diff --git a/src/ripple_app/peers/Peers.h b/src/ripple_app/peers/Peers.h index 7d3849216..b4db7187b 100644 --- a/src/ripple_app/peers/Peers.h +++ b/src/ripple_app/peers/Peers.h @@ -20,6 +20,10 @@ #ifndef RIPPLE_PEERS_H_INCLUDED #define RIPPLE_PEERS_H_INCLUDED +namespace Resource { +class Manager; +} + namespace PeerFinder { class Manager; } @@ -29,8 +33,9 @@ class Peers : public PropertyStream::Source { public: static Peers* New (Stoppable& parent, - boost::asio::io_service& io_service, - boost::asio::ssl::context& context); + Resource::Manager& resourceManager, + boost::asio::io_service& io_service, + boost::asio::ssl::context& context); Peers (); diff --git a/src/ripple_app/ripple_app.cpp b/src/ripple_app/ripple_app.cpp index 960316a83..8a06dd1b9 100644 --- a/src/ripple_app/ripple_app.cpp +++ b/src/ripple_app/ripple_app.cpp @@ -36,6 +36,7 @@ // material in Ripple since it holds the Application object. #include "../ripple/http/ripple_http.h" +#include "../ripple/resource/ripple_resource.h" #include "../ripple/rpc/ripple_rpc.h" #include "../ripple/validators/ripple_validators.h" diff --git a/src/ripple_app/ripple_app.h b/src/ripple_app/ripple_app.h index 7c2441a34..bce23e9b1 100644 --- a/src/ripple_app/ripple_app.h +++ b/src/ripple_app/ripple_app.h @@ -62,8 +62,7 @@ // #include "peers/PackedMessage.h" -namespace ripple -{ +namespace ripple { // Order matters here. If you get compile errors, // reorder the include lines until the order is correct. diff --git a/src/ripple_app/ripple_app_pt2.cpp b/src/ripple_app/ripple_app_pt2.cpp index f9191e588..6fe9b7ff2 100644 --- a/src/ripple_app/ripple_app_pt2.cpp +++ b/src/ripple_app/ripple_app_pt2.cpp @@ -22,8 +22,7 @@ #include "ripple_app.h" -namespace ripple -{ +namespace ripple { #include "shamap/SHAMap.cpp" // Uses theApp #include "shamap/SHAMapItem.cpp" diff --git a/src/ripple_app/ripple_app_pt5.cpp b/src/ripple_app/ripple_app_pt5.cpp index 7ae574f83..9ed318b46 100644 --- a/src/ripple_app/ripple_app_pt5.cpp +++ b/src/ripple_app/ripple_app_pt5.cpp @@ -24,10 +24,10 @@ #include "../ripple_net/ripple_net.h" #include "../ripple/peerfinder/ripple_peerfinder.h" +#include "../ripple/resource/ripple_resource.h" #include "../ripple/validators/ripple_validators.h" -namespace ripple -{ +namespace ripple { #include "ledger/LedgerTiming.cpp" #include "ledger/AcceptedLedgerTx.cpp" diff --git a/src/ripple_app/ripple_app_pt7.cpp b/src/ripple_app/ripple_app_pt7.cpp index e53910ed6..a266ab4fd 100644 --- a/src/ripple_app/ripple_app_pt7.cpp +++ b/src/ripple_app/ripple_app_pt7.cpp @@ -22,6 +22,8 @@ #include "ripple_app.h" +#include "../ripple/resource/ripple_resource.h" + namespace ripple { diff --git a/src/ripple_app/websocket/WSConnection.cpp b/src/ripple_app/websocket/WSConnection.cpp index 195067456..1c85eb5d4 100644 --- a/src/ripple_app/websocket/WSConnection.cpp +++ b/src/ripple_app/websocket/WSConnection.cpp @@ -28,9 +28,12 @@ static std::string trimIP(const std::string& ip) //------------------------------------------------------------------------------ -WSConnection::WSConnection (InfoSub::Source& source, bool isPublic, - std::string const& remoteIP, boost::asio::io_service& io_service) +WSConnection::WSConnection (Resource::Manager& resourceManager, + Resource::Consumer usage, InfoSub::Source& source, bool isPublic, + std::string const& remoteIP, boost::asio::io_service& io_service) : InfoSub (source) + , m_resourceManager (resourceManager) + , m_usage (usage) , m_isPublic (isPublic) , m_remoteIP (remoteIP) , m_receiveQueueMutex (this, "WSConnection", __FILE__, __LINE__) @@ -110,12 +113,19 @@ void WSConnection::returnMessage (message_ptr ptr) Json::Value WSConnection::invokeCommand (Json::Value& jvRequest) { - // VFALCO TODO Make LoadManager a ctor argument +#if RIPPLE_USE_RESOURCE_MANAGER + if (m_usage.disconnect ()) + { + disconnect (); + return rpcError (rpcSLOW_DOWN); + } +#else if (getApp().getLoadManager ().shouldCutoff (m_loadSource)) { disconnect (); return rpcError (rpcSLOW_DOWN); } +#endif // Requests without "command" are invalid. // @@ -133,7 +143,11 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest) jvResult["id"] = jvRequest["id"]; } +#if RIPPLE_USE_RESOURCE_MANAGER + m_usage.charge (Resource::feeInvalidRPC); +#else getApp().getLoadManager ().applyLoadCharge (m_loadSource, LT_RPCInvalid); +#endif return jvResult; } @@ -155,6 +169,13 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest) jvResult["result"] = mRPCHandler.doCommand (jvRequest, role, &loadType); } +#if RIPPLE_USE_RESOURCE_MANAGER + m_usage.charge (Resource::legacyFee (loadType)); + if (m_usage.warn ()) + { + jvResult["warning"] = "load"; + } +#else // Debit/credit the load and see if we should include a warning. // if (getApp().getLoadManager ().applyLoadCharge (m_loadSource, loadType) && @@ -162,6 +183,7 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest) { jvResult["warning"] = "load"; } +#endif // Currently we will simply unwrap errors returned by the RPC // API, in the future maybe we can make the responses diff --git a/src/ripple_app/websocket/WSConnection.h b/src/ripple_app/websocket/WSConnection.h index 44a5b8df6..c8d58edba 100644 --- a/src/ripple_app/websocket/WSConnection.h +++ b/src/ripple_app/websocket/WSConnection.h @@ -38,8 +38,9 @@ public: protected: typedef websocketpp::message::data::ptr message_ptr; - WSConnection (InfoSub::Source& source, bool isPublic, - std::string const& remoteIP, boost::asio::io_service& io_service); + WSConnection (Resource::Manager& resourceManager, + Resource::Consumer usage, InfoSub::Source& source, bool isPublic, + std::string const& remoteIP, boost::asio::io_service& io_service); virtual ~WSConnection (); @@ -54,6 +55,8 @@ public: Json::Value invokeCommand (Json::Value& jvRequest); protected: + Resource::Manager& m_resourceManager; + Resource::Consumer m_usage; bool const m_isPublic; std::string const m_remoteIP; LockType m_receiveQueueMutex; @@ -89,9 +92,21 @@ public: typedef WSServerHandler server_type; public: - WSConnectionType (InfoSub::Source& source, server_type& serverHandler, - connection_ptr const& cpConnection) - : WSConnection (source, + static IPEndpoint from_address (boost::asio::ip::address const& addr) + { + boost::asio::ip::address_v4::bytes_type bytes (addr.to_v4().to_bytes()); + IPEndpoint ep (IPEndpoint::V4 (bytes[0], bytes[1], bytes[2], bytes[3]), 0); + return ep; + } + + WSConnectionType (Resource::Manager& resourceManager, + InfoSub::Source& source, server_type& serverHandler, + connection_ptr const& cpConnection) + : WSConnection ( + resourceManager, + resourceManager.newInboundEndpoint (from_address ( + cpConnection->get_socket ().lowest_layer ().remote_endpoint ().address ())), + source, serverHandler.getPublic (), cpConnection->get_socket ().lowest_layer ().remote_endpoint ().address ().to_string (), cpConnection->get_io_service ()) diff --git a/src/ripple_app/websocket/WSDoor.cpp b/src/ripple_app/websocket/WSDoor.cpp index 6f355f645..ba9a2bd15 100644 --- a/src/ripple_app/websocket/WSDoor.cpp +++ b/src/ripple_app/websocket/WSDoor.cpp @@ -39,11 +39,12 @@ SETUP_LOG (WSDoor) class WSDoorImp : public WSDoor, protected Thread, LeakChecked { public: - WSDoorImp (InfoSub::Source& source, - std::string const& strIp, int iPort, bool bPublic, - boost::asio::ssl::context& ssl_context) + WSDoorImp (Resource::Manager& resourceManager, + InfoSub::Source& source, std::string const& strIp, + int iPort, bool bPublic, boost::asio::ssl::context& ssl_context) : WSDoor (source) , Thread ("websocket") + , m_resourceManager (resourceManager) , m_source (source) , m_ssl_context (ssl_context) , m_endpointLock (this, "WSDoor", __FILE__, __LINE__) @@ -67,8 +68,8 @@ private: (mPublic ? "Public" : "Private") % mIp % mPort); websocketpp::server_autotls::handler::ptr handler ( - new WSServerHandler (m_source, - m_ssl_context, mPublic)); + new WSServerHandler ( + m_resourceManager, m_source, m_ssl_context, mPublic)); { ScopedLockType lock (m_endpointLock, __FILE__, __LINE__); @@ -130,7 +131,8 @@ private: private: typedef RippleRecursiveMutex LockType; typedef LockType::ScopedLockType ScopedLockType; - + + Resource::Manager& m_resourceManager; InfoSub::Source& m_source; boost::asio::ssl::context& m_ssl_context; LockType m_endpointLock; @@ -150,14 +152,16 @@ WSDoor::WSDoor (Stoppable& parent) //------------------------------------------------------------------------------ -WSDoor* WSDoor::New (InfoSub::Source& source, std::string const& strIp, - int iPort, bool bPublic, boost::asio::ssl::context& ssl_context) +WSDoor* WSDoor::New (Resource::Manager& resourceManager, + InfoSub::Source& source, std::string const& strIp, + int iPort, bool bPublic, boost::asio::ssl::context& ssl_context) { ScopedPointer door; try { - door = new WSDoorImp (source, strIp, iPort, bPublic, ssl_context); + door = new WSDoorImp (resourceManager, + source, strIp, iPort, bPublic, ssl_context); } catch (...) { diff --git a/src/ripple_app/websocket/WSDoor.h b/src/ripple_app/websocket/WSDoor.h index 78bec2a56..90afb0876 100644 --- a/src/ripple_app/websocket/WSDoor.h +++ b/src/ripple_app/websocket/WSDoor.h @@ -30,8 +30,9 @@ protected: public: virtual ~WSDoor () { } - static WSDoor* New (InfoSub::Source& source, std::string const& strIp, - int iPort, bool bPublic, boost::asio::ssl::context& ssl_context); + static WSDoor* New (Resource::Manager& resourceManager, + InfoSub::Source& source, std::string const& strIp, + int iPort, bool bPublic, boost::asio::ssl::context& ssl_context); }; #endif diff --git a/src/ripple_app/websocket/WSServerHandler.h b/src/ripple_app/websocket/WSServerHandler.h index ad91ffde3..1cb1f990d 100644 --- a/src/ripple_app/websocket/WSServerHandler.h +++ b/src/ripple_app/websocket/WSServerHandler.h @@ -56,6 +56,7 @@ public: }; private: + Resource::Manager& m_resourceManager; InfoSub::Source& m_source; protected: @@ -74,8 +75,10 @@ protected: bool const mPublic; public: - WSServerHandler (InfoSub::Source& source, boost::asio::ssl::context& ssl_context, bool bPublic) - : m_source (source) + WSServerHandler (Resource::Manager& resourceManager, + InfoSub::Source& source, boost::asio::ssl::context& ssl_context, bool bPublic) + : m_resourceManager (resourceManager) + , m_source (source) , mLock (static_cast (this), "WSServerHandler", __FILE__, __LINE__) , m_ssl_context (ssl_context) , mPublic (bPublic) @@ -181,7 +184,9 @@ public: { mMap [cpClient] = boost::make_shared < WSConnectionType - > (boost::ref (m_source), boost::ref(*this), boost::cref(cpClient)); + > (boost::ref(m_resourceManager), + boost::ref (m_source), + boost::ref(*this), boost::cref(cpClient)); } catch (...) { diff --git a/src/ripple_core/functional/LoadSource.h b/src/ripple_core/functional/LoadSource.h index af7540543..f74e3e8b0 100644 --- a/src/ripple_core/functional/LoadSource.h +++ b/src/ripple_core/functional/LoadSource.h @@ -47,16 +47,6 @@ class LoadSource { public: - // VFALCO TODO Use these dispositions - /* - enum Disposition - { - none, - shouldWarn, - shouldDrop, - }; - */ - /** Construct a load source. Sources with admin privileges have relaxed or no restrictions diff --git a/src/ripple_core/ripple_core.h b/src/ripple_core/ripple_core.h index 05dcc2cf5..6985dc5f6 100644 --- a/src/ripple_core/ripple_core.h +++ b/src/ripple_core/ripple_core.h @@ -26,6 +26,7 @@ #include "beast/beast/http/URL.h" // for Config +#include "../ripple/resource/api/LegacyFees.h" #include "nodestore/NodeStore.h" @@ -41,7 +42,6 @@ namespace ripple # include "functional/LoadMonitor.h" # include "functional/Job.h" #include "functional/JobQueue.h" -# include "functional/LoadType.h" #include "functional/LoadSource.h" }