Feathercoin  0.5.0
P2P Digital Currency
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
bitcoinrpc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2013 The Feathercoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include "init.h"
8 #include "util.h"
9 #include "sync.h"
10 #include "ui_interface.h"
11 #include "base58.h"
12 #include "bitcoinrpc.h"
13 #include "db.h"
14 
15 #include <boost/asio.hpp>
16 #include <boost/asio/ip/v6_only.hpp>
17 #include <boost/bind.hpp>
18 #include <boost/filesystem.hpp>
19 #include <boost/foreach.hpp>
20 #include <boost/iostreams/concepts.hpp>
21 #include <boost/iostreams/stream.hpp>
22 #include <boost/algorithm/string.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/asio/ssl.hpp>
25 #include <boost/filesystem/fstream.hpp>
26 #include <boost/shared_ptr.hpp>
27 #include <list>
28 
29 using namespace std;
30 using namespace boost;
31 using namespace boost::asio;
32 using namespace json_spirit;
33 
34 static std::string strRPCUserColonPass;
35 
36 // These are created by StartRPCThreads, destroyed in StopRPCThreads
37 static asio::io_service* rpc_io_service = NULL;
38 static ssl::context* rpc_ssl_context = NULL;
39 static boost::thread_group* rpc_worker_group = NULL;
40 
41 static inline unsigned short GetDefaultRPCPort()
42 {
43  return GetBoolArg("-testnet", false) ? 19337 : 9337;
44 }
45 
46 Object JSONRPCError(int code, const string& message)
47 {
48  Object error;
49  error.push_back(Pair("code", code));
50  error.push_back(Pair("message", message));
51  return error;
52 }
53 
54 void RPCTypeCheck(const Array& params,
55  const list<Value_type>& typesExpected,
56  bool fAllowNull)
57 {
58  unsigned int i = 0;
59  BOOST_FOREACH(Value_type t, typesExpected)
60  {
61  if (params.size() <= i)
62  break;
63 
64  const Value& v = params[i];
65  if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
66  {
67  string err = strprintf("Expected type %s, got %s",
68  Value_type_name[t], Value_type_name[v.type()]);
69  throw JSONRPCError(RPC_TYPE_ERROR, err);
70  }
71  i++;
72  }
73 }
74 
75 void RPCTypeCheck(const Object& o,
76  const map<string, Value_type>& typesExpected,
77  bool fAllowNull)
78 {
79  BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
80  {
81  const Value& v = find_value(o, t.first);
82  if (!fAllowNull && v.type() == null_type)
83  throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first.c_str()));
84 
85  if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
86  {
87  string err = strprintf("Expected type %s for %s, got %s",
88  Value_type_name[t.second], t.first.c_str(), Value_type_name[v.type()]);
89  throw JSONRPCError(RPC_TYPE_ERROR, err);
90  }
91  }
92 }
93 
95 {
96  double dAmount = value.get_real();
97  if (dAmount <= 0.0 || dAmount > 336000000.0)
98  throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
99  int64 nAmount = roundint64(dAmount * COIN);
100  if (!MoneyRange(nAmount))
101  throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
102  return nAmount;
103 }
104 
106 {
107  return (double)amount / (double)COIN;
108 }
109 
110 std::string HexBits(unsigned int nBits)
111 {
112  union {
113  int32_t nBits;
114  char cBits[4];
115  } uBits;
116  uBits.nBits = htonl((int32_t)nBits);
117  return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
118 }
119 
120 
121 
125 
126 string CRPCTable::help(string strCommand) const
127 {
128  string strRet;
129  set<rpcfn_type> setDone;
130  for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
131  {
132  const CRPCCommand *pcmd = mi->second;
133  string strMethod = mi->first;
134  // We already filter duplicates, but these deprecated screw up the sort order
135  if (strMethod.find("label") != string::npos)
136  continue;
137  if (strCommand != "" && strMethod != strCommand)
138  continue;
139  if (pcmd->reqWallet && !pwalletMain)
140  continue;
141 
142  try
143  {
144  Array params;
145  rpcfn_type pfn = pcmd->actor;
146  if (setDone.insert(pfn).second)
147  (*pfn)(params, true);
148  }
149  catch (std::exception& e)
150  {
151  // Help text is returned in an exception
152  string strHelp = string(e.what());
153  if (strCommand == "")
154  if (strHelp.find('\n') != string::npos)
155  strHelp = strHelp.substr(0, strHelp.find('\n'));
156  strRet += strHelp + "\n";
157  }
158  }
159  if (strRet == "")
160  strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
161  strRet = strRet.substr(0,strRet.size()-1);
162  return strRet;
163 }
164 
165 Value help(const Array& params, bool fHelp)
166 {
167  if (fHelp || params.size() > 1)
168  throw runtime_error(
169  "help [command]\n"
170  "List commands, or get help for a command.");
171 
172  string strCommand;
173  if (params.size() > 0)
174  strCommand = params[0].get_str();
175 
176  return tableRPC.help(strCommand);
177 }
178 
179 
180 Value stop(const Array& params, bool fHelp)
181 {
182  // Accept the deprecated and ignored 'detach' boolean argument
183  if (fHelp || params.size() > 1)
184  throw runtime_error(
185  "stop\n"
186  "Stop Feathercoin server.");
187  // Shutdown will take long enough that the response should get back
188  StartShutdown();
189  return "Feathercoin server stopping";
190 }
191 
192 
193 
194 //
195 // Call Table
196 //
197 
198 
199 static const CRPCCommand vRPCCommands[] =
200 { // name actor (function) okSafeMode threadSafe reqWallet
201  // ------------------------ ----------------------- ---------- ---------- ---------
202  { "help", &help, true, true, false },
203  { "stop", &stop, true, true, false },
204  { "getblockcount", &getblockcount, true, false, false },
205  { "getbestblockhash", &getbestblockhash, true, false, false },
206  { "getconnectioncount", &getconnectioncount, true, false, false },
207  { "getpeerinfo", &getpeerinfo, true, false, false },
208  { "addnode", &addnode, true, true, false },
209  { "getaddednodeinfo", &getaddednodeinfo, true, true, false },
210  { "getdifficulty", &getdifficulty, true, false, false },
211  { "getnetworkhashps", &getnetworkhashps, true, false, false },
212  { "getgenerate", &getgenerate, true, false, false },
213  { "setgenerate", &setgenerate, true, false, true },
214  { "gethashespersec", &gethashespersec, true, false, false },
215  { "getinfo", &getinfo, true, false, false },
216  { "getmininginfo", &getmininginfo, true, false, false },
217  { "getnewaddress", &getnewaddress, true, false, true },
218  { "getaccountaddress", &getaccountaddress, true, false, true },
219  { "setaccount", &setaccount, true, false, true },
220  { "getaccount", &getaccount, false, false, true },
221  { "getaddressesbyaccount", &getaddressesbyaccount, true, false, true },
222  { "sendtoaddress", &sendtoaddress, false, false, true },
223  { "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
224  { "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
225  { "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
226  { "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
227  { "backupwallet", &backupwallet, true, false, true },
228  { "keypoolrefill", &keypoolrefill, true, false, true },
229  { "walletpassphrase", &walletpassphrase, true, false, true },
230  { "walletpassphrasechange", &walletpassphrasechange, false, false, true },
231  { "walletlock", &walletlock, true, false, true },
232  { "encryptwallet", &encryptwallet, false, false, true },
233  { "validateaddress", &validateaddress, true, false, false },
234  { "getbalance", &getbalance, false, false, true },
235  { "move", &movecmd, false, false, true },
236  { "sendfrom", &sendfrom, false, false, true },
237  { "sendmany", &sendmany, false, false, true },
238  { "addmultisigaddress", &addmultisigaddress, false, false, true },
239  { "createmultisig", &createmultisig, true, true , false },
240  { "getrawmempool", &getrawmempool, true, false, false },
241  { "getblock", &getblock, false, false, false },
242  { "getblockhash", &getblockhash, false, false, false },
243  { "gettransaction", &gettransaction, false, false, true },
244  { "listtransactions", &listtransactions, false, false, true },
245  { "listaddressgroupings", &listaddressgroupings, false, false, true },
246  { "signmessage", &signmessage, false, false, true },
247  { "verifymessage", &verifymessage, false, false, false },
248  { "getwork", &getwork, true, false, true },
249  { "getworkex", &getworkex, true, false, true },
250  { "listaccounts", &listaccounts, false, false, true },
251  { "settxfee", &settxfee, false, false, true },
252  { "getblocktemplate", &getblocktemplate, true, false, false },
253  { "submitblock", &submitblock, false, false, false },
254  { "setmininput", &setmininput, false, false, false },
255  { "listsinceblock", &listsinceblock, false, false, true },
256  { "dumpprivkey", &dumpprivkey, true, false, true },
257  { "importprivkey", &importprivkey, false, false, true },
258  { "getcheckpoint", &getcheckpoint, true, false, false },
259  { "sendcheckpoint", &sendcheckpoint, true, false, false },
260  { "enforcecheckpoint", &enforcecheckpoint, true, false, false },
261  { "makekeypair", &makekeypair, true, false, false },
262  { "sendalert", &sendalert, true, false, false },
263  { "listunspent", &listunspent, false, false, true },
264  { "getrawtransaction", &getrawtransaction, false, false, false },
265  { "createrawtransaction", &createrawtransaction, false, false, false },
266  { "decoderawtransaction", &decoderawtransaction, false, false, false },
267  { "signrawtransaction", &signrawtransaction, false, false, false },
268  { "sendrawtransaction", &sendrawtransaction, false, false, false },
269  { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
270  { "gettxout", &gettxout, true, false, false },
271  { "lockunspent", &lockunspent, false, false, true },
272  { "listlockunspent", &listlockunspent, false, false, true },
273  { "verifychain", &verifychain, true, false, false },
274 };
275 
277 {
278  unsigned int vcidx;
279  for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
280  {
281  const CRPCCommand *pcmd;
282 
283  pcmd = &vRPCCommands[vcidx];
284  mapCommands[pcmd->name] = pcmd;
285  }
286 }
287 
289 {
290  map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
291  if (it == mapCommands.end())
292  return NULL;
293  return (*it).second;
294 }
295 
296 //
297 // HTTP protocol
298 //
299 // This ain't Apache. We're just using HTTP header for the length field
300 // and to be compatible with other JSON-RPC implementations.
301 //
302 
303 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
304 {
305  ostringstream s;
306  s << "POST / HTTP/1.1\r\n"
307  << "User-Agent: feathercoin-json-rpc/" << FormatFullVersion() << "\r\n"
308  << "Host: 127.0.0.1\r\n"
309  << "Content-Type: application/json\r\n"
310  << "Content-Length: " << strMsg.size() << "\r\n"
311  << "Connection: close\r\n"
312  << "Accept: application/json\r\n";
313  BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
314  s << item.first << ": " << item.second << "\r\n";
315  s << "\r\n" << strMsg;
316 
317  return s.str();
318 }
319 
320 string rfc1123Time()
321 {
322  char buffer[64];
323  time_t now;
324  time(&now);
325  struct tm* now_gmt = gmtime(&now);
326  string locale(setlocale(LC_TIME, NULL));
327  setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings
328  strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
329  setlocale(LC_TIME, locale.c_str());
330  return string(buffer);
331 }
332 
333 static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
334 {
335  if (nStatus == HTTP_UNAUTHORIZED)
336  return strprintf("HTTP/1.0 401 Authorization Required\r\n"
337  "Date: %s\r\n"
338  "Server: feathercoin-json-rpc/%s\r\n"
339  "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
340  "Content-Type: text/html\r\n"
341  "Content-Length: 296\r\n"
342  "\r\n"
343  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
344  "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
345  "<HTML>\r\n"
346  "<HEAD>\r\n"
347  "<TITLE>Error</TITLE>\r\n"
348  "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
349  "</HEAD>\r\n"
350  "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
351  "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
352  const char *cStatus;
353  if (nStatus == HTTP_OK) cStatus = "OK";
354  else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
355  else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
356  else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
357  else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
358  else cStatus = "";
359  return strprintf(
360  "HTTP/1.1 %d %s\r\n"
361  "Date: %s\r\n"
362  "Connection: %s\r\n"
363  "Content-Length: %"PRIszu"\r\n"
364  "Content-Type: application/json\r\n"
365  "Server: feathercoin-json-rpc/%s\r\n"
366  "\r\n"
367  "%s",
368  nStatus,
369  cStatus,
370  rfc1123Time().c_str(),
371  keepalive ? "keep-alive" : "close",
372  strMsg.size(),
373  FormatFullVersion().c_str(),
374  strMsg.c_str());
375 }
376 
377 bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
378  string& http_method, string& http_uri)
379 {
380  string str;
381  getline(stream, str);
382 
383  // HTTP request line is space-delimited
384  vector<string> vWords;
385  boost::split(vWords, str, boost::is_any_of(" "));
386  if (vWords.size() < 2)
387  return false;
388 
389  // HTTP methods permitted: GET, POST
390  http_method = vWords[0];
391  if (http_method != "GET" && http_method != "POST")
392  return false;
393 
394  // HTTP URI must be an absolute path, relative to current host
395  http_uri = vWords[1];
396  if (http_uri.size() == 0 || http_uri[0] != '/')
397  return false;
398 
399  // parse proto, if present
400  string strProto = "";
401  if (vWords.size() > 2)
402  strProto = vWords[2];
403 
404  proto = 0;
405  const char *ver = strstr(strProto.c_str(), "HTTP/1.");
406  if (ver != NULL)
407  proto = atoi(ver+7);
408 
409  return true;
410 }
411 
412 int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
413 {
414  string str;
415  getline(stream, str);
416  vector<string> vWords;
417  boost::split(vWords, str, boost::is_any_of(" "));
418  if (vWords.size() < 2)
420  proto = 0;
421  const char *ver = strstr(str.c_str(), "HTTP/1.");
422  if (ver != NULL)
423  proto = atoi(ver+7);
424  return atoi(vWords[1].c_str());
425 }
426 
427 int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
428 {
429  int nLen = 0;
430  loop
431  {
432  string str;
433  std::getline(stream, str);
434  if (str.empty() || str == "\r")
435  break;
436  string::size_type nColon = str.find(":");
437  if (nColon != string::npos)
438  {
439  string strHeader = str.substr(0, nColon);
440  boost::trim(strHeader);
441  boost::to_lower(strHeader);
442  string strValue = str.substr(nColon+1);
443  boost::trim(strValue);
444  mapHeadersRet[strHeader] = strValue;
445  if (strHeader == "content-length")
446  nLen = atoi(strValue.c_str());
447  }
448  }
449  return nLen;
450 }
451 
452 int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
453  string>& mapHeadersRet, string& strMessageRet,
454  int nProto)
455 {
456  mapHeadersRet.clear();
457  strMessageRet = "";
458 
459  // Read header
460  int nLen = ReadHTTPHeaders(stream, mapHeadersRet);
461  if (nLen < 0 || nLen > (int)MAX_SIZE)
463 
464  // Read message
465  if (nLen > 0)
466  {
467  vector<char> vch(nLen);
468  stream.read(&vch[0], nLen);
469  strMessageRet = string(vch.begin(), vch.end());
470  }
471 
472  string sConHdr = mapHeadersRet["connection"];
473 
474  if ((sConHdr != "close") && (sConHdr != "keep-alive"))
475  {
476  if (nProto >= 1)
477  mapHeadersRet["connection"] = "keep-alive";
478  else
479  mapHeadersRet["connection"] = "close";
480  }
481 
482  return HTTP_OK;
483 }
484 
485 bool HTTPAuthorized(map<string, string>& mapHeaders)
486 {
487  string strAuth = mapHeaders["authorization"];
488  if (strAuth.substr(0,6) != "Basic ")
489  return false;
490  string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
491  string strUserPass = DecodeBase64(strUserPass64);
492  return TimingResistantEqual(strUserPass, strRPCUserColonPass);
493 }
494 
495 //
496 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
497 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
498 // unspecified (HTTP errors and contents of 'error').
499 //
500 // 1.0 spec: http://json-rpc.org/wiki/specification
501 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
502 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
503 //
504 
505 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
506 {
507  Object request;
508  request.push_back(Pair("method", strMethod));
509  request.push_back(Pair("params", params));
510  request.push_back(Pair("id", id));
511  return write_string(Value(request), false) + "\n";
512 }
513 
514 Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
515 {
516  Object reply;
517  if (error.type() != null_type)
518  reply.push_back(Pair("result", Value::null));
519  else
520  reply.push_back(Pair("result", result));
521  reply.push_back(Pair("error", error));
522  reply.push_back(Pair("id", id));
523  return reply;
524 }
525 
526 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
527 {
528  Object reply = JSONRPCReplyObj(result, error, id);
529  return write_string(Value(reply), false) + "\n";
530 }
531 
532 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
533 {
534  // Send error reply from json-rpc error object
535  int nStatus = HTTP_INTERNAL_SERVER_ERROR;
536  int code = find_value(objError, "code").get_int();
537  if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
538  else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
539  string strReply = JSONRPCReply(Value::null, objError, id);
540  stream << HTTPReply(nStatus, strReply, false) << std::flush;
541 }
542 
543 bool ClientAllowed(const boost::asio::ip::address& address)
544 {
545  // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
546  if (address.is_v6()
547  && (address.to_v6().is_v4_compatible()
548  || address.to_v6().is_v4_mapped()))
549  return ClientAllowed(address.to_v6().to_v4());
550 
551  if (address == asio::ip::address_v4::loopback()
552  || address == asio::ip::address_v6::loopback()
553  || (address.is_v4()
554  // Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet)
555  && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000))
556  return true;
557 
558  const string strAddress = address.to_string();
559  const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
560  BOOST_FOREACH(string strAllow, vAllow)
561  if (WildcardMatch(strAddress, strAllow))
562  return true;
563  return false;
564 }
565 
566 //
567 // IOStream device that speaks SSL but can also speak non-SSL
568 //
569 template <typename Protocol>
570 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
571 public:
572  SSLIOStreamDevice(asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn)
573  {
574  fUseSSL = fUseSSLIn;
575  fNeedHandshake = fUseSSLIn;
576  }
577 
578  void handshake(ssl::stream_base::handshake_type role)
579  {
580  if (!fNeedHandshake) return;
581  fNeedHandshake = false;
582  stream.handshake(role);
583  }
584  std::streamsize read(char* s, std::streamsize n)
585  {
586  handshake(ssl::stream_base::server); // HTTPS servers read first
587  if (fUseSSL) return stream.read_some(asio::buffer(s, n));
588  return stream.next_layer().read_some(asio::buffer(s, n));
589  }
590  std::streamsize write(const char* s, std::streamsize n)
591  {
592  handshake(ssl::stream_base::client); // HTTPS clients write first
593  if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
594  return asio::write(stream.next_layer(), asio::buffer(s, n));
595  }
596  bool connect(const std::string& server, const std::string& port)
597  {
598  ip::tcp::resolver resolver(stream.get_io_service());
599  ip::tcp::resolver::query query(server.c_str(), port.c_str());
600  ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
601  ip::tcp::resolver::iterator end;
602  boost::system::error_code error = asio::error::host_not_found;
603  while (error && endpoint_iterator != end)
604  {
605  stream.lowest_layer().close();
606  stream.lowest_layer().connect(*endpoint_iterator++, error);
607  }
608  if (error)
609  return false;
610  return true;
611  }
612 
613 private:
615  bool fUseSSL;
616  asio::ssl::stream<typename Protocol::socket>& stream;
617 };
618 
620 {
621 public:
622  virtual ~AcceptedConnection() {}
623 
624  virtual std::iostream& stream() = 0;
625  virtual std::string peer_address_to_string() const = 0;
626  virtual void close() = 0;
627 };
628 
629 template <typename Protocol>
631 {
632 public:
634  asio::io_service& io_service,
635  ssl::context &context,
636  bool fUseSSL) :
637  sslStream(io_service, context),
638  _d(sslStream, fUseSSL),
639  _stream(_d)
640  {
641  }
642 
643  virtual std::iostream& stream()
644  {
645  return _stream;
646  }
647 
648  virtual std::string peer_address_to_string() const
649  {
650  return peer.address().to_string();
651  }
652 
653  virtual void close()
654  {
655  _stream.close();
656  }
657 
658  typename Protocol::endpoint peer;
659  asio::ssl::stream<typename Protocol::socket> sslStream;
660 
661 private:
663  iostreams::stream< SSLIOStreamDevice<Protocol> > _stream;
664 };
665 
667 
668 // Forward declaration required for RPCListen
669 template <typename Protocol, typename SocketAcceptorService>
670 static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
671  ssl::context& context,
672  bool fUseSSL,
673  AcceptedConnection* conn,
674  const boost::system::error_code& error);
675 
679 template <typename Protocol, typename SocketAcceptorService>
680 static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
681  ssl::context& context,
682  const bool fUseSSL)
683 {
684  // Accept connection
685  AcceptedConnectionImpl<Protocol>* conn = new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL);
686 
687  acceptor->async_accept(
688  conn->sslStream.lowest_layer(),
689  conn->peer,
690  boost::bind(&RPCAcceptHandler<Protocol, SocketAcceptorService>,
691  acceptor,
692  boost::ref(context),
693  fUseSSL,
694  conn,
696 }
697 
701 template <typename Protocol, typename SocketAcceptorService>
702 static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
703  ssl::context& context,
704  const bool fUseSSL,
705  AcceptedConnection* conn,
706  const boost::system::error_code& error)
707 {
708  // Immediately start accepting new connections, except when we're cancelled or our socket is closed.
709  if (error != asio::error::operation_aborted && acceptor->is_open())
710  RPCListen(acceptor, context, fUseSSL);
711 
712  AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn);
713 
714  // TODO: Actually handle errors
715  if (error)
716  {
717  delete conn;
718  }
719 
720  // Restrict callers by IP. It is important to
721  // do this before starting client thread, to filter out
722  // certain DoS and misbehaving clients.
723  else if (tcp_conn && !ClientAllowed(tcp_conn->peer.address()))
724  {
725  // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
726  if (!fUseSSL)
727  conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
728  delete conn;
729  }
730  else {
731  ServiceConnection(conn);
732  conn->close();
733  delete conn;
734  }
735 }
736 
738 {
739  strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
740  if ((mapArgs["-rpcpassword"] == "") ||
741  (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"]))
742  {
743  unsigned char rand_pwd[32];
744  RAND_bytes(rand_pwd, 32);
745  string strWhatAmI = "To use feathercoind";
746  if (mapArgs.count("-server"))
747  strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
748  else if (mapArgs.count("-daemon"))
749  strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
751  _("%s, you must set a rpcpassword in the configuration file:\n"
752  "%s\n"
753  "It is recommended you use the following random password:\n"
754  "rpcuser=feathercoinrpc\n"
755  "rpcpassword=%s\n"
756  "(you do not need to remember this password)\n"
757  "The username and password MUST NOT be the same.\n"
758  "If the file does not exist, create it with owner-readable-only file permissions.\n"
759  "It is also recommended to set alertnotify so you are notified of problems;\n"
760  "for example: alertnotify=echo %%s | mail -s \"Feathercoin Alert\" admin@foo.com\n"),
761  strWhatAmI.c_str(),
762  GetConfigFile().string().c_str(),
763  EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
765  StartShutdown();
766  return;
767  }
768 
769  assert(rpc_io_service == NULL);
770  rpc_io_service = new asio::io_service();
771  rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23);
772 
773  const bool fUseSSL = GetBoolArg("-rpcssl");
774 
775  if (fUseSSL)
776  {
777  rpc_ssl_context->set_options(ssl::context::no_sslv2);
778 
779  filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
780  if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
781  if (filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string());
782  else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
783 
784  filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
785  if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
786  if (filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem);
787  else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
788 
789  string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
790  SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str());
791  }
792 
793  // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets
794  const bool loopback = !mapArgs.count("-rpcallowip");
795  asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any();
796  ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", GetDefaultRPCPort()));
797  boost::system::error_code v6_only_error;
798  boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
799 
800  bool fListening = false;
801  std::string strerr;
802  try
803  {
804  acceptor->open(endpoint.protocol());
805  acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
806 
807  // Try making the socket dual IPv6/IPv4 (if listening on the "any" address)
808  acceptor->set_option(boost::asio::ip::v6_only(loopback), v6_only_error);
809 
810  acceptor->bind(endpoint);
811  acceptor->listen(socket_base::max_connections);
812 
813  RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
814 
815  fListening = true;
816  }
817  catch(boost::system::system_error &e)
818  {
819  strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what());
820  }
821 
822  try {
823  // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
824  if (!fListening || loopback || v6_only_error)
825  {
826  bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any();
827  endpoint.address(bindAddress);
828 
829  acceptor.reset(new ip::tcp::acceptor(*rpc_io_service));
830  acceptor->open(endpoint.protocol());
831  acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
832  acceptor->bind(endpoint);
833  acceptor->listen(socket_base::max_connections);
834 
835  RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
836 
837  fListening = true;
838  }
839  }
840  catch(boost::system::system_error &e)
841  {
842  strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv4: %s"), endpoint.port(), e.what());
843  }
844 
845  if (!fListening) {
847  StartShutdown();
848  return;
849  }
850 
851  rpc_worker_group = new boost::thread_group();
852  for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
853  rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
854 }
855 
857 {
858  if (rpc_io_service == NULL) return;
859 
860  rpc_io_service->stop();
861  rpc_worker_group->join_all();
862  delete rpc_worker_group; rpc_worker_group = NULL;
863  delete rpc_ssl_context; rpc_ssl_context = NULL;
864  delete rpc_io_service; rpc_io_service = NULL;
865 }
866 
868 {
869 public:
871  string strMethod;
873 
874  JSONRequest() { id = Value::null; }
875  void parse(const Value& valRequest);
876 };
877 
878 void JSONRequest::parse(const Value& valRequest)
879 {
880  // Parse request
881  if (valRequest.type() != obj_type)
882  throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
883  const Object& request = valRequest.get_obj();
884 
885  // Parse id now so errors from here on will have the id
886  id = find_value(request, "id");
887 
888  // Parse method
889  Value valMethod = find_value(request, "method");
890  if (valMethod.type() == null_type)
891  throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
892  if (valMethod.type() != str_type)
893  throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
894  strMethod = valMethod.get_str();
895  if (strMethod != "getwork" && strMethod != "getworkex" && strMethod != "getblocktemplate")
896  printf("ThreadRPCServer method=%s\n", strMethod.c_str());
897 
898  // Parse params
899  Value valParams = find_value(request, "params");
900  if (valParams.type() == array_type)
901  params = valParams.get_array();
902  else if (valParams.type() == null_type)
903  params = Array();
904  else
905  throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
906 }
907 
908 static Object JSONRPCExecOne(const Value& req)
909 {
910  Object rpc_result;
911 
912  JSONRequest jreq;
913  try {
914  jreq.parse(req);
915 
916  Value result = tableRPC.execute(jreq.strMethod, jreq.params);
917  rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
918  }
919  catch (Object& objError)
920  {
921  rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
922  }
923  catch (std::exception& e)
924  {
925  rpc_result = JSONRPCReplyObj(Value::null,
926  JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
927  }
928 
929  return rpc_result;
930 }
931 
932 static string JSONRPCExecBatch(const Array& vReq)
933 {
934  Array ret;
935  for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
936  ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
937 
938  return write_string(Value(ret), false) + "\n";
939 }
940 
942 {
943  bool fRun = true;
944  while (fRun)
945  {
946  int nProto = 0;
947  map<string, string> mapHeaders;
948  string strRequest, strMethod, strURI;
949 
950  // Read HTTP request line
951  if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI))
952  break;
953 
954  // Read HTTP message headers and body
955  ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
956 
957  if (strURI != "/") {
958  conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
959  break;
960  }
961 
962  // Check authorization
963  if (mapHeaders.count("authorization") == 0)
964  {
965  conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
966  break;
967  }
968  if (!HTTPAuthorized(mapHeaders))
969  {
970  printf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string().c_str());
971  /* Deter brute-forcing short passwords.
972  If this results in a DOS the user really
973  shouldn't have their RPC port exposed.*/
974  if (mapArgs["-rpcpassword"].size() < 20)
975  MilliSleep(250);
976 
977  conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
978  break;
979  }
980  if (mapHeaders["connection"] == "close")
981  fRun = false;
982 
983  JSONRequest jreq;
984  try
985  {
986  // Parse request
987  Value valRequest;
988  if (!read_string(strRequest, valRequest))
989  throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
990 
991  string strReply;
992 
993  // singleton request
994  if (valRequest.type() == obj_type) {
995  jreq.parse(valRequest);
996 
997  Value result = tableRPC.execute(jreq.strMethod, jreq.params);
998 
999  // Send reply
1000  strReply = JSONRPCReply(result, Value::null, jreq.id);
1001 
1002  // array of requests
1003  } else if (valRequest.type() == array_type)
1004  strReply = JSONRPCExecBatch(valRequest.get_array());
1005  else
1006  throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
1007 
1008  conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
1009  }
1010  catch (Object& objError)
1011  {
1012  ErrorReply(conn->stream(), objError, jreq.id);
1013  break;
1014  }
1015  catch (std::exception& e)
1016  {
1017  ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
1018  break;
1019  }
1020  }
1021 }
1022 
1023 json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
1024 {
1025  // Find method
1026  const CRPCCommand *pcmd = tableRPC[strMethod];
1027  if (!pcmd)
1028  throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
1029  if (pcmd->reqWallet && !pwalletMain)
1030  throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
1031 
1032  // Observe safe mode
1033  string strWarning = GetWarnings("rpc");
1034  if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
1035  !pcmd->okSafeMode)
1036  throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
1037 
1038  try
1039  {
1040  // Execute
1041  Value result;
1042  {
1043  if (pcmd->threadSafe)
1044  result = pcmd->actor(params, false);
1045  else if (!pwalletMain) {
1046  LOCK(cs_main);
1047  result = pcmd->actor(params, false);
1048  } else {
1050  result = pcmd->actor(params, false);
1051  }
1052  }
1053  return result;
1054  }
1055  catch (std::exception& e)
1056  {
1057  throw JSONRPCError(RPC_MISC_ERROR, e.what());
1058  }
1059 }
1060 
1061 
1062 Object CallRPC(const string& strMethod, const Array& params)
1063 {
1064  if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1065  throw runtime_error(strprintf(
1066  _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
1067  "If the file does not exist, create it with owner-readable-only file permissions."),
1068  GetConfigFile().string().c_str()));
1069 
1070  // Connect to localhost
1071  bool fUseSSL = GetBoolArg("-rpcssl");
1072  asio::io_service io_service;
1073  ssl::context context(io_service, ssl::context::sslv23);
1074  context.set_options(ssl::context::no_sslv2);
1075  asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
1076  SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
1077  iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
1078  if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(GetDefaultRPCPort()))))
1079  throw runtime_error("couldn't connect to server");
1080 
1081  // HTTP basic authentication
1082  string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
1083  map<string, string> mapRequestHeaders;
1084  mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
1085 
1086  // Send request
1087  string strRequest = JSONRPCRequest(strMethod, params, 1);
1088  string strPost = HTTPPost(strRequest, mapRequestHeaders);
1089  stream << strPost << std::flush;
1090 
1091  // Receive HTTP reply status
1092  int nProto = 0;
1093  int nStatus = ReadHTTPStatus(stream, nProto);
1094 
1095  // Receive HTTP reply message headers and body
1096  map<string, string> mapHeaders;
1097  string strReply;
1098  ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
1099 
1100  if (nStatus == HTTP_UNAUTHORIZED)
1101  throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
1102  else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
1103  throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
1104  else if (strReply.empty())
1105  throw runtime_error("no response from server");
1106 
1107  // Parse reply
1108  Value valReply;
1109  if (!read_string(strReply, valReply))
1110  throw runtime_error("couldn't parse reply from server");
1111  const Object& reply = valReply.get_obj();
1112  if (reply.empty())
1113  throw runtime_error("expected reply to have result, error and id properties");
1114 
1115  return reply;
1116 }
1117 
1118 
1119 
1120 
1121 template<typename T>
1122 void ConvertTo(Value& value, bool fAllowNull=false)
1123 {
1124  if (fAllowNull && value.type() == null_type)
1125  return;
1126  if (value.type() == str_type)
1127  {
1128  // reinterpret string as unquoted json value
1129  Value value2;
1130  string strJSON = value.get_str();
1131  if (!read_string(strJSON, value2))
1132  throw runtime_error(string("Error parsing JSON:")+strJSON);
1133  ConvertTo<T>(value2, fAllowNull);
1134  value = value2;
1135  }
1136  else
1137  {
1138  value = value.get_value<T>();
1139  }
1140 }
1141 
1142 // Convert strings to command-specific RPC representation
1143 Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
1144 {
1145  Array params;
1146  BOOST_FOREACH(const std::string &param, strParams)
1147  params.push_back(param);
1148 
1149  int n = params.size();
1150 
1151  //
1152  // Special case non-string parameter types
1153  //
1154  if (strMethod == "stop" && n > 0) ConvertTo<bool>(params[0]);
1155  if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo<bool>(params[0]);
1156  if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
1157  if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1158  if (strMethod == "getnetworkhashps" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1159  if (strMethod == "getnetworkhashps" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1160  if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
1161  if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
1162  if (strMethod == "setmininput" && n > 0) ConvertTo<double>(params[0]);
1163  if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1164  if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1165  if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1166  if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
1167  if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1168  if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
1169  if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1170  if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1171  if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
1172  if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
1173  if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
1174  if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
1175  if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1176  if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
1177  if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1178  if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1179  if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]);
1180  if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1181  if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
1182  if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
1183  if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
1184  if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
1185  if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
1186  if (strMethod == "enforcecheckpoint" && n > 0) ConvertTo<bool>(params[0]);
1187  if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]);
1188  if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
1189  if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1190  if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
1191  if (strMethod == "createmultisig" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1192  if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]);
1193  if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1194  if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1195  if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]);
1196  if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
1197  if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1198  if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]);
1199  if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
1200  if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
1201  if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
1202  if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1203  if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
1204  if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
1205  if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
1206  if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
1207  if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]);
1208  if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]);
1209 
1210  return params;
1211 }
1212 
1213 int CommandLineRPC(int argc, char *argv[])
1214 {
1215  string strPrint;
1216  int nRet = 0;
1217  try
1218  {
1219  // Skip switches
1220  while (argc > 1 && IsSwitchChar(argv[1][0]))
1221  {
1222  argc--;
1223  argv++;
1224  }
1225 
1226  // Method
1227  if (argc < 2)
1228  throw runtime_error("too few parameters");
1229  string strMethod = argv[1];
1230 
1231  // Parameters default to strings
1232  std::vector<std::string> strParams(&argv[2], &argv[argc]);
1233  Array params = RPCConvertValues(strMethod, strParams);
1234 
1235  // Execute
1236  Object reply = CallRPC(strMethod, params);
1237 
1238  // Parse reply
1239  const Value& result = find_value(reply, "result");
1240  const Value& error = find_value(reply, "error");
1241 
1242  if (error.type() != null_type)
1243  {
1244  // Error
1245  strPrint = "error: " + write_string(error, false);
1246  int code = find_value(error.get_obj(), "code").get_int();
1247  nRet = abs(code);
1248  }
1249  else
1250  {
1251  // Result
1252  if (result.type() == null_type)
1253  strPrint = "";
1254  else if (result.type() == str_type)
1255  strPrint = result.get_str();
1256  else
1257  strPrint = write_string(result, true);
1258  }
1259  }
1260  catch (boost::thread_interrupted) {
1261  throw;
1262  }
1263  catch (std::exception& e) {
1264  strPrint = string("error: ") + e.what();
1265  nRet = 87;
1266  }
1267  catch (...) {
1268  PrintException(NULL, "CommandLineRPC()");
1269  }
1270 
1271  if (strPrint != "")
1272  {
1273  fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
1274  }
1275  return nRet;
1276 }
1277 
1278 
1279 
1280 
1281 #ifdef TEST
1282 int main(int argc, char *argv[])
1283 {
1284 #ifdef _MSC_VER
1285  // Turn off Microsoft heap dump noise
1286  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1287  _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
1288 #endif
1289  setbuf(stdin, NULL);
1290  setbuf(stdout, NULL);
1291  setbuf(stderr, NULL);
1292 
1293  try
1294  {
1295  if (argc >= 2 && string(argv[1]) == "-server")
1296  {
1297  printf("server ready\n");
1298  ThreadRPCServer(NULL);
1299  }
1300  else
1301  {
1302  return CommandLineRPC(argc, argv);
1303  }
1304  }
1305  catch (boost::thread_interrupted) {
1306  throw;
1307  }
1308  catch (std::exception& e) {
1309  PrintException(&e, "main()");
1310  } catch (...) {
1311  PrintException(NULL, "main()");
1312  }
1313  return 0;
1314 }
1315 #endif
1316 
bool error(const char *format,...)
Definition: util.cpp:358
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
Definition: util.cpp:1060
const Object & get_obj() const
json_spirit::Value enforcecheckpoint(const json_spirit::Array &params, bool fHelp)
#define PRIszu
Definition: util.h:70
string JSONRPCReply(const Value &result, const Value &error, const Value &id)
Definition: bitcoinrpc.cpp:526
json_spirit::Value listtransactions(const json_spirit::Array &params, bool fHelp)
#define strprintf(format,...)
Definition: util.h:169
bool okSafeMode
Definition: bitcoinrpc.h:100
SSLIOStreamDevice< Protocol > _d
Definition: bitcoinrpc.cpp:662
json_spirit::Value decoderawtransaction(const json_spirit::Array &params, bool fHelp)
virtual void close()
Definition: bitcoinrpc.cpp:653
std::streamsize read(char *s, std::streamsize n)
Definition: bitcoinrpc.cpp:584
std::string * value
Definition: version_set.cc:270
Bitcoin RPC command dispatcher.
Definition: bitcoinrpc.h:108
rpcfn_type actor
Definition: bitcoinrpc.h:99
json_spirit::Value getblockcount(const json_spirit::Array &params, bool fHelp)
json_spirit::Value listaccounts(const json_spirit::Array &params, bool fHelp)
void StopRPCThreads()
Definition: bitcoinrpc.cpp:856
iostreams::stream< SSLIOStreamDevice< Protocol > > _stream
Definition: bitcoinrpc.cpp:663
Definition: util.cpp:28
json_spirit::Value makekeypair(const json_spirit::Array &params, bool fHelp)
Value help(const Array &params, bool fHelp)
Definition: bitcoinrpc.cpp:165
json_spirit::Value getbalance(const json_spirit::Array &params, bool fHelp)
bool threadSafe
Definition: bitcoinrpc.h:101
asio::ssl::stream< typename Protocol::socket > sslStream
Definition: bitcoinrpc.cpp:659
bool ReadHTTPRequestLine(std::basic_istream< char > &stream, int &proto, string &http_method, string &http_uri)
Definition: bitcoinrpc.cpp:377
#define PAIRTYPE(t1, t2)
Definition: util.h:78
CCriticalSection cs_wallet
Definition: wallet.h:83
string JSONRPCRequest(const string &strMethod, const Array &params, const Value &id)
Definition: bitcoinrpc.cpp:505
#define END(a)
Definition: util.h:40
json_spirit::Value getworkex(const json_spirit::Array &params, bool fHelp)
json_spirit::Value gettxout(const json_spirit::Array &params, bool fHelp)
void ServiceConnection(AcceptedConnection *conn)
Definition: bitcoinrpc.cpp:941
json_spirit::Value getaccountaddress(const json_spirit::Array &params, bool fHelp)
int64 AmountFromValue(const Value &value)
Definition: bitcoinrpc.cpp:94
json_spirit::Value getaddressesbyaccount(const json_spirit::Array &params, bool fHelp)
json_spirit::Value listaddressgroupings(const json_spirit::Array &params, bool fHelp)
json_spirit::Value gettransaction(const json_spirit::Array &params, bool fHelp)
const CRPCCommand * operator[](std::string name) const
Definition: bitcoinrpc.cpp:288
void StartShutdown()
Definition: init.cpp:82
json_spirit::Value listreceivedbyaccount(const json_spirit::Array &params, bool fHelp)
CCriticalSection cs_main
Definition: main.cpp:32
string GetWarnings(string strFor)
Definition: main.cpp:3075
Value stop(const Array &params, bool fHelp)
Definition: bitcoinrpc.cpp:180
json_spirit::Value execute(const std::string &method, const json_spirit::Array &params) const
Execute a method.
json_spirit::Value createrawtransaction(const json_spirit::Array &params, bool fHelp)
string rfc1123Time()
Definition: bitcoinrpc.cpp:320
json_spirit::Value listreceivedbyaddress(const json_spirit::Array &params, bool fHelp)
json_spirit::Value encryptwallet(const json_spirit::Array &params, bool fHelp)
json_spirit::Value walletpassphrase(const json_spirit::Array &params, bool fHelp)
virtual ~AcceptedConnection()
Definition: bitcoinrpc.cpp:622
json_spirit::Value getrawtransaction(const json_spirit::Array &params, bool fHelp)
#define MAX_SIZE
Definition: mruset_tests.cpp:9
json_spirit::Value sendfrom(const json_spirit::Array &params, bool fHelp)
asio::ssl::stream< typename Protocol::socket > & stream
Definition: bitcoinrpc.cpp:616
int ReadHTTPHeaders(std::basic_istream< char > &stream, map< string, string > &mapHeadersRet)
Definition: bitcoinrpc.cpp:427
json_spirit::Value sendmany(const json_spirit::Array &params, bool fHelp)
json_spirit::Value sendtoaddress(const json_spirit::Array &params, bool fHelp)
int ReadHTTPStatus(std::basic_istream< char > &stream, int &proto)
Definition: bitcoinrpc.cpp:412
Object JSONRPCError(int code, const string &message)
Definition: bitcoinrpc.cpp:46
int CommandLineRPC(int argc, char *argv[])
virtual std::iostream & stream()
Definition: bitcoinrpc.cpp:643
Config::Object_type Object
json_spirit::Value gethashespersec(const json_spirit::Array &params, bool fHelp)
json_spirit::Value keypoolrefill(const json_spirit::Array &params, bool fHelp)
AcceptedConnectionImpl(asio::io_service &io_service, ssl::context &context, bool fUseSSL)
Definition: bitcoinrpc.cpp:633
const Array & get_array() const
json_spirit::Value walletpassphrasechange(const json_spirit::Array &params, bool fHelp)
bool reqWallet
Definition: bitcoinrpc.h:102
Array RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert parameter values for RPC call from strings to command-specific JSON objects.
virtual std::string peer_address_to_string() const
Definition: bitcoinrpc.cpp:648
virtual std::string peer_address_to_string() const =0
json_spirit::Value signmessage(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getbestblockhash(const json_spirit::Array &params, bool fHelp)
void MilliSleep(int64 n)
Definition: util.h:106
json_spirit::Value signrawtransaction(const json_spirit::Array &params, bool fHelp)
#define loop
Definition: util.h:38
int ReadHTTPMessage(std::basic_istream< char > &stream, map< string, string > &mapHeadersRet, string &strMessageRet, int nProto)
Definition: bitcoinrpc.cpp:452
json_spirit::Value walletlock(const json_spirit::Array &params, bool fHelp)
string EncodeBase64(const unsigned char *pch, size_t len)
Definition: util.cpp:628
#define LOCK2(cs1, cs2)
Definition: sync.h:109
std::string name
Definition: bitcoinrpc.h:98
Value_type type() const
Object CallRPC(const string &strMethod, const Array &params)
bool read_string(const String_type &s, Value_type &value)
void RPCTypeCheck(const Array &params, const list< Value_type > &typesExpected, bool fAllowNull)
Definition: bitcoinrpc.cpp:54
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
Definition: util.cpp:600
Config::Value_type Value
json_spirit::Value createmultisig(const json_spirit::Array &params, bool fHelp)
bool HTTPAuthorized(map< string, string > &mapHeaders)
Definition: bitcoinrpc.cpp:485
#define printf
Definition: rpcdump.cpp:12
std::string itostr(int n)
Definition: util.h:248
#define LOCK(cs)
Definition: sync.h:108
const Object_type::value_type::Value_type & find_value(const Object_type &obj, const String_type &name)
json_spirit::Value getgenerate(const json_spirit::Array &params, bool fHelp)
json_spirit::Value addmultisigaddress(const json_spirit::Array &params, bool fHelp)
Object JSONRPCReplyObj(const Value &result, const Value &error, const Value &id)
Definition: bitcoinrpc.cpp:514
json_spirit::Value getaccount(const json_spirit::Array &params, bool fHelp)
json_spirit::Value listlockunspent(const json_spirit::Array &params, bool fHelp)
CClientUIInterface uiInterface
Definition: init.cpp:32
Protocol::endpoint peer
Definition: bitcoinrpc.cpp:658
void write(const Value &value, std::ostream &os)
void handshake(ssl::stream_base::handshake_type role)
Definition: bitcoinrpc.cpp:578
void ErrorReply(std::ostream &stream, const Object &objError, const Value &id)
Definition: bitcoinrpc.cpp:532
CWallet * pwalletMain
Definition: init.cpp:31
json_spirit::Value lockunspent(const json_spirit::Array &params, bool fHelp)
json_spirit::Value dumpprivkey(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getconnectioncount(const json_spirit::Array &params, bool fHelp)
Config::Array_type Array
const String_type & get_str() const
json_spirit::Value importprivkey(const json_spirit::Array &params, bool fHelp)
std::string help(std::string name) const
Note: This interface may still be subject to change.
Definition: bitcoinrpc.cpp:126
std::streamsize write(const char *s, std::streamsize n)
Definition: bitcoinrpc.cpp:590
json_spirit::Value backupwallet(const json_spirit::Array &params, bool fHelp)
json_spirit::Value settxfee(const json_spirit::Array &params, bool fHelp)
json_spirit::Value verifymessage(const json_spirit::Array &params, bool fHelp)
json_spirit::Value validateaddress(const json_spirit::Array &params, bool fHelp)
string HTTPPost(const string &strMsg, const map< string, string > &mapRequestHeaders)
Definition: bitcoinrpc.cpp:303
json_spirit::Value getdifficulty(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getrawmempool(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getblocktemplate(const json_spirit::Array &params, bool fHelp)
std::string HexBits(unsigned int nBits)
Definition: bitcoinrpc.cpp:110
json_spirit::Value getcheckpoint(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getblock(const json_spirit::Array &params, bool fHelp)
json_spirit::Value setgenerate(const json_spirit::Array &params, bool fHelp)
#define BEGIN(a)
Definition: util.h:39
json_spirit::Value addnode(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getpeerinfo(const json_spirit::Array &params, bool fHelp)
bool ClientAllowed(const boost::asio::ip::address &address)
Definition: bitcoinrpc.cpp:543
int main(int argc, char *argv[])
Definition: init.cpp:258
Value_type::String_type write_string(const Value_type &value, bool pretty)
json_spirit::Value(* rpcfn_type)(const json_spirit::Array &params, bool fHelp)
Definition: bitcoinrpc.h:93
json_spirit::Value sendrawtransaction(const json_spirit::Array &params, bool fHelp)
bool IsSwitchChar(char c)
Definition: util.h:368
Value ValueFromAmount(int64 amount)
Definition: bitcoinrpc.cpp:105
json_spirit::Value getnetworkhashps(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getnewaddress(const json_spirit::Array &params, bool fHelp)
string strMethod
Definition: bitcoinrpc.cpp:871
string FormatFullVersion()
Definition: util.cpp:1404
bool WildcardMatch(const char *psz, const char *mask)
Definition: util.cpp:956
json_spirit::Value sendcheckpoint(const json_spirit::Array &params, bool fHelp)
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: ui_interface.h:104
json_spirit::Value movecmd(const json_spirit::Array &params, bool fHelp)
json_spirit::Value verifychain(const json_spirit::Array &params, bool fHelp)
void ConvertTo(Value &value, bool fAllowNull=false)
virtual std::iostream & stream()=0
void parse(const Value &valRequest)
Definition: bitcoinrpc.cpp:878
json_spirit::Value submitblock(const json_spirit::Array &params, bool fHelp)
json_spirit::Value gettxoutsetinfo(const json_spirit::Array &params, bool fHelp)
bool TimingResistantEqual(const T &a, const T &b)
Timing-attack-resistant comparison.
Definition: util.h:450
json_spirit::Value setaccount(const json_spirit::Array &params, bool fHelp)
boost::signals2::signal< bool(const std::string &message, const std::string &caption, unsigned int style), boost::signals2::last_value< bool > > ThreadSafeMessageBox
Show message box.
Definition: ui_interface.h:71
json_spirit::Value getmininginfo(const json_spirit::Array &params, bool fHelp)
std::string EncodeBase58(const unsigned char *pbegin, const unsigned char *pend)
Definition: base58.h:29
json_spirit::Value setmininput(const json_spirit::Array &params, bool fHelp)
SSLIOStreamDevice(asio::ssl::stream< typename Protocol::socket > &streamIn, bool fUseSSLIn)
Definition: bitcoinrpc.cpp:572
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
Definition: util.cpp:586
json_spirit::Value getblockhash(const json_spirit::Array &params, bool fHelp)
virtual void close()=0
const CRPCTable tableRPC
signed int int32_t
Definition: stdint.h:17
vector< unsigned char > DecodeBase64(const char *p, bool *pfInvalid)
Definition: util.cpp:679
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
Definition: util.h:292
std::string get_str(std::string::const_iterator begin, std::string::const_iterator end)
json_spirit::Value getreceivedbyaccount(const json_spirit::Array &params, bool fHelp)
map< string, vector< string > > mapMultiArgs
Definition: util.cpp:72
int64 roundint64(double d)
Definition: util.h:281
Config::Pair_type Pair
json_spirit::Value getinfo(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getaddednodeinfo(const json_spirit::Array &params, bool fHelp)
json_spirit::Value sendalert(const json_spirit::Array &params, bool fHelp)
void StartRPCThreads()
Definition: bitcoinrpc.cpp:737
json_spirit::Value listunspent(const json_spirit::Array &params, bool fHelp)
bool connect(const std::string &server, const std::string &port)
Definition: bitcoinrpc.cpp:596
bool MoneyRange(int64 nValue)
Definition: main.h:58
json_spirit::Value getwork(const json_spirit::Array &params, bool fHelp)
json_spirit::Value getreceivedbyaddress(const json_spirit::Array &params, bool fHelp)
json_spirit::Value listsinceblock(const json_spirit::Array &params, bool fHelp)
map< string, string > mapArgs
Definition: util.cpp:71
int atoi(const std::string &str)
Definition: util.h:271
const char * name
Definition: testharness.cc:18
void PrintException(std::exception *pex, const char *pszThread)
Definition: util.cpp:1014
boost::filesystem::path GetConfigFile()
Definition: util.cpp:1094
long long int64
Definition: serialize.h:25