Anoncoin  0.9.4
P2P Digital Currency
rpcclient.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 The Bitcoin developers
3 // Copyright (c) 2013-2014 The Anoncoin Core 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 <set>
8 #include "rpcclient.h"
9 
10 #include "rpcprotocol.h"
11 #include "util.h"
12 #include "ui_interface.h"
13 #include "chainparams.h" // for Params().RPCPort()
14 
15 #include <stdint.h>
16 
17 #include <boost/algorithm/string.hpp>
18 #include <boost/asio.hpp>
19 #include <boost/asio/ssl.hpp>
20 #include <boost/bind.hpp>
21 #include <boost/filesystem.hpp>
22 #include <boost/foreach.hpp>
23 #include <boost/iostreams/concepts.hpp>
24 #include <boost/iostreams/stream.hpp>
25 #include <boost/shared_ptr.hpp>
26 #include "json/json_spirit_writer_template.h"
27 
28 using namespace std;
29 using namespace boost;
30 using namespace boost::asio;
31 using namespace json_spirit;
32 
33 Object CallRPC(const string& strMethod, const Array& params)
34 {
35  if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
36  throw runtime_error(strprintf(
37  _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
38  "If the file does not exist, create it with owner-readable-only file permissions."),
39  GetConfigFile().string().c_str()));
40 
41  // Connect to localhost
42  bool fUseSSL = GetBoolArg("-rpcssl", false);
43  asio::io_service io_service;
44  ssl::context context(io_service, ssl::context::sslv23);
45  context.set_options(ssl::context::no_sslv2);
46  asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
47  SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
48  iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
49 
50  bool fWait = GetBoolArg("-rpcwait", false); // -rpcwait means try until server has started
51  do {
52  bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort())));
53  if (fConnected) break;
54  if (fWait)
55  MilliSleep(1000);
56  else
57  throw runtime_error("couldn't connect to server");
58  } while (fWait);
59 
60  // HTTP basic authentication
61  string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
62  map<string, string> mapRequestHeaders;
63  mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
64 
65  // Send request
66  string strRequest = JSONRPCRequest(strMethod, params, 1);
67  string strPost = HTTPPost(strRequest, mapRequestHeaders);
68  stream << strPost << std::flush;
69 
70  // Receive HTTP reply status
71  int nProto = 0;
72  int nStatus = ReadHTTPStatus(stream, nProto);
73 
74  // Receive HTTP reply message headers and body
75  map<string, string> mapHeaders;
76  string strReply;
77  ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
78 
79  if (nStatus == HTTP_UNAUTHORIZED)
80  throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
81  else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
82  throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
83  else if (strReply.empty())
84  throw runtime_error("no response from server");
85 
86  // Parse reply
87  Value valReply;
88  if (!read_string(strReply, valReply))
89  throw runtime_error("couldn't parse reply from server");
90  const Object& reply = valReply.get_obj();
91  if (reply.empty())
92  throw runtime_error("expected reply to have result, error and id properties");
93 
94  return reply;
95 }
96 
98 {
99 public:
100  std::string methodName; // method whose params want conversion
101  int paramIdx; // 0-based idx of param to convert
102 };
103 
104 static const CRPCConvertParam vRPCConvertParams[] =
105 {
106  { "stop", 0 },
107  { "getaddednodeinfo", 0 },
108  { "setgenerate", 0 },
109  { "setgenerate", 1 },
110  { "getnetworkhashps", 0 },
111  { "getnetworkhashps", 1 },
112  { "sendtoaddress", 1 },
113  { "settxfee", 0 },
114  { "getreceivedbyaddress", 1 },
115  { "getreceivedbyaccount", 1 },
116  { "listreceivedbyaddress", 0 },
117  { "listreceivedbyaddress", 1 },
118  { "listreceivedbyaddress", 2 },
119  { "listreceivedbyaccount", 0 },
120  { "listreceivedbyaccount", 1 },
121  { "listreceivedbyaccount", 2 },
122  { "getbalance", 1 },
123  { "getbalance", 2 },
124  { "getblockhash", 0 },
125  { "move", 2 },
126  { "move", 3 },
127  { "sendfrom", 2 },
128  { "sendfrom", 3 },
129  { "listtransactions", 1 },
130  { "listtransactions", 2 },
131  { "listtransactions", 3 },
132  { "listaccounts", 0 },
133  { "listaccounts", 1 },
134  { "walletpassphrase", 1 },
135  { "getblocktemplate", 0 },
136  { "listsinceblock", 1 },
137  { "listsinceblock", 2 },
138  { "sendmany", 1 },
139  { "sendmany", 2 },
140  { "addmultisigaddress", 0 },
141  { "addmultisigaddress", 1 },
142  { "createmultisig", 0 },
143  { "createmultisig", 1 },
144  { "listunspent", 0 },
145  { "listunspent", 1 },
146  { "listunspent", 2 },
147  { "getblock", 1 },
148  { "gettransaction", 1 },
149  { "getrawtransaction", 1 },
150  { "createrawtransaction", 0 },
151  { "createrawtransaction", 1 },
152  { "signrawtransaction", 1 },
153  { "signrawtransaction", 2 },
154  { "sendrawtransaction", 1 },
155  { "gettxout", 1 },
156  { "gettxout", 2 },
157  { "lockunspent", 0 },
158  { "lockunspent", 1 },
159  { "importprivkey", 2 },
160  { "importaddress", 2 },
161  { "verifychain", 0 },
162  { "verifychain", 1 },
163  { "keypoolrefill", 0 },
164  { "getrawmempool", 0 },
165 };
166 
168 {
169 private:
170  std::set<std::pair<std::string, int> > members;
171 
172 public:
174 
175  bool convert(const std::string& method, int idx) {
176  return (members.count(std::make_pair(method, idx)) > 0);
177  }
178 };
179 
181 {
182  const unsigned int n_elem =
183  (sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0]));
184 
185  for (unsigned int i = 0; i < n_elem; i++) {
186  members.insert(std::make_pair(vRPCConvertParams[i].methodName,
187  vRPCConvertParams[i].paramIdx));
188  }
189 }
190 
191 static CRPCConvertTable rpcCvtTable;
192 
193 // Convert strings to command-specific RPC representation
194 Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
195 {
196  Array params;
197 
198  for (unsigned int idx = 0; idx < strParams.size(); idx++) {
199  const std::string& strVal = strParams[idx];
200 
201  // insert string value directly
202  if (!rpcCvtTable.convert(strMethod, idx)) {
203  params.push_back(strVal);
204  }
205 
206  // parse string as JSON, insert bool/number/object/etc. value
207  else {
208  Value jVal;
209  if (!read_string(strVal, jVal))
210  throw runtime_error(string("Error parsing JSON:")+strVal);
211  params.push_back(jVal);
212  }
213  }
214 
215  return params;
216 }
217 
218 int CommandLineRPC(int argc, char *argv[])
219 {
220  string strPrint;
221  int nRet = 0;
222  try
223  {
224  // Skip switches
225  while (argc > 1 && IsSwitchChar(argv[1][0]))
226  {
227  argc--;
228  argv++;
229  }
230 
231  // Method
232  if (argc < 2)
233  throw runtime_error("too few parameters");
234  string strMethod = argv[1];
235 
236  // Parameters default to strings
237  std::vector<std::string> strParams(&argv[2], &argv[argc]);
238  Array params = RPCConvertValues(strMethod, strParams);
239 
240  // Execute
241  Object reply = CallRPC(strMethod, params);
242 
243  // Parse reply
244  const Value& result = find_value(reply, "result");
245  const Value& error = find_value(reply, "error");
246 
247  if (error.type() != null_type)
248  {
249  // Error
250  strPrint = "error: " + write_string(error, false);
251  int code = find_value(error.get_obj(), "code").get_int();
252  nRet = abs(code);
253  }
254  else
255  {
256  // Result
257  if (result.type() == null_type)
258  strPrint = "";
259  else if (result.type() == str_type)
260  strPrint = result.get_str();
261  else
262  strPrint = write_string(result, true);
263  }
264  }
265  catch (boost::thread_interrupted) {
266  throw;
267  }
268  catch (std::exception& e) {
269  strPrint = string("error: ") + e.what();
270  nRet = EXIT_FAILURE;
271  }
272  catch (...) {
273  PrintExceptionContinue(NULL, "CommandLineRPC()");
274  throw;
275  }
276 
277  if (strPrint != "")
278  {
279  fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
280  }
281  return nRet;
282 }
283 
284 std::string HelpMessageCli(bool mainProgram)
285 {
286  string strUsage;
287  if(mainProgram)
288  {
289  strUsage += _("Options:") + "\n";
290  strUsage += " -? " + _("This help message") + "\n";
291  strUsage += " -conf=<file> " + _("Specify configuration file (default: anoncoin.conf)") + "\n";
292  strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
293  strUsage += " -testnet " + _("Use the test network") + "\n";
294  strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
295  "solved instantly. This is intended for regression testing tools and app development.") + "\n";
296  } else {
297  strUsage += _("RPC client options:") + "\n";
298  }
299 
300  strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
301  strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 9332 or testnet: 19332)") + "\n";
302  strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
303 
304  if(mainProgram)
305  {
306  strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
307  strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
308 
309  strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
310  strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
311  }
312 
313  return strUsage;
314 }
315 
int ReadHTTPStatus(std::basic_istream< char > &stream, int &proto)
std::string HelpMessageCli(bool mainProgram)
Show help message for anoncoin-cli.
Definition: rpcclient.cpp:284
Definition: init.h:14
void MilliSleep(int64_t n)
Definition: util.h:80
#define strprintf
Definition: tinyformat.h:1011
std::set< std::pair< std::string, int > > members
Definition: rpcclient.cpp:170
Object CallRPC(const string &strMethod, const Array &params)
Definition: rpcclient.cpp:33
string EncodeBase64(const unsigned char *pch, size_t len)
Definition: util.cpp:548
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
Definition: util.cpp:520
int ReadHTTPMessage(std::basic_istream< char > &stream, map< string, string > &mapHeadersRet, string &strMessageRet, int nProto)
std::string itostr(int n)
Definition: util.h:212
void PrintExceptionContinue(std::exception *pex, const char *pszThread)
Definition: util.cpp:928
int CommandLineRPC(int argc, char *argv[])
Definition: rpcclient.cpp:218
bool convert(const std::string &method, int idx)
Definition: rpcclient.cpp:175
std::string methodName
Definition: rpcclient.cpp:100
bool IsSwitchChar(char c)
Definition: util.h:325
const CChainParams & Params()
Return the currently selected parameters.
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: ui_interface.h:125
string HTTPPost(const string &strMsg, const map< string, string > &mapRequestHeaders)
Definition: rpcprotocol.cpp:38
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
Definition: util.cpp:506
string JSONRPCRequest(const string &strMethod, const Array &params, const Value &id)
bool connect(const std::string &server, const std::string &port)
Definition: rpcprotocol.h:105
Array RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Definition: rpcclient.cpp:194
map< string, string > mapArgs
Definition: util.cpp:89
boost::filesystem::path GetConfigFile()
Definition: util.cpp:1007