New Resource::Manager for controlling access to server resources

This commit is contained in:
Vinnie Falco
2013-10-11 15:00:17 -07:00
parent 0902af8eb5
commit a1b487c512
53 changed files with 2494 additions and 132 deletions

View File

@@ -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 \

View File

@@ -121,6 +121,43 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\peerfinder\ripple_peerfinder.cpp" />
<ClCompile Include="..\..\src\ripple\resource\impl\Charge.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Consumer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Fees.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\LegacyFees.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Manager.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Tests.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\ripple_resource.cpp" />
<ClCompile Include="..\..\src\ripple\rpc\impl\Handler.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -1656,6 +1693,24 @@
<ClInclude Include="..\..\src\ripple\peerfinder\impl\StoreSqdb.h" />
<ClInclude Include="..\..\src\ripple\peerfinder\impl\Tuning.h" />
<ClInclude Include="..\..\src\ripple\peerfinder\ripple_peerfinder.h" />
<ClInclude Include="..\..\src\ripple\resource\api\Charge.h" />
<ClInclude Include="..\..\src\ripple\resource\api\Consumer.h" />
<ClInclude Include="..\..\src\ripple\resource\api\Disposition.h" />
<ClInclude Include="..\..\src\ripple\resource\api\Gossip.h" />
<ClInclude Include="..\..\src\ripple\resource\api\Fees.h" />
<ClInclude Include="..\..\src\ripple\resource\api\LegacyFees.h" />
<ClInclude Include="..\..\src\ripple\resource\api\Manager.h" />
<ClInclude Include="..\..\src\ripple\resource\api\Types.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\DecayingSample.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Entry.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Import.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Key.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Kind.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Logic.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\LogicType.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\SimpleMonotonicClock.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Tuning.h" />
<ClInclude Include="..\..\src\ripple\resource\ripple_resource.h" />
<ClInclude Include="..\..\src\ripple\rpc\api\Handler.h" />
<ClInclude Include="..\..\src\ripple\rpc\api\Manager.h" />
<ClInclude Include="..\..\src\ripple\rpc\api\Service.h" />
@@ -1836,7 +1891,6 @@
<ClInclude Include="..\..\src\ripple_basics\utility\Time.h" />
<ClInclude Include="..\..\src\ripple_basics\utility\UptimeTimer.h" />
<ClInclude Include="..\..\src\ripple_core\functional\LoadSource.h" />
<ClInclude Include="..\..\src\ripple_core\functional\LoadType.h" />
<ClInclude Include="..\..\src\ripple_core\functional\Config.h" />
<ClInclude Include="..\..\src\ripple_core\functional\ConfigSections.h" />
<ClInclude Include="..\..\src\ripple_core\functional\LoadFeeTrack.h" />

View File

@@ -238,6 +238,15 @@
<Filter Include="[1] Ripple\peerfinder\impl">
<UniqueIdentifier>{cd1585a6-bc32-477d-88cd-275159dafa83}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\resource">
<UniqueIdentifier>{ec26c9d0-ff17-466b-bf23-a36b8aa60717}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\resource\api">
<UniqueIdentifier>{555d2128-108e-4afa-abe5-48d1508edb1e}</UniqueIdentifier>
</Filter>
<Filter Include="[1] Ripple\resource\impl">
<UniqueIdentifier>{28a8ede0-743b-4a9a-bae1-5b2bc03ee44e}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\ripple_basics\containers\RangeSet.cpp">
@@ -1092,6 +1101,30 @@
<ClCompile Include="..\..\src\ripple\types\impl\JsonPropertyStream.cpp">
<Filter>[1] Ripple\types\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\main\BlackList.cpp">
<Filter>[2] Old Ripple\ripple_app\main</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\ripple_resource.cpp">
<Filter>[1] Ripple\resource</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Charge.cpp">
<Filter>[1] Ripple\resource\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Consumer.cpp">
<Filter>[1] Ripple\resource\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Manager.cpp">
<Filter>[1] Ripple\resource\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Tests.cpp">
<Filter>[1] Ripple\resource\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\Fees.cpp">
<Filter>[1] Ripple\resource\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\resource\impl\LegacyFees.cpp">
<Filter>[1] Ripple\resource\impl</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ripple_basics\containers\KeyCache.h">
@@ -1649,9 +1682,6 @@
<ClInclude Include="..\..\src\ripple_core\functional\LoadSource.h">
<Filter>[2] Old Ripple\ripple_core\functional</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_core\functional\LoadType.h">
<Filter>[2] Old Ripple\ripple_core\functional</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\main\LoadManager.h">
<Filter>[2] Old Ripple\ripple_app\main</Filter>
</ClInclude>
@@ -2220,6 +2250,63 @@
<ClInclude Include="..\..\src\ripple\types\api\JsonPropertyStream.h">
<Filter>[1] Ripple\types\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\main\BlackList.h">
<Filter>[2] Old Ripple\ripple_app\main</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\ripple_resource.h">
<Filter>[1] Ripple\resource</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\Disposition.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\Types.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\Charge.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\Consumer.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\Manager.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\DecayingSample.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\Kind.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\Key.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\Entry.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\SimpleMonotonicClock.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\Fees.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\Tuning.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\Logic.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\LogicType.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\Gossip.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\Import.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\resource\api\LegacyFees.h">
<Filter>[1] Ripple\resource\api</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">

View File

@@ -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',

View File

@@ -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

View File

@@ -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 <ios>
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <Item> items;
};
}
}
#endif

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <sstream>
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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 <int Window,
typename Value = int,
typename Elapsed = int>
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

View File

@@ -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 <Entry>::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 <decayWindowSeconds> 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

View File

@@ -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
}
}

View File

@@ -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 <Item> items;
};
}
}
#endif

View File

@@ -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 <std::string> 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

View File

@@ -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

View File

@@ -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;
};
}
}

View File

@@ -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 <std::string, Import> Imports;
typedef boost::unordered_map <Key, Entry, Key::hasher, Key::key_equal> Table;
struct State
{
// Table of all entries
Table table;
// List of all active inbound entries
List <Entry> inbound;
// List of all active outbound entries
List <Entry> outbound;
// List of all active admin entries
List <Entry> admin;
// List of all inactve entries
List <Entry> inactive;
// All imported gossip data
Imports import_table;
};
typedef SharedData <State> 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 <Table::iterator, bool> 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 <Table::iterator, bool> 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 <Table::iterator, bool> 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 <Table::iterator, bool> 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 <Entry>::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 <Imports::iterator, bool> 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 <Gossip::Item>::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 <Gossip::Item>::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 <Import::Item>::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 <Entry>::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 <Import::Item>::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 <Entry>& list)
{
for (List <Entry>::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

View File

@@ -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 <typename Clock>
class LogicType : public Logic
{
public:
explicit LogicType (Journal journal)
: Logic (journal)
{
}
DiscreteTime get_now ()
{
return m_clock();
}
private:
Clock m_clock;
};
}
}
#endif

View File

@@ -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 <SimpleMonotonicClock> 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);
}
}
}

View File

@@ -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

View File

@@ -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> logic (
new LogicType <TestClock> (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> logic (
new LogicType <TestClock> (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> logic (
new LogicType <TestClock> (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;
}
}

View File

@@ -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

View File

@@ -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 <boost/unordered_map.hpp>
#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"

View File

@@ -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

View File

@@ -17,13 +17,11 @@
*/
//==============================================================================
#include "BeastConfig.h"
#include "ripple_testoverlay.h"
namespace ripple
{
namespace ripple {
#include "impl/TestOverlay.cpp"

View File

@@ -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);
}

View File

@@ -42,6 +42,8 @@ class HTTPServerLog;
template <> char const* LogPartition::getPartitionName <HTTPServerLog> () { return "RPCServer"; }
class LoadManagerLog;
template <> char const* LogPartition::getPartitionName <LoadManagerLog> () { return "LoadManager"; }
class ResourceManagerLog;
template <> char const* LogPartition::getPartitionName <ResourceManagerLog> () { 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 <ResourceManagerLog> ())))
, m_rpcServiceManager (RPC::Manager::New (
LogJournal::get <RPCServiceManagerLog> ()))
@@ -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 <Resource::Manager> m_resourceManager;
ScopedPointer <RPC::Manager> m_rpcServiceManager;
// These are Stoppable-related

View File

@@ -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:

View File

@@ -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.

View File

@@ -35,8 +35,9 @@ class PeerImp : public Peer
, public CountedObject <PeerImp>
{
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<protocol::TMProposeSet> 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<protocol::TMProposeSet>& 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<protocol::TMProposeSet>& 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<protocol::TMValidation>& 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<protocol::TMValidation>& 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<protocol::TMValidation>& 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<protocol::TMLedgerData>& 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<protocol::TMLedgerData>& 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<protocol::TMLedgerData>& 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<protocol::TMLedgerData>& 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<protocol::TMLedgerData>& 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<Peer> (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<protocol::TMGetObjectByHash>&
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<protocol::TMGetObjectByHash>&
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<protocol::TMGetObjectByHash>&
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<protocol::TMGetObjectByHash>&
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>& peer, Resource::Charge const& fee)
{
Peer::pointer p (peer.lock());
if (p != nullptr)
p->charge (fee);
}
void Peer::applyLoadCharge (boost::weak_ptr <Peer>& peerToPunish,
LoadType loadThatWasImposed)
{
@@ -2730,3 +2801,4 @@ void Peer::applyLoadCharge (boost::weak_ptr <Peer>& peerToPunish,
p->applyLoadCharge (loadThatWasImposed);
}
}

View File

@@ -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 <std::string, int> 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>& peer, Resource::Charge const& fee);
virtual void applyLoadCharge (LoadType) = 0;
static void applyLoadCharge (boost::weak_ptr <Peer>& peerTOCharge, LoadType loadThatWasImposed);
virtual Json::Value getJson () = 0;

View File

@@ -25,9 +25,11 @@ class PeerDoorImp
, public LeakChecked <PeerDoorImp>
{
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);
}

View File

@@ -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;
};

View File

@@ -42,6 +42,7 @@ public:
typedef std::map<IPAndPortNumber, Peer::pointer>::value_type vtPeer;
typedef boost::unordered_map<RippleAddress, Peer::pointer>::value_type vtConMap;
Resource::Manager& m_resourceManager;
ScopedPointer <PeerFinder::Manager> 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 <PeerFinderLog> ())))
, 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);
}

View File

@@ -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 ();

View File

@@ -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"

View File

@@ -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.

View File

@@ -22,8 +22,7 @@
#include "ripple_app.h"
namespace ripple
{
namespace ripple {
#include "shamap/SHAMap.cpp" // Uses theApp
#include "shamap/SHAMapItem.cpp"

View File

@@ -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"

View File

@@ -22,6 +22,8 @@
#include "ripple_app.h"
#include "../ripple/resource/ripple_resource.h"
namespace ripple
{

View File

@@ -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

View File

@@ -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 <endpoint_type> 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 ())

View File

@@ -39,11 +39,12 @@ SETUP_LOG (WSDoor)
class WSDoorImp : public WSDoor, protected Thread, LeakChecked <WSDoorImp>
{
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 <websocketpp::server_autotls> (m_source,
m_ssl_context, mPublic));
new WSServerHandler <websocketpp::server_autotls> (
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 <WSDoor> door;
try
{
door = new WSDoorImp (source, strIp, iPort, bPublic, ssl_context);
door = new WSDoorImp (resourceManager,
source, strIp, iPort, bPublic, ssl_context);
}
catch (...)
{

View File

@@ -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

View File

@@ -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 <WSServerHandlerBase*> (this), "WSServerHandler", __FILE__, __LINE__)
, m_ssl_context (ssl_context)
, mPublic (bPublic)
@@ -181,7 +184,9 @@ public:
{
mMap [cpClient] = boost::make_shared <
WSConnectionType <endpoint_type>
> (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 (...)
{

View File

@@ -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

View File

@@ -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"
}