diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ba513f0..a0b4a862 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,7 @@ if(BUILD_TESTS) unittests/rpc/BaseTests.cpp unittests/rpc/RPCHelpersTest.cpp unittests/rpc/CountersTest.cpp + unittests/rpc/AdminVerificationTest.cpp ## RPC handlers unittests/rpc/handlers/DefaultProcessorTests.cpp unittests/rpc/handlers/TestHandlerTests.cpp diff --git a/src/backend/SimpleCache.cpp b/src/backend/SimpleCache.cpp index 6337a22b..51f6fc1a 100644 --- a/src/backend/SimpleCache.cpp +++ b/src/backend/SimpleCache.cpp @@ -96,9 +96,9 @@ SimpleCache::getPredecessor(ripple::uint256 const& key, uint32_t seq) const std::optional SimpleCache::get(ripple::uint256 const& key, uint32_t seq) const { + std::shared_lock lck{mtx_}; if (seq > latestSeq_) return {}; - std::shared_lock lck{mtx_}; objectReqCounter_++; auto e = map_.find(key); if (e == map_.end()) diff --git a/src/backend/Types.h b/src/backend/Types.h index 406846b6..fe6e4dd3 100644 --- a/src/backend/Types.h +++ b/src/backend/Types.h @@ -56,8 +56,8 @@ struct TransactionAndMetadata { Blob transaction; Blob metadata; - std::uint32_t ledgerSequence; - std::uint32_t date; + std::uint32_t ledgerSequence = 0; + std::uint32_t date = 0; TransactionAndMetadata() = default; TransactionAndMetadata( diff --git a/src/main/main.cpp b/src/main/main.cpp index b49dbb7c..8ce16d3a 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/src/rpc/Counters.cpp b/src/rpc/Counters.cpp index 11ba6c11..38bd2522 100644 --- a/src/rpc/Counters.cpp +++ b/src/rpc/Counters.cpp @@ -19,7 +19,6 @@ #include #include -#include #include namespace RPC { diff --git a/src/rpc/RPC.cpp b/src/rpc/RPC.cpp index 5a54c71e..51e0b88b 100644 --- a/src/rpc/RPC.cpp +++ b/src/rpc/RPC.cpp @@ -18,8 +18,7 @@ //============================================================================== #include -#include -#include +#include #include #include #include @@ -32,12 +31,6 @@ using namespace std; using namespace clio; using namespace RPC; -// local to compilation unit loggers -namespace { -clio::Logger gPerfLog{"Performance"}; -clio::Logger gLog{"RPC"}; -} // namespace - namespace RPC { optional @@ -92,165 +85,4 @@ make_HttpContext( return make_optional(yc, command, 1, array.at(0).as_object(), nullptr, tagFactory, range, clientIp); } -static unordered_set forwardCommands{ - "submit", - "submit_multisigned", - "fee", - "ledger_closed", - "ledger_current", - "ripple_path_find", - "manifest", - "channel_authorize", - "channel_verify"}; - -RPCEngine::RPCEngine( - std::shared_ptr const& backend, - std::shared_ptr const& subscriptions, - std::shared_ptr const& balancer, - std::shared_ptr const& etl, - clio::DOSGuard const& dosGuard, - WorkQueue& workQueue, - Counters& counters, - std::shared_ptr const& handlerProvider) - : backend_{backend} - , subscriptions_{subscriptions} - , balancer_{balancer} - , dosGuard_{std::cref(dosGuard)} - , workQueue_{std::ref(workQueue)} - , counters_{std::ref(counters)} - , handlerTable_{handlerProvider} -{ -} - -std::shared_ptr -RPCEngine::make_RPCEngine( - clio::Config const& config, - std::shared_ptr const& backend, - std::shared_ptr const& subscriptions, - std::shared_ptr const& balancer, - std::shared_ptr const& etl, - clio::DOSGuard const& dosGuard, - WorkQueue& workQueue, - Counters& counters, - std::shared_ptr const& handlerProvider) -{ - return std::make_shared( - backend, subscriptions, balancer, etl, dosGuard, workQueue, counters, handlerProvider); -} - -bool -RPCEngine::validHandler(string const& method) const -{ - return handlerTable_.contains(method) || forwardCommands.contains(method); -} - -bool -RPCEngine::isClioOnly(string const& method) const -{ - return handlerTable_.isClioOnly(method); -} - -bool -RPCEngine::shouldForwardToRippled(Web::Context const& ctx) const -{ - auto request = ctx.params; - - if (isClioOnly(ctx.method)) - return false; - - if (forwardCommands.find(ctx.method) != forwardCommands.end()) - return true; - - if (specifiesCurrentOrClosedLedger(request)) - return true; - - if (ctx.method == "account_info" && request.contains("queue") && request.at("queue").as_bool()) - return true; - - return false; -} - -Result -RPCEngine::buildResponse(Web::Context const& ctx) -{ - if (shouldForwardToRippled(ctx)) - { - auto toForward = ctx.params; - toForward["command"] = ctx.method; - - auto const res = balancer_->forwardToRippled(toForward, ctx.clientIp, ctx.yield); - notifyForwarded(ctx.method); - - if (!res) - return Status{RippledError::rpcFAILED_TO_FORWARD}; - - return *res; - } - - if (backend_->isTooBusy()) - { - gLog.error() << "Database is too busy. Rejecting request"; - return Status{RippledError::rpcTOO_BUSY}; - } - - auto const method = handlerTable_.getHandler(ctx.method); - if (!method) - return Status{RippledError::rpcUNKNOWN_COMMAND}; - - try - { - gPerfLog.debug() << ctx.tag() << " start executing rpc `" << ctx.method << '`'; - - auto const isAdmin = ctx.clientIp == "127.0.0.1"; // TODO: this should be a strategy - auto const context = Context{ctx.yield, ctx.session, isAdmin, ctx.clientIp}; - auto const v = (*method).process(ctx.params, context); - - gPerfLog.debug() << ctx.tag() << " finish executing rpc `" << ctx.method << '`'; - - if (v) - return v->as_object(); - else - return Status{v.error()}; - } - catch (InvalidParamsError const& err) - { - return Status{RippledError::rpcINVALID_PARAMS, err.what()}; - } - catch (AccountNotFoundError const& err) - { - return Status{RippledError::rpcACT_NOT_FOUND, err.what()}; - } - catch (Backend::DatabaseTimeout const& t) - { - gLog.error() << "Database timeout"; - return Status{RippledError::rpcTOO_BUSY}; - } - catch (exception const& err) - { - gLog.error() << ctx.tag() << " caught exception: " << err.what(); - return Status{RippledError::rpcINTERNAL}; - } -} - -void -RPCEngine::notifyComplete(std::string const& method, std::chrono::microseconds const& duration) -{ - if (validHandler(method)) - counters_.get().rpcComplete(method, duration); -} - -void -RPCEngine::notifyErrored(std::string const& method) -{ - if (validHandler(method)) - counters_.get().rpcErrored(method); -} - -void -RPCEngine::notifyForwarded(std::string const& method) -{ - if (validHandler(method)) - counters_.get().rpcForwarded(method); -} - } // namespace RPC diff --git a/src/rpc/RPC.h b/src/rpc/RPC.h index 13041ec2..a6c9f4d8 100644 --- a/src/rpc/RPC.h +++ b/src/rpc/RPC.h @@ -20,34 +20,24 @@ #pragma once #include -#include #include -#include #include -#include -#include -#include #include -#include #include #include #include +#include #include #include -#include -#include /* * This file contains various classes necessary for executing RPC handlers. - * Context gives the handlers access to various other parts of the application - * Status is used to report errors. - * And lastly, there are various functions for making Contexts, Statuses and - * serializing Status to JSON. - * This file is meant to contain any class or function that code outside of the - * rpc folder needs to use. For helper functions or classes used within the rpc - * folder, use RPCHelpers.h. + * Context gives the handlers access to various other parts of the application Status is used to report errors. + * And lastly, there are various functions for making Contexts, Statuses and serializing Status to JSON. + * This file is meant to contain any class or function that code outside of the rpc folder needs to use. For helper + * functions or classes used within the rpc folder, use RPCHelpers.h. */ class WsBase; @@ -57,26 +47,6 @@ class ReportingETL; namespace RPC { -struct AccountCursor -{ - ripple::uint256 index; - std::uint32_t hint; - - std::string - toString() const - { - return ripple::strHex(index) + "," + std::to_string(hint); - } - - bool - isNonZero() const - { - return index.isNonZero() || hint != 0; - } -}; - -using Result = std::variant; - std::optional make_WsContext( boost::asio::yield_context& yc, @@ -94,114 +64,4 @@ make_HttpContext( Backend::LedgerRange const& range, std::string const& clientIp); -/** - * @brief The RPC engine that ties all RPC-related functionality together - */ -class RPCEngine -{ - std::shared_ptr backend_; - std::shared_ptr subscriptions_; - std::shared_ptr balancer_; - std::reference_wrapper dosGuard_; - std::reference_wrapper workQueue_; - std::reference_wrapper counters_; - - HandlerTable handlerTable_; - -public: - RPCEngine( - std::shared_ptr const& backend, - std::shared_ptr const& subscriptions, - std::shared_ptr const& balancer, - std::shared_ptr const& etl, - clio::DOSGuard const& dosGuard, - WorkQueue& workQueue, - Counters& counters, - std::shared_ptr const& handlerProvider); - - static std::shared_ptr - make_RPCEngine( - clio::Config const& config, - std::shared_ptr const& backend, - std::shared_ptr const& subscriptions, - std::shared_ptr const& balancer, - std::shared_ptr const& etl, - clio::DOSGuard const& dosGuard, - WorkQueue& workQueue, - Counters& counters, - std::shared_ptr const& handlerProvider); - - /** - * @brief Main request processor routine - * @param ctx The @ref Context of the request - */ - Result - buildResponse(Web::Context const& ctx); - - /** - * @brief Used to schedule request processing onto the work queue - * @param func The lambda to execute when this request is handled - * @param ip The ip address for which this request is being executed - */ - template - bool - post(Fn&& func, std::string const& ip) - { - return workQueue_.get().postCoro(std::forward(func), dosGuard_.get().isWhiteListed(ip)); - } - - /** - * @brief Notify the system that specified method was executed - * @param method - * @param duration The time it took to execute the method specified in - * microseconds - */ - void - notifyComplete(std::string const& method, std::chrono::microseconds const& duration); - - /** - * @brief Notify the system that specified method failed to execute - * @param method - */ - void - notifyErrored(std::string const& method); - - /** - * @brief Notify the system that specified method execution was forwarded to rippled - * @param method - */ - void - notifyForwarded(std::string const& method); - -private: - bool - shouldForwardToRippled(Web::Context const& ctx) const; - - bool - isClioOnly(std::string const& method) const; - - bool - validHandler(std::string const& method) const; -}; - -template -void -logDuration(Web::Context const& ctx, T const& dur) -{ - using boost::json::serialize; - - static clio::Logger log{"RPC"}; - auto const millis = std::chrono::duration_cast(dur).count(); - auto const seconds = std::chrono::duration_cast(dur).count(); - auto const msg = - fmt::format("Request processing duration = {} milliseconds. request = {}", millis, serialize(ctx.params)); - - if (seconds > 10) - log.error() << ctx.tag() << msg; - else if (seconds > 1) - log.warn() << ctx.tag() << msg; - else - log.info() << ctx.tag() << msg; -} - } // namespace RPC diff --git a/src/rpc/RPCEngine.h b/src/rpc/RPCEngine.h new file mode 100644 index 00000000..d718443e --- /dev/null +++ b/src/rpc/RPCEngine.h @@ -0,0 +1,275 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2022, the clio developers. + + Permission to use, copy, modify, and 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. +*/ +//============================================================================== + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +class WsBase; +class SubscriptionManager; +class ETLLoadBalancer; +class ReportingETL; + +namespace RPC { + +/** + * @brief The RPC engine that ties all RPC-related functionality together + */ +template +class RPCEngineBase +{ + clio::Logger perfLog_{"Performance"}; + clio::Logger log_{"RPC"}; + + std::shared_ptr backend_; + std::shared_ptr subscriptions_; + std::shared_ptr balancer_; + std::reference_wrapper dosGuard_; + std::reference_wrapper workQueue_; + std::reference_wrapper counters_; + + HandlerTable handlerTable_; + AdminVerificationStrategyType adminVerifier_; + +public: + RPCEngineBase( + std::shared_ptr const& backend, + std::shared_ptr const& subscriptions, + std::shared_ptr const& balancer, + std::shared_ptr const& etl, + clio::DOSGuard const& dosGuard, + WorkQueue& workQueue, + Counters& counters, + std::shared_ptr const& handlerProvider) + : backend_{backend} + , subscriptions_{subscriptions} + , balancer_{balancer} + , dosGuard_{std::cref(dosGuard)} + , workQueue_{std::ref(workQueue)} + , counters_{std::ref(counters)} + , handlerTable_{handlerProvider} + { + } + + static std::shared_ptr + make_RPCEngine( + clio::Config const& config, + std::shared_ptr const& backend, + std::shared_ptr const& subscriptions, + std::shared_ptr const& balancer, + std::shared_ptr const& etl, + clio::DOSGuard const& dosGuard, + WorkQueue& workQueue, + Counters& counters, + std::shared_ptr const& handlerProvider) + { + return std::make_shared( + backend, subscriptions, balancer, etl, dosGuard, workQueue, counters, handlerProvider); + } + + /** + * @brief Main request processor routine + * @param ctx The @ref Context of the request + */ + Result + buildResponse(Web::Context const& ctx) + { + if (shouldForwardToRippled(ctx)) + { + auto toForward = ctx.params; + toForward["command"] = ctx.method; + + auto const res = balancer_->forwardToRippled(toForward, ctx.clientIp, ctx.yield); + notifyForwarded(ctx.method); + + if (!res) + return Status{RippledError::rpcFAILED_TO_FORWARD}; + + return *res; + } + + if (backend_->isTooBusy()) + { + log_.error() << "Database is too busy. Rejecting request"; + return Status{RippledError::rpcTOO_BUSY}; + } + + auto const method = handlerTable_.getHandler(ctx.method); + if (!method) + return Status{RippledError::rpcUNKNOWN_COMMAND}; + + try + { + perfLog_.debug() << ctx.tag() << " start executing rpc `" << ctx.method << '`'; + + auto const isAdmin = adminVerifier_.isAdmin(ctx.clientIp); + auto const context = Context{ctx.yield, ctx.session, isAdmin, ctx.clientIp}; + auto const v = (*method).process(ctx.params, context); + + perfLog_.debug() << ctx.tag() << " finish executing rpc `" << ctx.method << '`'; + + if (v) + return v->as_object(); + else + return Status{v.error()}; + } + catch (InvalidParamsError const& err) + { + return Status{RippledError::rpcINVALID_PARAMS, err.what()}; + } + catch (AccountNotFoundError const& err) + { + return Status{RippledError::rpcACT_NOT_FOUND, err.what()}; + } + catch (Backend::DatabaseTimeout const& t) + { + log_.error() << "Database timeout"; + return Status{RippledError::rpcTOO_BUSY}; + } + catch (std::exception const& err) + { + log_.error() << ctx.tag() << " caught exception: " << err.what(); + return Status{RippledError::rpcINTERNAL}; + } + } + + /** + * @brief Used to schedule request processing onto the work queue + * @param func The lambda to execute when this request is handled + * @param ip The ip address for which this request is being executed + */ + template + bool + post(Fn&& func, std::string const& ip) + { + return workQueue_.get().postCoro(std::forward(func), dosGuard_.get().isWhiteListed(ip)); + } + + /** + * @brief Notify the system that specified method was executed + * @param method + * @param duration The time it took to execute the method specified in + * microseconds + */ + void + notifyComplete(std::string const& method, std::chrono::microseconds const& duration) + { + if (validHandler(method)) + counters_.get().rpcComplete(method, duration); + } + + /** + * @brief Notify the system that specified method failed to execute + * @param method + */ + void + notifyErrored(std::string const& method) + { + if (validHandler(method)) + counters_.get().rpcErrored(method); + } + + /** + * @brief Notify the system that specified method execution was forwarded to rippled + * @param method + */ + void + notifyForwarded(std::string const& method) + { + if (validHandler(method)) + counters_.get().rpcForwarded(method); + } + +private: + bool + shouldForwardToRippled(Web::Context const& ctx) const + { + auto request = ctx.params; + + if (isClioOnly(ctx.method)) + return false; + + if (isForwardCommand(ctx.method)) + return true; + + if (specifiesCurrentOrClosedLedger(request)) + return true; + + if (ctx.method == "account_info" && request.contains("queue") && request.at("queue").as_bool()) + return true; + + return false; + } + + bool + isForwardCommand(std::string const& method) const + { + static std::unordered_set const FORWARD_COMMANDS{ + "submit", + "submit_multisigned", + "fee", + "ledger_closed", + "ledger_current", + "ripple_path_find", + "manifest", + "channel_authorize", + "channel_verify", + }; + + return FORWARD_COMMANDS.contains(method); + } + + bool + isClioOnly(std::string const& method) const + { + return handlerTable_.isClioOnly(method); + } + + bool + validHandler(std::string const& method) const + { + return handlerTable_.contains(method) || isForwardCommand(method); + } +}; + +using RPCEngine = RPCEngineBase; + +} // namespace RPC diff --git a/src/rpc/RPCHelpers.cpp b/src/rpc/RPCHelpers.cpp index 990164df..00cbc821 100644 --- a/src/rpc/RPCHelpers.cpp +++ b/src/rpc/RPCHelpers.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/src/rpc/RPCHelpers.h b/src/rpc/RPCHelpers.h index fcd1c052..b3a3dbc9 100644 --- a/src/rpc/RPCHelpers.h +++ b/src/rpc/RPCHelpers.h @@ -20,8 +20,7 @@ #pragma once /* - * This file contains a variety of utility functions used when executing - * the handlers + * This file contains a variety of utility functions used when executing the handlers. */ #include @@ -30,9 +29,11 @@ #include #include #include -#include +#include #include +#include + namespace RPC { std::optional @@ -281,4 +282,24 @@ traverseTransactions( std::optional const&, boost::asio::yield_context& yield)> transactionFetcher); +template +void +logDuration(Web::Context const& ctx, T const& dur) +{ + using boost::json::serialize; + + static clio::Logger log{"RPC"}; + auto const millis = std::chrono::duration_cast(dur).count(); + auto const seconds = std::chrono::duration_cast(dur).count(); + auto const msg = + fmt::format("Request processing duration = {} milliseconds. request = {}", millis, serialize(ctx.params)); + + if (seconds > 10) + log.error() << ctx.tag() << msg; + else if (seconds > 1) + log.warn() << ctx.tag() << msg; + else + log.info() << ctx.tag() << msg; +} + } // namespace RPC diff --git a/src/rpc/common/Types.h b/src/rpc/common/Types.h index 6878b9be..0e32eee9 100644 --- a/src/rpc/common/Types.h +++ b/src/rpc/common/Types.h @@ -22,6 +22,8 @@ #include #include +#include + #include #include @@ -71,6 +73,26 @@ struct Context std::string clientIp; }; +using Result = std::variant; + +struct AccountCursor +{ + ripple::uint256 index; + std::uint32_t hint; + + std::string + toString() const + { + return ripple::strHex(index) + "," + std::to_string(hint); + } + + bool + isNonZero() const + { + return index.isNonZero() || hint != 0; + } +}; + class AnyHandler; class HandlerProvider diff --git a/src/rpc/common/impl/AdminVerificationStrategy.h b/src/rpc/common/impl/AdminVerificationStrategy.h new file mode 100644 index 00000000..e1aeec87 --- /dev/null +++ b/src/rpc/common/impl/AdminVerificationStrategy.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2023, the clio developers. + + Permission to use, copy, modify, and 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. +*/ +//============================================================================== + +#pragma once + +#include + +namespace RPC::detail { + +class IPAdminVerificationStrategy final +{ +public: + /** + * @brief Checks whether request is from a host that is considered authorized as admin. + * + * @param ip The ip addr of the client + * @return true if authorized; false otherwise + */ + bool + isAdmin(std::string_view ip) const + { + return ip == "127.0.0.1"; + } +}; + +} // namespace RPC::detail diff --git a/src/rpc/handlers/AccountLines.cpp b/src/rpc/handlers/AccountLines.cpp index 62739b31..0a445715 100644 --- a/src/rpc/handlers/AccountLines.cpp +++ b/src/rpc/handlers/AccountLines.cpp @@ -17,7 +17,6 @@ */ //============================================================================== -#include #include namespace RPC { diff --git a/src/rpc/handlers/NoRippleCheck.cpp b/src/rpc/handlers/NoRippleCheck.cpp index 7d5af44b..7ea054ce 100644 --- a/src/rpc/handlers/NoRippleCheck.cpp +++ b/src/rpc/handlers/NoRippleCheck.cpp @@ -18,7 +18,6 @@ //============================================================================== #include -#include #include #include diff --git a/src/webserver/HttpBase.h b/src/webserver/HttpBase.h index db86a7b7..d7d38767 100644 --- a/src/webserver/HttpBase.h +++ b/src/webserver/HttpBase.h @@ -41,6 +41,7 @@ #include
#include #include +#include #include #include #include diff --git a/src/webserver/WsBase.h b/src/webserver/WsBase.h index e34df918..1cec2d60 100644 --- a/src/webserver/WsBase.h +++ b/src/webserver/WsBase.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/unittests/rpc/AdminVerificationTest.cpp b/unittests/rpc/AdminVerificationTest.cpp new file mode 100644 index 00000000..c61a8b7a --- /dev/null +++ b/unittests/rpc/AdminVerificationTest.cpp @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2023, the clio developers. + + Permission to use, copy, modify, and 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 + +#include + +#include +#include + +class RPCAdminVerificationTest : public NoLoggerFixture +{ +protected: + RPC::detail::IPAdminVerificationStrategy strat_; +}; + +TEST_F(RPCAdminVerificationTest, IsAdminOnlyForIP_127_0_0_1) +{ + EXPECT_TRUE(strat_.isAdmin("127.0.0.1")); + EXPECT_FALSE(strat_.isAdmin("127.0.0.2")); + EXPECT_FALSE(strat_.isAdmin("127")); + EXPECT_FALSE(strat_.isAdmin("")); + EXPECT_FALSE(strat_.isAdmin("localhost")); +}