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