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