aboutsummaryrefslogtreecommitdiff
path: root/src/rpcserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpcserver.cpp')
-rw-r--r--src/rpcserver.cpp146
1 files changed, 85 insertions, 61 deletions
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 9f2100a8d..d771a4242 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
+// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,8 +8,8 @@
#include "base58.h"
#include "init.h"
#include "main.h"
-#include "util.h"
#include "ui_interface.h"
+#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#endif
@@ -22,7 +22,6 @@
#include <boost/foreach.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
-#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include "json/json_spirit_writer_template.h"
@@ -38,6 +37,7 @@ static asio::io_service* rpc_io_service = NULL;
static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
static ssl::context* rpc_ssl_context = NULL;
static boost::thread_group* rpc_worker_group = NULL;
+static boost::asio::io_service::work *rpc_dummy_work = NULL;
void RPCTypeCheck(const Array& params,
const list<Value_type>& typesExpected,
@@ -68,12 +68,12 @@ void RPCTypeCheck(const Object& o,
{
const Value& v = find_value(o, t.first);
if (!fAllowNull && v.type() == null_type)
- throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first.c_str()));
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
{
string err = strprintf("Expected type %s for %s, got %s",
- Value_type_name[t.second], t.first.c_str(), Value_type_name[v.type()]);
+ Value_type_name[t.second], t.first, Value_type_name[v.type()]);
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
}
@@ -175,7 +175,7 @@ string CRPCTable::help(string strCommand) const
}
}
if (strRet == "")
- strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
+ strRet = strprintf("help: unknown command: %s\n", strCommand);
strRet = strRet.substr(0,strRet.size()-1);
return strRet;
}
@@ -222,85 +222,95 @@ Value stop(const Array& params, bool fHelp)
static const CRPCCommand vRPCCommands[] =
{ // name actor (function) okSafeMode threadSafe reqWallet
// ------------------------ ----------------------- ---------- ---------- ---------
+ /* Overall control/query calls */
+ { "getinfo", &getinfo, true, false, false }, /* uses wallet if enabled */
{ "help", &help, true, true, false },
{ "stop", &stop, true, true, false },
- { "getblockcount", &getblockcount, true, false, false },
- { "getbestblockhash", &getbestblockhash, true, false, false },
- { "getconnectioncount", &getconnectioncount, true, false, false },
- { "getpeerinfo", &getpeerinfo, true, false, false },
- { "ping", &ping, true, false, false },
+
+ /* P2P networking */
{ "addnode", &addnode, true, true, false },
{ "getaddednodeinfo", &getaddednodeinfo, true, true, false },
+ { "getconnectioncount", &getconnectioncount, true, false, false },
{ "getnettotals", &getnettotals, true, true, false },
- { "getdifficulty", &getdifficulty, true, false, false },
- { "getinfo", &getinfo, true, false, false },
- { "getrawmempool", &getrawmempool, true, false, false },
+ { "getpeerinfo", &getpeerinfo, true, false, false },
+ { "ping", &ping, true, false, false },
+
+ /* Block chain and UTXO */
+ { "getbestblockhash", &getbestblockhash, true, false, false },
+ { "getblockcount", &getblockcount, true, false, false },
{ "getblock", &getblock, false, false, false },
{ "getblockhash", &getblockhash, false, false, false },
- { "getrawtransaction", &getrawtransaction, false, false, false },
- { "createrawtransaction", &createrawtransaction, false, false, false },
- { "decoderawtransaction", &decoderawtransaction, false, false, false },
- { "decodescript", &decodescript, false, false, false },
- { "signrawtransaction", &signrawtransaction, false, false, false },
- { "sendrawtransaction", &sendrawtransaction, false, false, false },
- { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
+ { "getdifficulty", &getdifficulty, true, false, false },
+ { "getrawmempool", &getrawmempool, true, false, false },
{ "gettxout", &gettxout, true, false, false },
+ { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
{ "verifychain", &verifychain, true, false, false },
/* Mining */
- { "getnetworkhashps", &getnetworkhashps, true, false, false },
- { "getmininginfo", &getmininginfo, true, false, false },
{ "getblocktemplate", &getblocktemplate, true, false, false },
+ { "getmininginfo", &getmininginfo, true, false, false },
+ { "getnetworkhashps", &getnetworkhashps, true, false, false },
{ "submitblock", &submitblock, false, false, false },
- { "validateaddress", &validateaddress, true, false, false },
+
+ /* Raw transactions */
+ { "createrawtransaction", &createrawtransaction, false, false, false },
+ { "decoderawtransaction", &decoderawtransaction, false, false, false },
+ { "decodescript", &decodescript, false, false, false },
+ { "getrawtransaction", &getrawtransaction, false, false, false },
+ { "sendrawtransaction", &sendrawtransaction, false, false, false },
+ { "signrawtransaction", &signrawtransaction, false, false, false }, /* uses wallet if enabled */
+
+ /* Utility functions */
{ "createmultisig", &createmultisig, true, true , false },
+ { "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */
{ "verifymessage", &verifymessage, false, false, false },
#ifdef ENABLE_WALLET
/* Wallet */
- { "getnewaddress", &getnewaddress, true, false, true },
+ { "addmultisigaddress", &addmultisigaddress, false, false, true },
+ { "backupwallet", &backupwallet, true, false, true },
+ { "dumpprivkey", &dumpprivkey, true, false, true },
+ { "dumpwallet", &dumpwallet, true, false, true },
+ { "encryptwallet", &encryptwallet, false, false, true },
{ "getaccountaddress", &getaccountaddress, true, false, true },
- { "getrawchangeaddress", &getrawchangeaddress, true, false, true },
- { "setaccount", &setaccount, true, false, true },
{ "getaccount", &getaccount, false, false, true },
{ "getaddressesbyaccount", &getaddressesbyaccount, true, false, true },
- { "sendtoaddress", &sendtoaddress, false, false, true },
- { "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
- { "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
- { "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
- { "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
- { "backupwallet", &backupwallet, true, false, true },
- { "keypoolrefill", &keypoolrefill, true, false, true },
- { "walletpassphrase", &walletpassphrase, true, false, true },
- { "walletpassphrasechange", &walletpassphrasechange, false, false, true },
- { "walletlock", &walletlock, true, false, true },
- { "encryptwallet", &encryptwallet, false, false, true },
{ "getbalance", &getbalance, false, false, true },
- { "getunconfirmedbalance", &getunconfirmedbalance, false, false, true },
- { "move", &movecmd, false, false, true },
- { "sendfrom", &sendfrom, false, false, true },
- { "sendmany", &sendmany, false, false, true },
- { "addmultisigaddress", &addmultisigaddress, false, false, true },
+ { "getnewaddress", &getnewaddress, true, false, true },
+ { "getrawchangeaddress", &getrawchangeaddress, true, false, true },
+ { "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
+ { "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
{ "gettransaction", &gettransaction, false, false, true },
- { "listtransactions", &listtransactions, false, false, true },
- { "listaddressgroupings", &listaddressgroupings, false, false, true },
- { "signmessage", &signmessage, false, false, true },
- { "listaccounts", &listaccounts, false, false, true },
- { "listsinceblock", &listsinceblock, false, false, true },
- { "dumpprivkey", &dumpprivkey, true, false, true },
- { "dumpwallet", &dumpwallet, true, false, true },
+ { "getunconfirmedbalance", &getunconfirmedbalance, false, false, true },
+ { "getwalletinfo", &getwalletinfo, true, false, true },
{ "importprivkey", &importprivkey, false, false, true },
{ "importwallet", &importwallet, false, false, true },
+ { "keypoolrefill", &keypoolrefill, true, false, true },
+ { "listaccounts", &listaccounts, false, false, true },
+ { "listaddressgroupings", &listaddressgroupings, false, false, true },
+ { "listlockunspent", &listlockunspent, false, false, true },
+ { "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
+ { "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
+ { "listsinceblock", &listsinceblock, false, false, true },
+ { "listtransactions", &listtransactions, false, false, true },
{ "listunspent", &listunspent, false, false, true },
{ "lockunspent", &lockunspent, false, false, true },
- { "listlockunspent", &listlockunspent, false, false, true },
+ { "move", &movecmd, false, false, true },
+ { "sendfrom", &sendfrom, false, false, true },
+ { "sendmany", &sendmany, false, false, true },
+ { "sendtoaddress", &sendtoaddress, false, false, true },
+ { "setaccount", &setaccount, true, false, true },
{ "settxfee", &settxfee, false, false, true },
+ { "signmessage", &signmessage, false, false, true },
+ { "walletlock", &walletlock, true, false, true },
+ { "walletpassphrasechange", &walletpassphrasechange, false, false, true },
+ { "walletpassphrase", &walletpassphrase, true, false, true },
/* Wallet-enabled mining */
{ "getgenerate", &getgenerate, true, false, false },
- { "setgenerate", &setgenerate, true, true, false },
{ "gethashespersec", &gethashespersec, true, false, false },
- { "getwork", &getwork, true, false, true },
+ { "getwork", &getwork, true, false, true },
+ { "setgenerate", &setgenerate, true, true, false },
#endif // ENABLE_WALLET
};
@@ -512,9 +522,9 @@ void StartRPCThreads()
"If the file does not exist, create it with owner-readable-only file permissions.\n"
"It is also recommended to set alertnotify so you are notified of problems;\n"
"for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" [email protected]\n"),
- strWhatAmI.c_str(),
- GetConfigFile().string().c_str(),
- EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
+ strWhatAmI,
+ GetConfigFile().string(),
+ EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
@@ -533,12 +543,12 @@ void StartRPCThreads()
filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
if (filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string());
- else LogPrintf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
+ else LogPrintf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string());
filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
if (filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem);
- else LogPrintf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
+ else LogPrintf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string());
string strCiphers = GetArg("-rpcsslciphers", "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH");
SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str());
@@ -607,6 +617,19 @@ void StartRPCThreads()
rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
}
+void StartDummyRPCThread()
+{
+ if(rpc_io_service == NULL)
+ {
+ rpc_io_service = new asio::io_service();
+ /* Create dummy "work" to keep the thread from exiting when no timeouts active,
+ * see http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/io_service.html#boost_asio.reference.io_service.stopping_the_io_service_from_running_out_of_work */
+ rpc_dummy_work = new asio::io_service::work(*rpc_io_service);
+ rpc_worker_group = new boost::thread_group();
+ rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
+ }
+}
+
void StopRPCThreads()
{
if (rpc_io_service == NULL) return;
@@ -615,6 +638,7 @@ void StopRPCThreads()
rpc_io_service->stop();
if (rpc_worker_group != NULL)
rpc_worker_group->join_all();
+ delete rpc_dummy_work; rpc_dummy_work = NULL;
delete rpc_worker_group; rpc_worker_group = NULL;
delete rpc_ssl_context; rpc_ssl_context = NULL;
delete rpc_io_service; rpc_io_service = NULL;
@@ -668,7 +692,7 @@ void JSONRequest::parse(const Value& valRequest)
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str();
if (strMethod != "getwork" && strMethod != "getblocktemplate")
- LogPrint("rpc", "ThreadRPCServer method=%s\n", strMethod.c_str());
+ LogPrint("rpc", "ThreadRPCServer method=%s\n", strMethod);
// Parse params
Value valParams = find_value(request, "params");
@@ -717,7 +741,7 @@ static string JSONRPCExecBatch(const Array& vReq)
void ServiceConnection(AcceptedConnection *conn)
{
bool fRun = true;
- while (fRun)
+ while (fRun && !ShutdownRequested())
{
int nProto = 0;
map<string, string> mapHeaders;
@@ -743,7 +767,7 @@ void ServiceConnection(AcceptedConnection *conn)
}
if (!HTTPAuthorized(mapHeaders))
{
- LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string().c_str());
+ LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
/* Deter brute-forcing short passwords.
If this results in a DoS the user really
shouldn't have their RPC port exposed. */