Merge #10114: [tests] sync_with_ping should assert that ping hasn't timed out
[bitcoinplatinum.git] / src / bitcoin-cli.cpp
blobed8ca7e14c50b88c0c08d1be8c070793982d8157
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 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.
6 #if defined(HAVE_CONFIG_H)
7 #include "config/bitcoin-config.h"
8 #endif
10 #include "chainparamsbase.h"
11 #include "clientversion.h"
12 #include "rpc/client.h"
13 #include "rpc/protocol.h"
14 #include "util.h"
15 #include "utilstrencodings.h"
17 #include <boost/filesystem/operations.hpp>
18 #include <stdio.h>
20 #include <event2/buffer.h>
21 #include <event2/keyvalq_struct.h>
22 #include "support/events.h"
24 #include <univalue.h>
26 static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
27 static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
28 static const bool DEFAULT_NAMED=false;
29 static const int CONTINUE_EXECUTION=-1;
31 std::string HelpMessageCli()
33 std::string strUsage;
34 strUsage += HelpMessageGroup(_("Options:"));
35 strUsage += HelpMessageOpt("-?", _("This help message"));
36 strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
37 strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
38 AppendParamsHelpMessages(strUsage);
39 strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
40 strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
41 strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort()));
42 strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
43 strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
44 strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
45 strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
46 strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
48 return strUsage;
51 //////////////////////////////////////////////////////////////////////////////
53 // Start
57 // Exception thrown on connection error. This error is used to determine
58 // when to wait if -rpcwait is given.
60 class CConnectionFailed : public std::runtime_error
62 public:
64 explicit inline CConnectionFailed(const std::string& msg) :
65 std::runtime_error(msg)
71 // This function returns either one of EXIT_ codes when it's expected to stop the process or
72 // CONTINUE_EXECUTION when it's expected to continue further.
74 static int AppInitRPC(int argc, char* argv[])
77 // Parameters
79 ParseParameters(argc, argv);
80 if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) {
81 std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n";
82 if (!IsArgSet("-version")) {
83 strUsage += "\n" + _("Usage:") + "\n" +
84 " bitcoin-cli [options] <command> [params] " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" +
85 " bitcoin-cli [options] -named <command> [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME)) + "\n" +
86 " bitcoin-cli [options] help " + _("List commands") + "\n" +
87 " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
89 strUsage += "\n" + HelpMessageCli();
92 fprintf(stdout, "%s", strUsage.c_str());
93 if (argc < 2) {
94 fprintf(stderr, "Error: too few parameters\n");
95 return EXIT_FAILURE;
97 return EXIT_SUCCESS;
99 if (!boost::filesystem::is_directory(GetDataDir(false))) {
100 fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
101 return EXIT_FAILURE;
103 try {
104 ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
105 } catch (const std::exception& e) {
106 fprintf(stderr,"Error reading configuration file: %s\n", e.what());
107 return EXIT_FAILURE;
109 // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
110 try {
111 SelectBaseParams(ChainNameFromCommandLine());
112 } catch (const std::exception& e) {
113 fprintf(stderr, "Error: %s\n", e.what());
114 return EXIT_FAILURE;
116 if (GetBoolArg("-rpcssl", false))
118 fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
119 return EXIT_FAILURE;
121 return CONTINUE_EXECUTION;
125 /** Reply structure for request_done to fill in */
126 struct HTTPReply
128 HTTPReply(): status(0), error(-1) {}
130 int status;
131 int error;
132 std::string body;
135 const char *http_errorstring(int code)
137 switch(code) {
138 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
139 case EVREQ_HTTP_TIMEOUT:
140 return "timeout reached";
141 case EVREQ_HTTP_EOF:
142 return "EOF reached";
143 case EVREQ_HTTP_INVALID_HEADER:
144 return "error while reading header, or invalid header";
145 case EVREQ_HTTP_BUFFER_ERROR:
146 return "error encountered while reading or writing";
147 case EVREQ_HTTP_REQUEST_CANCEL:
148 return "request was canceled";
149 case EVREQ_HTTP_DATA_TOO_LONG:
150 return "response body is larger than allowed";
151 #endif
152 default:
153 return "unknown";
157 static void http_request_done(struct evhttp_request *req, void *ctx)
159 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
161 if (req == NULL) {
162 /* If req is NULL, it means an error occurred while connecting: the
163 * error code will have been passed to http_error_cb.
165 reply->status = 0;
166 return;
169 reply->status = evhttp_request_get_response_code(req);
171 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
172 if (buf)
174 size_t size = evbuffer_get_length(buf);
175 const char *data = (const char*)evbuffer_pullup(buf, size);
176 if (data)
177 reply->body = std::string(data, size);
178 evbuffer_drain(buf, size);
182 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
183 static void http_error_cb(enum evhttp_request_error err, void *ctx)
185 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
186 reply->error = err;
188 #endif
190 UniValue CallRPC(const std::string& strMethod, const UniValue& params)
192 std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
193 int port = GetArg("-rpcport", BaseParams().RPCPort());
195 // Obtain event base
196 raii_event_base base = obtain_event_base();
198 // Synchronously look up hostname
199 raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
200 evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
202 HTTPReply response;
203 raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
204 if (req == NULL)
205 throw std::runtime_error("create http request failed");
206 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
207 evhttp_request_set_error_cb(req.get(), http_error_cb);
208 #endif
210 // Get credentials
211 std::string strRPCUserColonPass;
212 if (GetArg("-rpcpassword", "") == "") {
213 // Try fall back to cookie-based authentication if no password is provided
214 if (!GetAuthCookie(&strRPCUserColonPass)) {
215 throw std::runtime_error(strprintf(
216 _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
217 GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
220 } else {
221 strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
224 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
225 assert(output_headers);
226 evhttp_add_header(output_headers, "Host", host.c_str());
227 evhttp_add_header(output_headers, "Connection", "close");
228 evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
230 // Attach request data
231 std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
232 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
233 assert(output_buffer);
234 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
236 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
237 req.release(); // ownership moved to evcon in above call
238 if (r != 0) {
239 throw CConnectionFailed("send http request failed");
242 event_base_dispatch(base.get());
244 if (response.status == 0)
245 throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
246 else if (response.status == HTTP_UNAUTHORIZED)
247 throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
248 else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
249 throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
250 else if (response.body.empty())
251 throw std::runtime_error("no response from server");
253 // Parse reply
254 UniValue valReply(UniValue::VSTR);
255 if (!valReply.read(response.body))
256 throw std::runtime_error("couldn't parse reply from server");
257 const UniValue& reply = valReply.get_obj();
258 if (reply.empty())
259 throw std::runtime_error("expected reply to have result, error and id properties");
261 return reply;
264 int CommandLineRPC(int argc, char *argv[])
266 std::string strPrint;
267 int nRet = 0;
268 try {
269 // Skip switches
270 while (argc > 1 && IsSwitchChar(argv[1][0])) {
271 argc--;
272 argv++;
274 std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
275 if (GetBoolArg("-stdin", false)) {
276 // Read one arg per line from stdin and append
277 std::string line;
278 while (std::getline(std::cin,line))
279 args.push_back(line);
281 if (args.size() < 1)
282 throw std::runtime_error("too few parameters (need at least command)");
283 std::string strMethod = args[0];
284 args.erase(args.begin()); // Remove trailing method name from arguments vector
286 UniValue params;
287 if(GetBoolArg("-named", DEFAULT_NAMED)) {
288 params = RPCConvertNamedValues(strMethod, args);
289 } else {
290 params = RPCConvertValues(strMethod, args);
293 // Execute and handle connection failures with -rpcwait
294 const bool fWait = GetBoolArg("-rpcwait", false);
295 do {
296 try {
297 const UniValue reply = CallRPC(strMethod, params);
299 // Parse reply
300 const UniValue& result = find_value(reply, "result");
301 const UniValue& error = find_value(reply, "error");
303 if (!error.isNull()) {
304 // Error
305 int code = error["code"].get_int();
306 if (fWait && code == RPC_IN_WARMUP)
307 throw CConnectionFailed("server in warmup");
308 strPrint = "error: " + error.write();
309 nRet = abs(code);
310 if (error.isObject())
312 UniValue errCode = find_value(error, "code");
313 UniValue errMsg = find_value(error, "message");
314 strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
316 if (errMsg.isStr())
317 strPrint += "error message:\n"+errMsg.get_str();
319 } else {
320 // Result
321 if (result.isNull())
322 strPrint = "";
323 else if (result.isStr())
324 strPrint = result.get_str();
325 else
326 strPrint = result.write(2);
328 // Connection succeeded, no need to retry.
329 break;
331 catch (const CConnectionFailed&) {
332 if (fWait)
333 MilliSleep(1000);
334 else
335 throw;
337 } while (fWait);
339 catch (const boost::thread_interrupted&) {
340 throw;
342 catch (const std::exception& e) {
343 strPrint = std::string("error: ") + e.what();
344 nRet = EXIT_FAILURE;
346 catch (...) {
347 PrintExceptionContinue(NULL, "CommandLineRPC()");
348 throw;
351 if (strPrint != "") {
352 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
354 return nRet;
357 int main(int argc, char* argv[])
359 SetupEnvironment();
360 if (!SetupNetworking()) {
361 fprintf(stderr, "Error: Initializing networking failed\n");
362 return EXIT_FAILURE;
365 try {
366 int ret = AppInitRPC(argc, argv);
367 if (ret != CONTINUE_EXECUTION)
368 return ret;
370 catch (const std::exception& e) {
371 PrintExceptionContinue(&e, "AppInitRPC()");
372 return EXIT_FAILURE;
373 } catch (...) {
374 PrintExceptionContinue(NULL, "AppInitRPC()");
375 return EXIT_FAILURE;
378 int ret = EXIT_FAILURE;
379 try {
380 ret = CommandLineRPC(argc, argv);
382 catch (const std::exception& e) {
383 PrintExceptionContinue(&e, "CommandLineRPC()");
384 } catch (...) {
385 PrintExceptionContinue(NULL, "CommandLineRPC()");
387 return ret;