]> Git Repo - VerusCoin.git/blob - src/rpcserver.cpp
Bitcore port
[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 #include "asyncrpcqueue.h"
16
17 #include <memory>
18
19 #include <univalue.h>
20
21 #include <boost/bind.hpp>
22 #include <boost/filesystem.hpp>
23 #include <boost/foreach.hpp>
24 #include <boost/iostreams/concepts.hpp>
25 #include <boost/iostreams/stream.hpp>
26 #include <boost/shared_ptr.hpp>
27 #include <boost/signals2/signal.hpp>
28 #include <boost/thread.hpp>
29 #include <boost/algorithm/string/case_conv.hpp> // for to_upper()
30
31 using namespace RPCServer;
32 using namespace std;
33
34 static bool fRPCRunning = false;
35 static bool fRPCInWarmup = true;
36 static std::string rpcWarmupStatus("RPC server started");
37 static CCriticalSection cs_rpcWarmup;
38 /* Timer-creating functions */
39 static std::vector<RPCTimerInterface*> timerInterfaces;
40 /* Map of name to timer.
41  * @note Can be changed to std::unique_ptr when C++11 */
42 static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers;
43
44 static struct CRPCSignals
45 {
46     boost::signals2::signal<void ()> Started;
47     boost::signals2::signal<void ()> Stopped;
48     boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
49     boost::signals2::signal<void (const CRPCCommand&)> PostCommand;
50 } g_rpcSignals;
51
52 void RPCServer::OnStarted(boost::function<void ()> slot)
53 {
54     g_rpcSignals.Started.connect(slot);
55 }
56
57 void RPCServer::OnStopped(boost::function<void ()> slot)
58 {
59     g_rpcSignals.Stopped.connect(slot);
60 }
61
62 void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot)
63 {
64     g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
65 }
66
67 void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
68 {
69     g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
70 }
71
72 void RPCTypeCheck(const UniValue& params,
73                   const list<UniValue::VType>& typesExpected,
74                   bool fAllowNull)
75 {
76     size_t i = 0;
77     BOOST_FOREACH(UniValue::VType t, typesExpected)
78     {
79         if (params.size() <= i)
80             break;
81
82         const UniValue& v = params[i];
83         if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
84         {
85             string err = strprintf("Expected type %s, got %s",
86                                    uvTypeName(t), uvTypeName(v.type()));
87             throw JSONRPCError(RPC_TYPE_ERROR, err);
88         }
89         i++;
90     }
91 }
92
93 void RPCTypeCheckObj(const UniValue& o,
94                   const map<string, UniValue::VType>& typesExpected,
95                   bool fAllowNull)
96 {
97     BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected)
98     {
99         const UniValue& v = find_value(o, t.first);
100         if (!fAllowNull && v.isNull())
101             throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
102
103         if (!((v.type() == t.second) || (fAllowNull && (v.isNull()))))
104         {
105             string err = strprintf("Expected type %s for %s, got %s",
106                                    uvTypeName(t.second), t.first, uvTypeName(v.type()));
107             throw JSONRPCError(RPC_TYPE_ERROR, err);
108         }
109     }
110 }
111
112 CAmount AmountFromValue(const UniValue& value)
113 {
114     if (!value.isNum() && !value.isStr())
115         throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
116     CAmount amount;
117     if (!ParseFixedPoint(value.getValStr(), 8, &amount))
118         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
119     if (!MoneyRange(amount))
120         throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
121     return amount;
122 }
123
124 UniValue ValueFromAmount(const CAmount& amount)
125 {
126     bool sign = amount < 0;
127     int64_t n_abs = (sign ? -amount : amount);
128     int64_t quotient = n_abs / COIN;
129     int64_t remainder = n_abs % COIN;
130     return UniValue(UniValue::VNUM,
131             strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
132 }
133
134 uint256 ParseHashV(const UniValue& v, string strName)
135 {
136     string strHex;
137     if (v.isStr())
138         strHex = v.get_str();
139     if (!IsHex(strHex)) // Note: IsHex("") is false
140         throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
141     uint256 result;
142     result.SetHex(strHex);
143     return result;
144 }
145 uint256 ParseHashO(const UniValue& o, string strKey)
146 {
147     return ParseHashV(find_value(o, strKey), strKey);
148 }
149 vector<unsigned char> ParseHexV(const UniValue& v, string strName)
150 {
151     string strHex;
152     if (v.isStr())
153         strHex = v.get_str();
154     if (!IsHex(strHex))
155         throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
156     return ParseHex(strHex);
157 }
158 vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
159 {
160     return ParseHexV(find_value(o, strKey), strKey);
161 }
162
163 /**
164  * Note: This interface may still be subject to change.
165  */
166
167 std::string CRPCTable::help(const std::string& strCommand) const
168 {
169     string strRet;
170     string category;
171     set<rpcfn_type> setDone;
172     vector<pair<string, const CRPCCommand*> > vCommands;
173
174     for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
175         vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second));
176     sort(vCommands.begin(), vCommands.end());
177
178     BOOST_FOREACH(const PAIRTYPE(string, const CRPCCommand*)& command, vCommands)
179     {
180         const CRPCCommand *pcmd = command.second;
181         string strMethod = pcmd->name;
182         // We already filter duplicates, but these deprecated screw up the sort order
183         if (strMethod.find("label") != string::npos)
184             continue;
185         if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
186             continue;
187         try
188         {
189             UniValue params;
190             rpcfn_type pfn = pcmd->actor;
191             if (setDone.insert(pfn).second)
192                 (*pfn)(params, true);
193         }
194         catch (const std::exception& e)
195         {
196             // Help text is returned in an exception
197             string strHelp = string(e.what());
198             if (strCommand == "")
199             {
200                 if (strHelp.find('\n') != string::npos)
201                     strHelp = strHelp.substr(0, strHelp.find('\n'));
202
203                 if (category != pcmd->category)
204                 {
205                     if (!category.empty())
206                         strRet += "\n";
207                     category = pcmd->category;
208                     string firstLetter = category.substr(0,1);
209                     boost::to_upper(firstLetter);
210                     strRet += "== " + firstLetter + category.substr(1) + " ==\n";
211                 }
212             }
213             strRet += strHelp + "\n";
214         }
215     }
216     if (strRet == "")
217         strRet = strprintf("help: unknown command: %s\n", strCommand);
218     strRet = strRet.substr(0,strRet.size()-1);
219     return strRet;
220 }
221
222 UniValue help(const UniValue& params, bool fHelp)
223 {
224     if (fHelp || params.size() > 1)
225         throw runtime_error(
226             "help ( \"command\" )\n"
227             "\nList all commands, or get help for a specified command.\n"
228             "\nArguments:\n"
229             "1. \"command\"     (string, optional) The command to get help on\n"
230             "\nResult:\n"
231             "\"text\"     (string) The help text\n"
232         );
233
234     string strCommand;
235     if (params.size() > 0)
236         strCommand = params[0].get_str();
237
238     return tableRPC.help(strCommand);
239 }
240
241
242 UniValue stop(const UniValue& params, bool fHelp)
243 {
244    // Accept the deprecated and ignored 'detach' boolean argument
245     if (fHelp || params.size() > 1)
246         throw runtime_error(
247             "stop\n"
248             "\nStop Komodo server.");
249     // Shutdown will take long enough that the response should get back
250     StartShutdown();
251     return "Komodo server stopping";
252 }
253
254 /**
255  * Call Table
256  */
257 static const CRPCCommand vRPCCommands[] =
258 { //  category              name                      actor (function)         okSafeMode
259   //  --------------------- ------------------------  -----------------------  ----------
260     /* Overall control/query calls */
261     { "control",            "getinfo",                &getinfo,                true  }, /* uses wallet if enabled */
262     { "control",            "help",                   &help,                   true  },
263     { "control",            "stop",                   &stop,                   true  },
264
265     /* P2P networking */
266     { "network",            "getnetworkinfo",         &getnetworkinfo,         true  },
267     { "network",            "addnode",                &addnode,                true  },
268     { "network",            "disconnectnode",         &disconnectnode,         true  },
269     { "network",            "getaddednodeinfo",       &getaddednodeinfo,       true  },
270     { "network",            "getconnectioncount",     &getconnectioncount,     true  },
271     { "network",            "getnettotals",           &getnettotals,           true  },
272     { "network",            "getpeerinfo",            &getpeerinfo,            true  },
273     { "network",            "ping",                   &ping,                   true  },
274     { "network",            "setban",                 &setban,                 true  },
275     { "network",            "listbanned",             &listbanned,             true  },
276     { "network",            "clearbanned",            &clearbanned,            true  },
277
278     /* Block chain and UTXO */
279     { "blockchain",         "getblockchaininfo",      &getblockchaininfo,      true  },
280     { "blockchain",         "getbestblockhash",       &getbestblockhash,       true  },
281     { "blockchain",         "getblockcount",          &getblockcount,          true  },
282     { "blockchain",         "getblock",               &getblock,               true  },
283     { "blockchain",         "getblockdeltas",         &getblockdeltas,         false },
284     { "blockchain",         "getblockhashes",         &getblockhashes,         true  },
285     { "blockchain",         "getblockhash",           &getblockhash,           true  },
286     { "blockchain",         "getblockheader",         &getblockheader,         true  },
287     { "blockchain",         "getchaintips",           &getchaintips,           true  },
288     { "blockchain",         "getdifficulty",          &getdifficulty,          true  },
289     { "blockchain",         "getmempoolinfo",         &getmempoolinfo,         true  },
290     { "blockchain",         "getrawmempool",          &getrawmempool,          true  },
291     { "blockchain",         "gettxout",               &gettxout,               true  },
292     { "blockchain",         "gettxoutproof",          &gettxoutproof,          true  },
293     { "blockchain",         "verifytxoutproof",       &verifytxoutproof,       true  },
294     { "blockchain",         "gettxoutsetinfo",        &gettxoutsetinfo,        true  },
295     { "blockchain",         "verifychain",            &verifychain,            true  },
296     { "blockchain",         "getspentinfo",           &getspentinfo,           false },
297     { "blockchain",         "paxprice",               &paxprice,               true  },
298     { "blockchain",         "paxpending",             &paxpending,             true  },
299     { "blockchain",         "paxprices",              &paxprices,              true  },
300     { "blockchain",         "notaries",               &notaries,               true  },
301     { "blockchain",         "minerids",               &minerids,               true  },
302     { "blockchain",         "kvsearch",               &kvsearch,               true  },
303     { "blockchain",         "kvupdate",               &kvupdate,               true  },
304
305     /* Mining */
306 #ifdef ENABLE_WALLET
307     { "mining",             "getblocktemplate",       &getblocktemplate,       true  },
308 #endif
309     { "mining",             "getmininginfo",          &getmininginfo,          true  },
310     { "mining",             "getlocalsolps",          &getlocalsolps,          true  },
311     { "mining",             "getnetworksolps",        &getnetworksolps,        true  },
312     { "mining",             "getnetworkhashps",       &getnetworkhashps,       true  },
313     { "mining",             "prioritisetransaction",  &prioritisetransaction,  true  },
314     { "mining",             "submitblock",            &submitblock,            true  },
315     { "mining",             "getblocksubsidy",        &getblocksubsidy,        true  },
316
317 #ifdef ENABLE_MINING
318     /* Coin generation */
319     { "generating",         "getgenerate",            &getgenerate,            true  },
320     { "generating",         "setgenerate",            &setgenerate,            true  },
321     { "generating",         "generate",               &generate,               true  },
322 #endif
323
324     /* Raw transactions */
325     { "rawtransactions",    "createrawtransaction",   &createrawtransaction,   true  },
326     { "rawtransactions",    "decoderawtransaction",   &decoderawtransaction,   true  },
327     { "rawtransactions",    "decodescript",           &decodescript,           true  },
328     { "rawtransactions",    "getrawtransaction",      &getrawtransaction,      true  },
329     { "rawtransactions",    "sendrawtransaction",     &sendrawtransaction,     false },
330     { "rawtransactions",    "signrawtransaction",     &signrawtransaction,     false }, /* uses wallet if enabled */
331 #ifdef ENABLE_WALLET
332     { "rawtransactions",    "fundrawtransaction",     &fundrawtransaction,     false },
333 #endif
334
335 /* Address index */
336     { "addressindex",       "getaddressmempool",      &getaddressmempool,      true  },
337     { "addressindex",       "getaddressutxos",        &getaddressutxos,        false },
338     { "addressindex",       "getaddressdeltas",       &getaddressdeltas,       false },
339     { "addressindex",       "getaddresstxids",        &getaddresstxids,        false },
340     { "addressindex",       "getaddressbalance",      &getaddressbalance,      false },
341
342     /* Utility functions */
343     { "util",               "createmultisig",         &createmultisig,         true  },
344     { "util",               "validateaddress",        &validateaddress,        true  }, /* uses wallet if enabled */
345     { "util",               "verifymessage",          &verifymessage,          true  },
346     { "util",               "estimatefee",            &estimatefee,            true  },
347     { "util",               "estimatepriority",       &estimatepriority,       true  },
348     { "util",               "z_validateaddress",      &z_validateaddress,      true  }, /* uses wallet if enabled */
349     { "util",               "jumblr_deposit",       &jumblr_deposit,       true  },
350     { "util",               "jumblr_secret",        &jumblr_secret,       true  },
351     { "util",               "jumblr_pause",        &jumblr_pause,       true  },
352     { "util",               "jumblr_resume",        &jumblr_resume,       true  },
353
354     /* Not shown in help */
355     { "hidden",             "invalidateblock",        &invalidateblock,        true  },
356     { "hidden",             "reconsiderblock",        &reconsiderblock,        true  },
357     { "hidden",             "setmocktime",            &setmocktime,            true  },
358 #ifdef ENABLE_WALLET
359     { "hidden",             "resendwallettransactions", &resendwallettransactions, true},
360 #endif
361
362 #ifdef ENABLE_WALLET
363     /* Wallet */
364     { "wallet",             "addmultisigaddress",     &addmultisigaddress,     true  },
365     { "wallet",             "backupwallet",           &backupwallet,           true  },
366     { "wallet",             "dumpprivkey",            &dumpprivkey,            true  },
367     { "wallet",             "dumpwallet",             &dumpwallet,             true  },
368     { "wallet",             "encryptwallet",          &encryptwallet,          true  },
369     { "wallet",             "getaccountaddress",      &getaccountaddress,      true  },
370     { "wallet",             "getaccount",             &getaccount,             true  },
371     { "wallet",             "getaddressesbyaccount",  &getaddressesbyaccount,  true  },
372     { "wallet",             "getbalance",             &getbalance,             false },
373     { "wallet",             "getnewaddress",          &getnewaddress,          true  },
374     { "wallet",             "getrawchangeaddress",    &getrawchangeaddress,    true  },
375     { "wallet",             "getreceivedbyaccount",   &getreceivedbyaccount,   false },
376     { "wallet",             "getreceivedbyaddress",   &getreceivedbyaddress,   false },
377     { "wallet",             "gettransaction",         &gettransaction,         false },
378     { "wallet",             "getunconfirmedbalance",  &getunconfirmedbalance,  false },
379     { "wallet",             "getwalletinfo",          &getwalletinfo,          false },
380     { "wallet",             "importprivkey",          &importprivkey,          true  },
381     { "wallet",             "importwallet",           &importwallet,           true  },
382     { "wallet",             "importaddress",          &importaddress,          true  },
383     { "wallet",             "keypoolrefill",          &keypoolrefill,          true  },
384     { "wallet",             "listaccounts",           &listaccounts,           false },
385     { "wallet",             "listaddressgroupings",   &listaddressgroupings,   false },
386     { "wallet",             "listlockunspent",        &listlockunspent,        false },
387     { "wallet",             "listreceivedbyaccount",  &listreceivedbyaccount,  false },
388     { "wallet",             "listreceivedbyaddress",  &listreceivedbyaddress,  false },
389     { "wallet",             "listsinceblock",         &listsinceblock,         false },
390     { "wallet",             "listtransactions",       &listtransactions,       false },
391     { "wallet",             "listunspent",            &listunspent,            false },
392     { "wallet",             "lockunspent",            &lockunspent,            true  },
393     { "wallet",             "move",                   &movecmd,                false },
394     { "wallet",             "sendfrom",               &sendfrom,               false },
395     { "wallet",             "sendmany",               &sendmany,               false },
396     { "wallet",             "sendtoaddress",          &sendtoaddress,          false },
397     { "wallet",             "setaccount",             &setaccount,             true  },
398     { "wallet",             "settxfee",               &settxfee,               true  },
399     { "wallet",             "signmessage",            &signmessage,            true  },
400     { "wallet",             "walletlock",             &walletlock,             true  },
401     { "wallet",             "walletpassphrasechange", &walletpassphrasechange, true  },
402     { "wallet",             "walletpassphrase",       &walletpassphrase,       true  },
403     { "wallet",             "zcbenchmark",            &zc_benchmark,           true  },
404     { "wallet",             "zcrawkeygen",            &zc_raw_keygen,          true  },
405     { "wallet",             "zcrawjoinsplit",         &zc_raw_joinsplit,       true  },
406     { "wallet",             "zcrawreceive",           &zc_raw_receive,         true  },
407     { "wallet",             "zcsamplejoinsplit",      &zc_sample_joinsplit,    true  },
408     { "wallet",             "z_listreceivedbyaddress",&z_listreceivedbyaddress,false },
409     { "wallet",             "z_getbalance",           &z_getbalance,           false },
410     { "wallet",             "z_gettotalbalance",      &z_gettotalbalance,      false },
411     { "wallet",             "z_sendmany",             &z_sendmany,             false },
412     { "wallet",             "z_getoperationstatus",   &z_getoperationstatus,   true  },
413     { "wallet",             "z_getoperationresult",   &z_getoperationresult,   true  },
414     { "wallet",             "z_listoperationids",     &z_listoperationids,     true  },
415     { "wallet",             "z_getnewaddress",        &z_getnewaddress,        true  },
416     { "wallet",             "z_listaddresses",        &z_listaddresses,        true  },
417     { "wallet",             "z_exportkey",            &z_exportkey,            true  },
418     { "wallet",             "z_importkey",            &z_importkey,            true  },
419     { "wallet",             "z_exportwallet",         &z_exportwallet,         true  },
420     { "wallet",             "z_importwallet",         &z_importwallet,         true  },
421     
422     { "wallet",             "paxdeposit",             &paxdeposit,             true  },
423     { "wallet",             "paxwithdraw",            &paxwithdraw,            true  }
424 #endif // ENABLE_WALLET
425 };
426
427 CRPCTable::CRPCTable()
428 {
429     unsigned int vcidx;
430     for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
431     {
432         const CRPCCommand *pcmd;
433
434         pcmd = &vRPCCommands[vcidx];
435         mapCommands[pcmd->name] = pcmd;
436     }
437 }
438
439 const CRPCCommand *CRPCTable::operator[](const std::string &name) const
440 {
441     map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
442     if (it == mapCommands.end())
443         return NULL;
444     return (*it).second;
445 }
446
447 bool StartRPC()
448 {
449 /*<<<<<<< HEA
450     std::string addr;
451     int port = defaultPort;
452     SplitHostPort(strEndpoint, port, addr);
453     return ip::tcp::endpoint(boost::asio::ip::address::from_string(addr), port);
454 }
455
456 void StartRPCThreads()
457 {
458     rpc_allow_subnets.clear();
459     rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
460     rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
461     if (mapMultiArgs.count("-rpcallowip"))
462     {
463         const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
464         BOOST_FOREACH(string strAllow, vAllow)
465         {
466             CSubNet subnet(strAllow);
467             if(!subnet.IsValid())
468             {
469                 uiInterface.ThreadSafeMessageBox(
470                     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),
471                     "", CClientUIInterface::MSG_ERROR);
472                 StartShutdown();
473                 return;
474             }
475             rpc_allow_subnets.push_back(subnet);
476         }
477     }
478     std::string strAllowed;
479     BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
480         strAllowed += subnet.ToString() + " ";
481     LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
482
483     if (mapArgs["-rpcpassword"] == "")
484     {
485         LogPrintf("No rpcpassword set - using random cookie authentication\n");
486         if (!GenerateAuthCookie(&strRPCUserColonPass)) {
487             uiInterface.ThreadSafeMessageBox(
488                 _("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode
489                 "", CClientUIInterface::MSG_ERROR);
490             StartShutdown();
491             return;
492         }
493     } else {
494         strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
495     }
496
497     assert(rpc_io_service == NULL);
498     rpc_io_service = new boost::asio::io_service();
499     rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23);
500
501     const bool fUseSSL = GetBoolArg("-rpcssl", false);
502
503     if (fUseSSL)
504     {
505         rpc_ssl_context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3);
506
507         boost::filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
508         if (!pathCertFile.is_complete()) pathCertFile = boost::filesystem::path(GetDataDir()) / pathCertFile;
509         if (boost::filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string());
510         else LogPrintf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string());
511
512         boost::filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
513         if (!pathPKFile.is_complete()) pathPKFile = boost::filesystem::path(GetDataDir()) / pathPKFile;
514         if (boost::filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem);
515         else LogPrintf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string());
516
517         string strCiphers = GetArg("-rpcsslciphers", "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH");
518         SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str());
519     }
520
521     std::vector<ip::tcp::endpoint> vEndpoints;
522     bool bBindAny = false;
523     int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
524     if (!mapArgs.count("-rpcallowip")) // Default to loopback if not allowing external IPs
525     {
526         vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v6::loopback(), defaultPort));
527         vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v4::loopback(), defaultPort));
528         if (mapArgs.count("-rpcbind"))
529         {
530             LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
531         }
532     } else if (mapArgs.count("-rpcbind")) // Specific bind address
533     {
534         BOOST_FOREACH(const std::string &addr, mapMultiArgs["-rpcbind"])
535         {
536             try {
537                 vEndpoints.push_back(ParseEndpoint(addr, defaultPort));
538             }
539             catch (const boost::system::system_error&)
540             {
541                 uiInterface.ThreadSafeMessageBox(
542                     strprintf(_("Could not parse -rpcbind value %s as network address"), addr),
543                     "", CClientUIInterface::MSG_ERROR);
544                 StartShutdown();
545                 return;
546             }
547         }
548     } else { // No specific bind address specified, bind to any
549         vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v6::any(), defaultPort));
550         vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v4::any(), defaultPort));
551         // Prefer making the socket dual IPv6/IPv4 instead of binding
552         // to both addresses separately.
553         bBindAny = true;
554     }
555
556     bool fListening = false;
557     std::string strerr;
558     std::string straddress;
559     BOOST_FOREACH(const ip::tcp::endpoint &endpoint, vEndpoints)
560     {
561         try {
562             boost::asio::ip::address bindAddress = endpoint.address();
563             straddress = bindAddress.to_string();
564             LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", straddress, endpoint.port(), bBindAny);
565             boost::system::error_code v6_only_error;
566             boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
567
568             acceptor->open(endpoint.protocol());
569             acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
570
571             // Try making the socket dual IPv6/IPv4 when listening on the IPv6 "any" address
572             acceptor->set_option(boost::asio::ip::v6_only(
573                 !bBindAny || bindAddress != boost::asio::ip::address_v6::any()), v6_only_error);
574
575             acceptor->bind(endpoint);
576             acceptor->listen(socket_base::max_connections);
577
578             RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
579
580             fListening = true;
581             rpc_acceptors.push_back(acceptor);
582             // If dual IPv6/IPv4 bind successful, skip binding to IPv4 separately
583             if(bBindAny && bindAddress == boost::asio::ip::address_v6::any() && !v6_only_error)
584                 break;
585         }
586         catch (const boost::system::system_error& e)
587         {
588             LogPrintf("ERROR: Binding RPC on address %s port %i failed: %s\n", straddress, endpoint.port(), e.what());
589             strerr = strprintf(_("An error occurred while setting up the RPC address %s port %u for listening: %s"), straddress, endpoint.port(), e.what());
590         }
591     }
592
593     if (!fListening) {
594         uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR);
595         StartShutdown();
596         return;
597     }
598
599     rpc_worker_group = new boost::thread_group();
600     for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
601         rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service));
602 =======
603     LogPrint("rpc", "Starting RPC\n");
604 >>>>>>> zcash/master*/
605     fRPCRunning = true;
606     g_rpcSignals.Started();
607
608     // Launch one async rpc worker.  The ability to launch multiple workers is not recommended at present and thus the option is disabled.
609     //for (int i=0; i<32; i++)
610         getAsyncRPCQueue()->addWorker();
611 /*   
612     int n = GetArg("-rpcasyncthreads", 1);
613     if (n<1) {
614         LogPrintf("ERROR: Invalid value %d for -rpcasyncthreads.  Must be at least 1.\n", n);
615         strerr = strprintf(_("An error occurred while setting up the Async RPC threads, invalid parameter value of %d (must be at least 1)."), n);
616         uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR);
617         StartShutdown();
618         return;
619     }
620     for (int i = 0; i < n; i++)
621         getAsyncRPCQueue()->addWorker();
622 */
623     return true;
624 }
625
626 void InterruptRPC()
627 {
628     LogPrint("rpc", "Interrupting RPC\n");
629     // Interrupt e.g. running longpolls
630     fRPCRunning = false;
631 }
632
633 void StopRPC()
634 {
635     LogPrint("rpc", "Stopping RPC\n");
636     deadlineTimers.clear();
637     g_rpcSignals.Stopped();
638
639     // Tells async queue to cancel all operations and shutdown.
640     LogPrintf("%s: waiting for async rpc workers to stop\n", __func__);
641     getAsyncRPCQueue()->closeAndWait();
642 }
643
644 bool IsRPCRunning()
645 {
646     return fRPCRunning;
647 }
648
649 void SetRPCWarmupStatus(const std::string& newStatus)
650 {
651     LOCK(cs_rpcWarmup);
652     rpcWarmupStatus = newStatus;
653 }
654
655 void SetRPCWarmupFinished()
656 {
657     LOCK(cs_rpcWarmup);
658     assert(fRPCInWarmup);
659     fRPCInWarmup = false;
660 }
661
662 bool RPCIsInWarmup(std::string *outStatus)
663 {
664     LOCK(cs_rpcWarmup);
665     if (outStatus)
666         *outStatus = rpcWarmupStatus;
667     return fRPCInWarmup;
668 }
669
670 void JSONRequest::parse(const UniValue& valRequest)
671 {
672     // Parse request
673     if (!valRequest.isObject())
674         throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
675     const UniValue& request = valRequest.get_obj();
676
677     // Parse id now so errors from here on will have the id
678     id = find_value(request, "id");
679
680     // Parse method
681     UniValue valMethod = find_value(request, "method");
682     if (valMethod.isNull())
683         throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
684     if (!valMethod.isStr())
685         throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
686     strMethod = valMethod.get_str();
687     if (strMethod != "getblocktemplate")
688         LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
689
690     // Parse params
691     UniValue valParams = find_value(request, "params");
692     if (valParams.isArray())
693         params = valParams.get_array();
694     else if (valParams.isNull())
695         params = UniValue(UniValue::VARR);
696     else
697         throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
698 }
699
700 static UniValue JSONRPCExecOne(const UniValue& req)
701 {
702     UniValue rpc_result(UniValue::VOBJ);
703
704     JSONRequest jreq;
705     try {
706         jreq.parse(req);
707
708         UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
709         rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
710     }
711     catch (const UniValue& objError)
712     {
713         rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
714     }
715     catch (const std::exception& e)
716     {
717         rpc_result = JSONRPCReplyObj(NullUniValue,
718                                      JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
719     }
720
721     return rpc_result;
722 }
723
724 std::string JSONRPCExecBatch(const UniValue& vReq)
725 {
726     UniValue ret(UniValue::VARR);
727     for (size_t reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
728         ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
729
730     return ret.write() + "\n";
731 }
732
733 UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
734 {
735     // Return immediately if in warmup
736     {
737         LOCK(cs_rpcWarmup);
738         if (fRPCInWarmup)
739             throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
740     }
741
742 /*<<<<<<< HEA
743     if (!HTTPAuthorized(mapHeaders))
744     {
745         LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
746         //Deter brute-forcing  We don't support exposing the RPC port, so this shouldn't result in a DoS.
747         MilliSleep(250);
748
749         conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
750         return false;
751     }
752     JSONRequest jreq;
753     try
754     {
755         // Parse request
756         Value valRequest;
757         if (!read_string(strRequest, valRequest))
758         {
759             fprintf(stderr,"CANTPARSE.(%s)\n",strRequest.c_str());
760             throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
761         }
762         // Return immediately if in warmup
763         {
764             LOCK(cs_rpcWarmup);
765             if (fRPCInWarmup)
766                 throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
767         }
768
769         string strReply;
770
771         // singleton request
772         if (valRequest.type() == obj_type) {
773             jreq.parse(valRequest);
774
775             Value result = tableRPC.execute(jreq.strMethod, jreq.params);
776
777             // Send reply
778             strReply = JSONRPCReply(result, Value::null, jreq.id);
779
780         // array of requests
781         } else if (valRequest.type() == array_type)
782             strReply = JSONRPCExecBatch(valRequest.get_array());
783         else
784             throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
785
786         conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, strReply.size()) << strReply << std::flush;
787     }
788     catch (const Object& objError)
789     {
790         ErrorReply(conn->stream(), objError, jreq.id);
791         return false;
792     }
793     catch (const std::exception& e)
794     {
795         ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
796         return false;
797     }
798     return true;
799 }
800
801 void ServiceConnection(AcceptedConnection *conn)
802 {
803     bool fRun = true;
804     while (fRun && !ShutdownRequested())
805     {
806         int nProto = 0;
807         map<string, string> mapHeaders;
808         string strRequest, strMethod, strURI;
809
810         // Read HTTP request line
811         if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI))
812             break;
813
814         // Read HTTP message headers and body
815         ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto, MAX_SIZE);
816
817         // TODO #1856: Re-enable support for persistent connections.
818         // We have disabled support for HTTP Keep-Alive until resolution of #1680, upstream rpc deadlock.
819         // Close connection immediately.
820         fRun = false;
821  
822         // HTTP Keep-Alive is false; close connection immediately
823         //if ((mapHeaders["connection"] == "close") || (!GetBoolArg("-rpckeepalive", true)))
824         //    fRun = false;
825  
826
827         // Process via JSON-RPC API
828         if (strURI == "/") {
829             if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
830                 break;
831
832         // Process via HTTP REST API
833         } else if (strURI.substr(0, 6) == "/rest/" && GetBoolArg("-rest", false)) {
834             if (!HTTPReq_REST(conn, strURI, strRequest, mapHeaders, fRun))
835                 break;
836
837         } else {
838             conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
839             break;
840         }
841     }
842 }
843
844 json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
845 {
846 =======
847 >>>>>>> zcash/master*/
848     // Find method
849     const CRPCCommand *pcmd = tableRPC[strMethod];
850     if (!pcmd)
851         throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
852
853     g_rpcSignals.PreCommand(*pcmd);
854
855     try
856     {
857         // Execute
858         return pcmd->actor(params, false);
859     }
860     catch (const std::exception& e)
861     {
862         throw JSONRPCError(RPC_MISC_ERROR, e.what());
863     }
864
865     g_rpcSignals.PostCommand(*pcmd);
866 }
867
868 std::string HelpExampleCli(const std::string& methodname, const std::string& args)
869 {
870     return "> zcash-cli " + methodname + " " + args + "\n";
871 }
872
873 std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
874 {
875     return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
876         "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8232/\n";
877 }
878
879 void RPCRegisterTimerInterface(RPCTimerInterface *iface)
880 {
881     timerInterfaces.push_back(iface);
882 }
883
884 void RPCUnregisterTimerInterface(RPCTimerInterface *iface)
885 {
886     std::vector<RPCTimerInterface*>::iterator i = std::find(timerInterfaces.begin(), timerInterfaces.end(), iface);
887     assert(i != timerInterfaces.end());
888     timerInterfaces.erase(i);
889 }
890
891 void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
892 {
893     if (timerInterfaces.empty())
894         throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
895     deadlineTimers.erase(name);
896     RPCTimerInterface* timerInterface = timerInterfaces[0];
897     LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
898     deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
899 }
900
901 const CRPCTable tableRPC;
902
903 // Return async rpc queue
904 std::shared_ptr<AsyncRPCQueue> getAsyncRPCQueue()
905 {
906     return AsyncRPCQueue::sharedInstance();
907 }
This page took 0.074576 seconds and 4 git commands to generate.