aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/server.cpp')
-rw-r--r--src/rpc/server.cpp111
1 files changed, 81 insertions, 30 deletions
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 9d2c6ca0a6..edaf64f3e1 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -15,7 +15,6 @@
#include <util/strencodings.h>
#include <util/system.h>
-#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
@@ -24,7 +23,7 @@
#include <unordered_map>
static CCriticalSection cs_rpcWarmup;
-static bool fRPCRunning = false;
+static std::atomic<bool> g_rpc_running{false};
static bool fRPCInWarmup GUARDED_BY(cs_rpcWarmup) = true;
static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server started";
/* Timer-creating functions */
@@ -32,11 +31,39 @@ static RPCTimerInterface* timerInterface = nullptr;
/* Map of name to timer. */
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
+struct RPCCommandExecutionInfo
+{
+ std::string method;
+ int64_t start;
+};
+
+struct RPCServerInfo
+{
+ Mutex mutex;
+ std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex);
+};
+
+static RPCServerInfo g_rpc_server_info;
+
+struct RPCCommandExecution
+{
+ std::list<RPCCommandExecutionInfo>::iterator it;
+ explicit RPCCommandExecution(const std::string& method)
+ {
+ LOCK(g_rpc_server_info.mutex);
+ it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.cend(), {method, GetTimeMicros()});
+ }
+ ~RPCCommandExecution()
+ {
+ LOCK(g_rpc_server_info.mutex);
+ g_rpc_server_info.active_commands.erase(it);
+ }
+};
+
static struct CRPCSignals
{
boost::signals2::signal<void ()> Started;
boost::signals2::signal<void ()> Stopped;
- boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
} g_rpcSignals;
void RPCServer::OnStarted(std::function<void ()> slot)
@@ -142,10 +169,6 @@ std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
return ParseHexV(find_value(o, strKey), strKey);
}
-/**
- * Note: This interface may still be subject to change.
- */
-
std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
{
std::string strRet;
@@ -204,10 +227,12 @@ UniValue help(const JSONRPCRequest& jsonRequest)
{
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw std::runtime_error(
- "help ( \"command\" )\n"
- "\nList all commands, or get help for a specified command.\n"
- "\nArguments:\n"
- "1. \"command\" (string, optional) The command to get help on\n"
+ RPCHelpMan{"help",
+ "\nList all commands, or get help for a specified command.\n",
+ {
+ {"command", RPCArg::Type::STR, /* opt */ true, /* default_val */ "all commands", "The command to get help on"},
+ }}
+ .ToString() +
"\nResult:\n"
"\"text\" (string) The help text\n"
);
@@ -223,22 +248,30 @@ UniValue help(const JSONRPCRequest& jsonRequest)
UniValue stop(const JSONRPCRequest& jsonRequest)
{
// Accept the deprecated and ignored 'detach' boolean argument
+ // Also accept the hidden 'wait' integer argument (milliseconds)
+ // For instance, 'stop 1000' makes the call wait 1 second before returning
+ // to the client (intended for testing)
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw std::runtime_error(
- "stop\n"
- "\nStop Bitcoin server.");
+ RPCHelpMan{"stop",
+ "\nStop Bitcoin server.", {}}
+ .ToString());
// Event loop will exit after current HTTP requests have been handled, so
// this reply will get back to the client.
StartShutdown();
+ if (jsonRequest.params[0].isNum()) {
+ MilliSleep(jsonRequest.params[0].get_int());
+ }
return "Bitcoin server stopping";
}
static UniValue uptime(const JSONRPCRequest& jsonRequest)
{
- if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 0)
throw std::runtime_error(
- "uptime\n"
- "\nReturns the total uptime of the server.\n"
+ RPCHelpMan{"uptime",
+ "\nReturns the total uptime of the server.\n", {}}
+ .ToString() +
"\nResult:\n"
"ttt (numeric) The number of seconds that the server has been running\n"
"\nExamples:\n"
@@ -249,16 +282,39 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest)
return GetTime() - GetStartupTime();
}
+static UniValue getrpcinfo(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() > 0) {
+ throw std::runtime_error(
+ RPCHelpMan{"getrpcinfo",
+ "\nReturns details of the RPC server.\n", {}}
+ .ToString()
+ );
+ }
+
+ LOCK(g_rpc_server_info.mutex);
+ UniValue active_commands(UniValue::VARR);
+ for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {
+ UniValue entry(UniValue::VOBJ);
+ entry.pushKV("method", info.method);
+ entry.pushKV("duration", GetTimeMicros() - info.start);
+ active_commands.push_back(entry);
+ }
+
+ UniValue result(UniValue::VOBJ);
+ result.pushKV("active_commands", active_commands);
+
+ return result;
+}
+
// clang-format off
-/**
- * Call Table
- */
static const CRPCCommand vRPCCommands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
+ { "control", "getrpcinfo", &getrpcinfo, {} },
{ "control", "help", &help, {"command"} },
- { "control", "stop", &stop, {} },
+ { "control", "stop", &stop, {"wait"} },
{ "control", "uptime", &uptime, {} },
};
// clang-format on
@@ -300,7 +356,7 @@ bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
void StartRPC()
{
LogPrint(BCLog::RPC, "Starting RPC\n");
- fRPCRunning = true;
+ g_rpc_running = true;
g_rpcSignals.Started();
}
@@ -308,7 +364,7 @@ void InterruptRPC()
{
LogPrint(BCLog::RPC, "Interrupting RPC\n");
// Interrupt e.g. running longpolls
- fRPCRunning = false;
+ g_rpc_running = false;
}
void StopRPC()
@@ -321,7 +377,7 @@ void StopRPC()
bool IsRPCRunning()
{
- return fRPCRunning;
+ return g_rpc_running;
}
void SetRPCWarmupStatus(const std::string& newStatus)
@@ -481,10 +537,9 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
- g_rpcSignals.PreCommand(*pcmd);
-
try
{
+ RPCCommandExecution execution(request.strMethod);
// Execute, convert arguments to array if necessary
if (request.params.isObject()) {
return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
@@ -501,11 +556,7 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
std::vector<std::string> CRPCTable::listCommands() const
{
std::vector<std::string> commandList;
- typedef std::map<std::string, const CRPCCommand*> commandMap;
-
- std::transform( mapCommands.begin(), mapCommands.end(),
- std::back_inserter(commandList),
- boost::bind(&commandMap::value_type::first,_1) );
+ for (const auto& i : mapCommands) commandList.emplace_back(i.first);
return commandList;
}