]> Git Repo - VerusCoin.git/blame - src/rpcserver.cpp
doc: remove mention of `-rpctimeout` from man page
[VerusCoin.git] / src / rpcserver.cpp
CommitLineData
69d605f4 1// Copyright (c) 2010 Satoshi Nakamoto
57702541 2// Copyright (c) 2009-2014 The Bitcoin developers
69d605f4 3// Distributed under the MIT/X11 software license, see the accompanying
3a25a2b9 4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
69d605f4 5
fb78cc23 6#include "rpcserver.h"
51ed9ec9
BD
7
8#include "base58.h"
0eeb4f5d 9#include "init.h"
51ed9ec9 10#include "main.h"
48ba56cd 11#include "ui_interface.h"
c037531d 12#include "util.h"
48ba56cd 13#ifdef ENABLE_WALLET
51ed9ec9 14#include "wallet.h"
48ba56cd 15#endif
51ed9ec9 16
92f2c1fe 17#include <boost/algorithm/string.hpp>
69d605f4 18#include <boost/asio.hpp>
92f2c1fe 19#include <boost/asio/ssl.hpp>
914dc012 20#include <boost/bind.hpp>
95d888a6 21#include <boost/filesystem.hpp>
a0780ba0 22#include <boost/foreach.hpp>
69d605f4
WL
23#include <boost/iostreams/concepts.hpp>
24#include <boost/iostreams/stream.hpp>
914dc012 25#include <boost/shared_ptr.hpp>
51ed9ec9 26#include "json/json_spirit_writer_template.h"
5ce4c2a2 27
69d605f4
WL
28using namespace std;
29using namespace boost;
30using namespace boost::asio;
31using namespace json_spirit;
32
f81ce5bd
GA
33static std::string strRPCUserColonPass;
34
21eb5ada
GA
35// These are created by StartRPCThreads, destroyed in StopRPCThreads
36static asio::io_service* rpc_io_service = NULL;
92f2c1fe 37static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
21eb5ada
GA
38static ssl::context* rpc_ssl_context = NULL;
39static boost::thread_group* rpc_worker_group = NULL;
a8db31c8 40static boost::asio::io_service::work *rpc_dummy_work = NULL;
ee219125 41static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
e9205293 42
899d373b 43void RPCTypeCheck(const Array& params,
cc6dfd1f
GA
44 const list<Value_type>& typesExpected,
45 bool fAllowNull)
899d373b 46{
dab9fa7f 47 unsigned int i = 0;
899d373b
GA
48 BOOST_FOREACH(Value_type t, typesExpected)
49 {
50 if (params.size() <= i)
51 break;
52
cc6dfd1f
GA
53 const Value& v = params[i];
54 if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
899d373b
GA
55 {
56 string err = strprintf("Expected type %s, got %s",
57 Value_type_name[t], Value_type_name[v.type()]);
738835d7 58 throw JSONRPCError(RPC_TYPE_ERROR, err);
899d373b
GA
59 }
60 i++;
61 }
62}
63
64void RPCTypeCheck(const Object& o,
cc6dfd1f
GA
65 const map<string, Value_type>& typesExpected,
66 bool fAllowNull)
899d373b
GA
67{
68 BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
69 {
70 const Value& v = find_value(o, t.first);
cc6dfd1f 71 if (!fAllowNull && v.type() == null_type)
7d9d134b 72 throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
cc6dfd1f
GA
73
74 if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
899d373b
GA
75 {
76 string err = strprintf("Expected type %s for %s, got %s",
7d9d134b 77 Value_type_name[t.second], t.first, Value_type_name[v.type()]);
738835d7 78 throw JSONRPCError(RPC_TYPE_ERROR, err);
899d373b
GA
79 }
80 }
81}
82
51ed9ec9 83int64_t AmountFromValue(const Value& value)
69d605f4
WL
84{
85 double dAmount = value.get_real();
86 if (dAmount <= 0.0 || dAmount > 21000000.0)
738835d7 87 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
51ed9ec9 88 int64_t nAmount = roundint64(dAmount * COIN);
69d605f4 89 if (!MoneyRange(nAmount))
738835d7 90 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
69d605f4
WL
91 return nAmount;
92}
93
51ed9ec9 94Value ValueFromAmount(int64_t amount)
69d605f4
WL
95{
96 return (double)amount / (double)COIN;
97}
98
bdab0cf5 99std::string HexBits(unsigned int nBits)
34f87889
LD
100{
101 union {
102 int32_t nBits;
103 char cBits[4];
104 } uBits;
105 uBits.nBits = htonl((int32_t)nBits);
106 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
107}
108
463c9710
PT
109uint256 ParseHashV(const Value& v, string strName)
110{
111 string strHex;
112 if (v.type() == str_type)
113 strHex = v.get_str();
114 if (!IsHex(strHex)) // Note: IsHex("") is false
115 throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
116 uint256 result;
117 result.SetHex(strHex);
118 return result;
119}
120uint256 ParseHashO(const Object& o, string strKey)
121{
122 return ParseHashV(find_value(o, strKey), strKey);
123}
124vector<unsigned char> ParseHexV(const Value& v, string strName)
125{
126 string strHex;
127 if (v.type() == str_type)
128 strHex = v.get_str();
129 if (!IsHex(strHex))
130 throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
131 return ParseHex(strHex);
132}
133vector<unsigned char> ParseHexO(const Object& o, string strKey)
134{
135 return ParseHexV(find_value(o, strKey), strKey);
136}
69d605f4 137
74335bd3 138
69d605f4
WL
139///
140/// Note: This interface may still be subject to change.
141///
142
9862229d 143string CRPCTable::help(string strCommand) const
69d605f4 144{
69d605f4
WL
145 string strRet;
146 set<rpcfn_type> setDone;
9862229d 147 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
69d605f4 148 {
9862229d 149 const CRPCCommand *pcmd = mi->second;
dc42bf52 150 string strMethod = mi->first;
69d605f4 151 // We already filter duplicates, but these deprecated screw up the sort order
47f48a65 152 if (strMethod.find("label") != string::npos)
69d605f4
WL
153 continue;
154 if (strCommand != "" && strMethod != strCommand)
155 continue;
48ba56cd 156#ifdef ENABLE_WALLET
b0730874
JG
157 if (pcmd->reqWallet && !pwalletMain)
158 continue;
48ba56cd 159#endif
b0730874 160
69d605f4
WL
161 try
162 {
163 Array params;
dc42bf52 164 rpcfn_type pfn = pcmd->actor;
69d605f4
WL
165 if (setDone.insert(pfn).second)
166 (*pfn)(params, true);
167 }
168 catch (std::exception& e)
169 {
170 // Help text is returned in an exception
171 string strHelp = string(e.what());
172 if (strCommand == "")
ab9dc75a 173 if (strHelp.find('\n') != string::npos)
69d605f4
WL
174 strHelp = strHelp.substr(0, strHelp.find('\n'));
175 strRet += strHelp + "\n";
176 }
177 }
178 if (strRet == "")
7d9d134b 179 strRet = strprintf("help: unknown command: %s\n", strCommand);
69d605f4
WL
180 strRet = strRet.substr(0,strRet.size()-1);
181 return strRet;
182}
183
9862229d
PW
184Value help(const Array& params, bool fHelp)
185{
186 if (fHelp || params.size() > 1)
187 throw runtime_error(
a6099ef3 188 "help ( \"command\" )\n"
189 "\nList all commands, or get help for a specified command.\n"
190 "\nArguments:\n"
191 "1. \"command\" (string, optional) The command to get help on\n"
192 "\nResult:\n"
193 "\"text\" (string) The help text\n"
194 );
9862229d
PW
195
196 string strCommand;
197 if (params.size() > 0)
198 strCommand = params[0].get_str();
199
200 return tableRPC.help(strCommand);
201}
202
69d605f4
WL
203
204Value stop(const Array& params, bool fHelp)
205{
6e65420b 206 // Accept the deprecated and ignored 'detach' boolean argument
3731f578 207 if (fHelp || params.size() > 1)
69d605f4 208 throw runtime_error(
92467073 209 "stop\n"
a6099ef3 210 "\nStop Bitcoin server.");
69d605f4 211 // Shutdown will take long enough that the response should get back
9247134e 212 StartShutdown();
ff0ee876 213 return "Bitcoin server stopping";
69d605f4
WL
214}
215
216
69d605f4
WL
217
218//
219// Call Table
220//
221
dc42bf52 222
e46704dd 223static const CRPCCommand vRPCCommands[] =
b0730874
JG
224{ // name actor (function) okSafeMode threadSafe reqWallet
225 // ------------------------ ----------------------- ---------- ---------- ---------
ab88ed93
WL
226 /* Overall control/query calls */
227 { "getinfo", &getinfo, true, false, false }, /* uses wallet if enabled */
b0730874
JG
228 { "help", &help, true, true, false },
229 { "stop", &stop, true, true, false },
ab88ed93
WL
230
231 /* P2P networking */
d387b8ec 232 { "getnetworkinfo", &getnetworkinfo, true, false, false },
b0730874
JG
233 { "addnode", &addnode, true, true, false },
234 { "getaddednodeinfo", &getaddednodeinfo, true, true, false },
ab88ed93 235 { "getconnectioncount", &getconnectioncount, true, false, false },
ce14345a 236 { "getnettotals", &getnettotals, true, true, false },
ab88ed93
WL
237 { "getpeerinfo", &getpeerinfo, true, false, false },
238 { "ping", &ping, true, false, false },
239
240 /* Block chain and UTXO */
d387b8ec 241 { "getblockchaininfo", &getblockchaininfo, true, false, false },
ab88ed93
WL
242 { "getbestblockhash", &getbestblockhash, true, false, false },
243 { "getblockcount", &getblockcount, true, false, false },
48ba56cd
WL
244 { "getblock", &getblock, false, false, false },
245 { "getblockhash", &getblockhash, false, false, false },
ab88ed93
WL
246 { "getdifficulty", &getdifficulty, true, false, false },
247 { "getrawmempool", &getrawmempool, true, false, false },
48ba56cd 248 { "gettxout", &gettxout, true, false, false },
ab88ed93 249 { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
48ba56cd
WL
250 { "verifychain", &verifychain, true, false, false },
251
4a85e067 252 /* Mining */
4a85e067 253 { "getblocktemplate", &getblocktemplate, true, false, false },
ab88ed93
WL
254 { "getmininginfo", &getmininginfo, true, false, false },
255 { "getnetworkhashps", &getnetworkhashps, true, false, false },
4a85e067 256 { "submitblock", &submitblock, false, false, false },
ab88ed93
WL
257
258 /* Raw transactions */
259 { "createrawtransaction", &createrawtransaction, false, false, false },
260 { "decoderawtransaction", &decoderawtransaction, false, false, false },
261 { "decodescript", &decodescript, false, false, false },
262 { "getrawtransaction", &getrawtransaction, false, false, false },
263 { "sendrawtransaction", &sendrawtransaction, false, false, false },
264 { "signrawtransaction", &signrawtransaction, false, false, false }, /* uses wallet if enabled */
265
266 /* Utility functions */
723a03d2 267 { "createmultisig", &createmultisig, true, true , false },
ab88ed93 268 { "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */
c3a7f516 269 { "verifymessage", &verifymessage, false, false, false },
4a85e067
WL
270
271#ifdef ENABLE_WALLET
272 /* Wallet */
ab88ed93
WL
273 { "addmultisigaddress", &addmultisigaddress, false, false, true },
274 { "backupwallet", &backupwallet, true, false, true },
275 { "dumpprivkey", &dumpprivkey, true, false, true },
276 { "dumpwallet", &dumpwallet, true, false, true },
277 { "encryptwallet", &encryptwallet, false, false, true },
b0730874 278 { "getaccountaddress", &getaccountaddress, true, false, true },
b0730874
JG
279 { "getaccount", &getaccount, false, false, true },
280 { "getaddressesbyaccount", &getaddressesbyaccount, true, false, true },
b0730874 281 { "getbalance", &getbalance, false, false, true },
ab88ed93
WL
282 { "getnewaddress", &getnewaddress, true, false, true },
283 { "getrawchangeaddress", &getrawchangeaddress, true, false, true },
284 { "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
285 { "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
b0730874 286 { "gettransaction", &gettransaction, false, false, true },
ab88ed93
WL
287 { "getunconfirmedbalance", &getunconfirmedbalance, false, false, true },
288 { "getwalletinfo", &getwalletinfo, true, false, true },
b0730874
JG
289 { "importprivkey", &importprivkey, false, false, true },
290 { "importwallet", &importwallet, false, false, true },
ab88ed93
WL
291 { "keypoolrefill", &keypoolrefill, true, false, true },
292 { "listaccounts", &listaccounts, false, false, true },
293 { "listaddressgroupings", &listaddressgroupings, false, false, true },
294 { "listlockunspent", &listlockunspent, false, false, true },
295 { "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
296 { "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
297 { "listsinceblock", &listsinceblock, false, false, true },
298 { "listtransactions", &listtransactions, false, false, true },
b0730874 299 { "listunspent", &listunspent, false, false, true },
b0730874 300 { "lockunspent", &lockunspent, false, false, true },
ab88ed93
WL
301 { "move", &movecmd, false, false, true },
302 { "sendfrom", &sendfrom, false, false, true },
303 { "sendmany", &sendmany, false, false, true },
304 { "sendtoaddress", &sendtoaddress, false, false, true },
305 { "setaccount", &setaccount, true, false, true },
a943bde6 306 { "settxfee", &settxfee, false, false, true },
ab88ed93
WL
307 { "signmessage", &signmessage, false, false, true },
308 { "walletlock", &walletlock, true, false, true },
309 { "walletpassphrasechange", &walletpassphrasechange, false, false, true },
310 { "walletpassphrase", &walletpassphrase, true, false, true },
4a85e067
WL
311
312 /* Wallet-enabled mining */
313 { "getgenerate", &getgenerate, true, false, false },
4a85e067 314 { "gethashespersec", &gethashespersec, true, false, false },
ab88ed93
WL
315 { "getwork", &getwork, true, false, true },
316 { "setgenerate", &setgenerate, true, true, false },
48ba56cd 317#endif // ENABLE_WALLET
69d605f4 318};
69d605f4 319
9862229d 320CRPCTable::CRPCTable()
dc42bf52 321{
dc42bf52
JG
322 unsigned int vcidx;
323 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
324 {
e46704dd 325 const CRPCCommand *pcmd;
69d605f4 326
dc42bf52
JG
327 pcmd = &vRPCCommands[vcidx];
328 mapCommands[pcmd->name] = pcmd;
329 }
330}
69d605f4 331
9862229d
PW
332const CRPCCommand *CRPCTable::operator[](string name) const
333{
334 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
335 if (it == mapCommands.end())
336 return NULL;
337 return (*it).second;
338}
69d605f4 339
69d605f4 340
69d605f4
WL
341bool HTTPAuthorized(map<string, string>& mapHeaders)
342{
343 string strAuth = mapHeaders["authorization"];
344 if (strAuth.substr(0,6) != "Basic ")
345 return false;
346 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
347 string strUserPass = DecodeBase64(strUserPass64);
42656ea2 348 return TimingResistantEqual(strUserPass, strRPCUserColonPass);
69d605f4
WL
349}
350
69d605f4
WL
351void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
352{
353 // Send error reply from json-rpc error object
285746d3 354 int nStatus = HTTP_INTERNAL_SERVER_ERROR;
69d605f4 355 int code = find_value(objError, "code").get_int();
285746d3
WL
356 if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
357 else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
69d605f4 358 string strReply = JSONRPCReply(Value::null, objError, id);
96c52695 359 stream << HTTPReply(nStatus, strReply, false) << std::flush;
69d605f4
WL
360}
361
21bf3d25 362CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address)
69d605f4 363{
ee219125 364 CNetAddr netaddr;
43b6dafa
GS
365 // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
366 if (address.is_v6()
367 && (address.to_v6().is_v4_compatible()
368 || address.to_v6().is_v4_mapped()))
ee219125
WL
369 address = address.to_v6().to_v4();
370
371 if(address.is_v4())
372 {
373 boost::asio::ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();
374 netaddr.SetRaw(NET_IPV4, &bytes[0]);
375 }
376 else
377 {
378 boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
379 netaddr.SetRaw(NET_IPV6, &bytes[0]);
380 }
381 return netaddr;
382}
383
384bool ClientAllowed(const boost::asio::ip::address& address)
385{
386 CNetAddr netaddr = BoostAsioToCNetAddr(address);
387 BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
388 if (subnet.Match(netaddr))
69d605f4
WL
389 return true;
390 return false;
391}
392
e9205293
DJS
393class AcceptedConnection
394{
a0780ba0
GS
395public:
396 virtual ~AcceptedConnection() {}
397
398 virtual std::iostream& stream() = 0;
399 virtual std::string peer_address_to_string() const = 0;
400 virtual void close() = 0;
401};
e9205293 402
a0780ba0
GS
403template <typename Protocol>
404class AcceptedConnectionImpl : public AcceptedConnection
405{
406public:
407 AcceptedConnectionImpl(
408 asio::io_service& io_service,
409 ssl::context &context,
410 bool fUseSSL) :
411 sslStream(io_service, context),
412 _d(sslStream, fUseSSL),
413 _stream(_d)
414 {
415 }
416
417 virtual std::iostream& stream()
418 {
419 return _stream;
420 }
421
422 virtual std::string peer_address_to_string() const
423 {
424 return peer.address().to_string();
425 }
e9205293 426
a0780ba0
GS
427 virtual void close()
428 {
429 _stream.close();
430 }
431
432 typename Protocol::endpoint peer;
433 asio::ssl::stream<typename Protocol::socket> sslStream;
434
435private:
436 SSLIOStreamDevice<Protocol> _d;
437 iostreams::stream< SSLIOStreamDevice<Protocol> > _stream;
e9205293
DJS
438};
439
21eb5ada 440void ServiceConnection(AcceptedConnection *conn);
69d605f4 441
914dc012 442// Forward declaration required for RPCListen
a0780ba0
GS
443template <typename Protocol, typename SocketAcceptorService>
444static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
914dc012
GS
445 ssl::context& context,
446 bool fUseSSL,
1a445225 447 boost::shared_ptr< AcceptedConnection > conn,
914dc012
GS
448 const boost::system::error_code& error);
449
450/**
451 * Sets up I/O resources to accept and handle a new connection.
452 */
a0780ba0
GS
453template <typename Protocol, typename SocketAcceptorService>
454static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
914dc012
GS
455 ssl::context& context,
456 const bool fUseSSL)
457{
914dc012 458 // Accept connection
1a445225 459 boost::shared_ptr< AcceptedConnectionImpl<Protocol> > conn(new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL));
914dc012
GS
460
461 acceptor->async_accept(
462 conn->sslStream.lowest_layer(),
463 conn->peer,
a0780ba0 464 boost::bind(&RPCAcceptHandler<Protocol, SocketAcceptorService>,
914dc012
GS
465 acceptor,
466 boost::ref(context),
467 fUseSSL,
468 conn,
0a0cd345 469 _1));
914dc012
GS
470}
471
fb78cc23 472
914dc012
GS
473/**
474 * Accept and handle incoming connection.
475 */
a0780ba0
GS
476template <typename Protocol, typename SocketAcceptorService>
477static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
914dc012
GS
478 ssl::context& context,
479 const bool fUseSSL,
1a445225 480 boost::shared_ptr< AcceptedConnection > conn,
914dc012
GS
481 const boost::system::error_code& error)
482{
814efd6f 483 // Immediately start accepting new connections, except when we're cancelled or our socket is closed.
21eb5ada 484 if (error != asio::error::operation_aborted && acceptor->is_open())
ad25804f 485 RPCListen(acceptor, context, fUseSSL);
914dc012 486
1a445225 487 AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn.get());
a0780ba0 488
914dc012
GS
489 if (error)
490 {
0a0cd345
WL
491 // TODO: Actually handle errors
492 LogPrintf("%s: Error: %s\n", __func__, error.message());
914dc012 493 }
914dc012
GS
494 // Restrict callers by IP. It is important to
495 // do this before starting client thread, to filter out
496 // certain DoS and misbehaving clients.
21eb5ada 497 else if (tcp_conn && !ClientAllowed(tcp_conn->peer.address()))
914dc012
GS
498 {
499 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
500 if (!fUseSSL)
285746d3 501 conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
1a445225 502 conn->close();
914dc012 503 }
21eb5ada 504 else {
1a445225 505 ServiceConnection(conn.get());
21eb5ada 506 conn->close();
914dc012 507 }
914dc012
GS
508}
509
21eb5ada 510void StartRPCThreads()
69d605f4 511{
ee219125
WL
512 rpc_allow_subnets.clear();
513 rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
514 rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
515 if (mapMultiArgs.count("-rpcallowip"))
516 {
517 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
518 BOOST_FOREACH(string strAllow, vAllow)
519 {
520 CSubNet subnet(strAllow);
521 if(!subnet.IsValid())
522 {
523 uiInterface.ThreadSafeMessageBox(
524 strprintf("Invalid -rpcallowip subnet specification: %s", strAllow),
525 "", CClientUIInterface::MSG_ERROR);
526 StartShutdown();
527 return;
528 }
529 rpc_allow_subnets.push_back(subnet);
530 }
531 }
532 std::string strAllowed;
533 BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
534 strAllowed += subnet.ToString() + " ";
535 LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
536
f81ce5bd 537 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
0e4b3175
MH
538 if (((mapArgs["-rpcpassword"] == "") ||
539 (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
69d605f4 540 {
b04f301c
GM
541 unsigned char rand_pwd[32];
542 RAND_bytes(rand_pwd, 32);
69d605f4
WL
543 string strWhatAmI = "To use bitcoind";
544 if (mapArgs.count("-server"))
545 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
546 else if (mapArgs.count("-daemon"))
547 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
ab1b288f 548 uiInterface.ThreadSafeMessageBox(strprintf(
90bd933e
PK
549 _("%s, you must set a rpcpassword in the configuration file:\n"
550 "%s\n"
5a60b66a
WL
551 "It is recommended you use the following random password:\n"
552 "rpcuser=bitcoinrpc\n"
553 "rpcpassword=%s\n"
554 "(you do not need to remember this password)\n"
7e1610d5 555 "The username and password MUST NOT be the same.\n"
3d9d2d42
GA
556 "If the file does not exist, create it with owner-readable-only file permissions.\n"
557 "It is also recommended to set alertnotify so you are notified of problems;\n"
558 "for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" [email protected]\n"),
7d9d134b
WL
559 strWhatAmI,
560 GetConfigFile().string(),
561 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
5350ea41 562 "", CClientUIInterface::MSG_ERROR);
9247134e 563 StartShutdown();
69d605f4
WL
564 return;
565 }
566
21eb5ada
GA
567 assert(rpc_io_service == NULL);
568 rpc_io_service = new asio::io_service();
569 rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23);
69d605f4 570
3260b4c0 571 const bool fUseSSL = GetBoolArg("-rpcssl", false);
fbf9df2e 572
69d605f4
WL
573 if (fUseSSL)
574 {
21eb5ada 575 rpc_ssl_context->set_options(ssl::context::no_sslv2);
93fb7489
PK
576
577 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
578 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
21eb5ada 579 if (filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string());
7d9d134b 580 else LogPrintf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string());
93fb7489
PK
581
582 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
583 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
21eb5ada 584 if (filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem);
7d9d134b 585 else LogPrintf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string());
93fb7489 586
1728bf08 587 string strCiphers = GetArg("-rpcsslciphers", "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH");
21eb5ada 588 SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str());
69d605f4 589 }
69d605f4 590
c1ecab81
GS
591 // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets
592 const bool loopback = !mapArgs.count("-rpcallowip");
593 asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any();
0e4b3175 594 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", Params().RPCPort()));
c1d79812 595 boost::system::error_code v6_only_error;
21eb5ada 596 boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
7cf3d2cc 597
c1d79812
PW
598 bool fListening = false;
599 std::string strerr;
c1ecab81
GS
600 try
601 {
ad25804f
GS
602 acceptor->open(endpoint.protocol());
603 acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
c1ecab81
GS
604
605 // Try making the socket dual IPv6/IPv4 (if listening on the "any" address)
ad25804f 606 acceptor->set_option(boost::asio::ip::v6_only(loopback), v6_only_error);
c1ecab81 607
ad25804f
GS
608 acceptor->bind(endpoint);
609 acceptor->listen(socket_base::max_connections);
c1ecab81 610
21eb5ada 611 RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
c1ecab81 612
c1d79812
PW
613 fListening = true;
614 }
615 catch(boost::system::system_error &e)
616 {
95e625d2 617 strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what());
c1d79812
PW
618 }
619
620 try {
c1ecab81 621 // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
c1d79812 622 if (!fListening || loopback || v6_only_error)
c1ecab81
GS
623 {
624 bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any();
625 endpoint.address(bindAddress);
626
21eb5ada 627 acceptor.reset(new ip::tcp::acceptor(*rpc_io_service));
ad25804f
GS
628 acceptor->open(endpoint.protocol());
629 acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
630 acceptor->bind(endpoint);
631 acceptor->listen(socket_base::max_connections);
632
21eb5ada 633 RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
c1d79812
PW
634
635 fListening = true;
c1ecab81
GS
636 }
637 }
638 catch(boost::system::system_error &e)
639 {
463a1cab 640 strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv4: %s"), endpoint.port(), e.what());
c1d79812
PW
641 }
642
643 if (!fListening) {
5350ea41 644 uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR);
07368a9e 645 StartShutdown();
c1ecab81
GS
646 return;
647 }
69d605f4 648
21eb5ada
GA
649 rpc_worker_group = new boost::thread_group();
650 for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
651 rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
652}
653
a8db31c8
WL
654void StartDummyRPCThread()
655{
656 if(rpc_io_service == NULL)
657 {
658 rpc_io_service = new asio::io_service();
659 /* Create dummy "work" to keep the thread from exiting when no timeouts active,
660 * 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 */
661 rpc_dummy_work = new asio::io_service::work(*rpc_io_service);
662 rpc_worker_group = new boost::thread_group();
663 rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
664 }
665}
666
21eb5ada
GA
667void StopRPCThreads()
668{
669 if (rpc_io_service == NULL) return;
670
92f2c1fe 671 deadlineTimers.clear();
21eb5ada 672 rpc_io_service->stop();
b2ba55c4
GA
673 if (rpc_worker_group != NULL)
674 rpc_worker_group->join_all();
a8db31c8 675 delete rpc_dummy_work; rpc_dummy_work = NULL;
21eb5ada
GA
676 delete rpc_worker_group; rpc_worker_group = NULL;
677 delete rpc_ssl_context; rpc_ssl_context = NULL;
678 delete rpc_io_service; rpc_io_service = NULL;
e9205293
DJS
679}
680
92f2c1fe
GA
681void RPCRunHandler(const boost::system::error_code& err, boost::function<void(void)> func)
682{
683 if (!err)
684 func();
685}
686
51ed9ec9 687void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
92f2c1fe
GA
688{
689 assert(rpc_io_service != NULL);
690
691 if (deadlineTimers.count(name) == 0)
692 {
693 deadlineTimers.insert(make_pair(name,
694 boost::shared_ptr<deadline_timer>(new deadline_timer(*rpc_io_service))));
695 }
696 deadlineTimers[name]->expires_from_now(posix_time::seconds(nSeconds));
697 deadlineTimers[name]->async_wait(boost::bind(RPCRunHandler, _1, func));
698}
699
c6494d82
JG
700class JSONRequest
701{
702public:
703 Value id;
704 string strMethod;
705 Array params;
706
707 JSONRequest() { id = Value::null; }
708 void parse(const Value& valRequest);
709};
710
711void JSONRequest::parse(const Value& valRequest)
712{
713 // Parse request
714 if (valRequest.type() != obj_type)
738835d7 715 throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
c6494d82
JG
716 const Object& request = valRequest.get_obj();
717
718 // Parse id now so errors from here on will have the id
719 id = find_value(request, "id");
720
721 // Parse method
722 Value valMethod = find_value(request, "method");
723 if (valMethod.type() == null_type)
738835d7 724 throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
c6494d82 725 if (valMethod.type() != str_type)
738835d7 726 throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
c6494d82 727 strMethod = valMethod.get_str();
44427fa8 728 if (strMethod != "getwork" && strMethod != "getblocktemplate")
7d9d134b 729 LogPrint("rpc", "ThreadRPCServer method=%s\n", strMethod);
c6494d82
JG
730
731 // Parse params
732 Value valParams = find_value(request, "params");
733 if (valParams.type() == array_type)
734 params = valParams.get_array();
735 else if (valParams.type() == null_type)
736 params = Array();
737 else
738835d7 738 throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
c6494d82
JG
739}
740
fb78cc23 741
61338901
JG
742static Object JSONRPCExecOne(const Value& req)
743{
744 Object rpc_result;
745
746 JSONRequest jreq;
747 try {
748 jreq.parse(req);
749
750 Value result = tableRPC.execute(jreq.strMethod, jreq.params);
751 rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
752 }
753 catch (Object& objError)
754 {
755 rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
756 }
757 catch (std::exception& e)
758 {
759 rpc_result = JSONRPCReplyObj(Value::null,
738835d7 760 JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
61338901
JG
761 }
762
763 return rpc_result;
764}
765
766static string JSONRPCExecBatch(const Array& vReq)
767{
768 Array ret;
769 for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
770 ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
771
0db9a805 772 return write_string(Value(ret), false) + "\n";
61338901
JG
773}
774
21eb5ada 775void ServiceConnection(AcceptedConnection *conn)
e9205293 776{
96c52695 777 bool fRun = true;
d138598f 778 while (fRun && !ShutdownRequested())
21eb5ada 779 {
2306dc4b 780 int nProto = 0;
69d605f4 781 map<string, string> mapHeaders;
fcf234fc
JG
782 string strRequest, strMethod, strURI;
783
784 // Read HTTP request line
785 if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI))
786 break;
69d605f4 787
2306dc4b
JG
788 // Read HTTP message headers and body
789 ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
69d605f4 790
9f4976af
JG
791 if (strURI != "/") {
792 conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
793 break;
794 }
795
69d605f4
WL
796 // Check authorization
797 if (mapHeaders.count("authorization") == 0)
798 {
285746d3 799 conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
e9205293 800 break;
69d605f4
WL
801 }
802 if (!HTTPAuthorized(mapHeaders))
803 {
7d9d134b 804 LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
b04f301c 805 /* Deter brute-forcing short passwords.
f65dddc7
PK
806 If this results in a DoS the user really
807 shouldn't have their RPC port exposed. */
b04f301c 808 if (mapArgs["-rpcpassword"].size() < 20)
1b43bf0d 809 MilliSleep(250);
69d605f4 810
285746d3 811 conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
e9205293 812 break;
69d605f4 813 }
96c52695
DJS
814 if (mapHeaders["connection"] == "close")
815 fRun = false;
69d605f4 816
c6494d82 817 JSONRequest jreq;
69d605f4
WL
818 try
819 {
820 // Parse request
821 Value valRequest;
61338901 822 if (!read_string(strRequest, valRequest))
738835d7 823 throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
69d605f4 824
61338901
JG
825 string strReply;
826
827 // singleton request
828 if (valRequest.type() == obj_type) {
829 jreq.parse(valRequest);
c6494d82 830
61338901 831 Value result = tableRPC.execute(jreq.strMethod, jreq.params);
460c51fd 832
61338901
JG
833 // Send reply
834 strReply = JSONRPCReply(result, Value::null, jreq.id);
835
836 // array of requests
837 } else if (valRequest.type() == array_type)
838 strReply = JSONRPCExecBatch(valRequest.get_array());
839 else
738835d7 840 throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
ea0796bd 841
285746d3 842 conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
69d605f4
WL
843 }
844 catch (Object& objError)
845 {
c6494d82 846 ErrorReply(conn->stream(), objError, jreq.id);
e9205293 847 break;
69d605f4
WL
848 }
849 catch (std::exception& e)
850 {
738835d7 851 ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
e9205293 852 break;
69d605f4
WL
853 }
854 }
855}
856
460c51fd
WL
857json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
858{
859 // Find method
860 const CRPCCommand *pcmd = tableRPC[strMethod];
861 if (!pcmd)
738835d7 862 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
48ba56cd 863#ifdef ENABLE_WALLET
b0730874
JG
864 if (pcmd->reqWallet && !pwalletMain)
865 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
48ba56cd 866#endif
69d605f4 867
460c51fd
WL
868 // Observe safe mode
869 string strWarning = GetWarnings("rpc");
3260b4c0 870 if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
460c51fd 871 !pcmd->okSafeMode)
738835d7 872 throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
460c51fd
WL
873
874 try
875 {
876 // Execute
877 Value result;
878 {
10ef3611 879 if (pcmd->threadSafe)
0e1d3551 880 result = pcmd->actor(params, false);
48ba56cd 881#ifdef ENABLE_WALLET
b0730874
JG
882 else if (!pwalletMain) {
883 LOCK(cs_main);
884 result = pcmd->actor(params, false);
885 } else {
0e1d3551
JG
886 LOCK2(cs_main, pwalletMain->cs_wallet);
887 result = pcmd->actor(params, false);
888 }
48ba56cd
WL
889#else // ENABLE_WALLET
890 else {
891 LOCK(cs_main);
892 result = pcmd->actor(params, false);
893 }
894#endif // !ENABLE_WALLET
460c51fd
WL
895 }
896 return result;
897 }
898 catch (std::exception& e)
899 {
738835d7 900 throw JSONRPCError(RPC_MISC_ERROR, e.what());
460c51fd
WL
901 }
902}
69d605f4 903
bbb09365
WL
904std::string HelpExampleCli(string methodname, string args){
905 return "> bitcoin-cli " + methodname + " " + args + "\n";
906}
907
908std::string HelpExampleRpc(string methodname, string args){
909 return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
910 "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
911}
912
e46704dd 913const CRPCTable tableRPC;
This page took 0.396259 seconds and 4 git commands to generate.