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