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