You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bitcoin-cli.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. // Copyright (c) 2009-2010 Satoshi Nakamoto
  2. // Copyright (c) 2009-2015 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. #include "chainparamsbase.h"
  6. #include "clientversion.h"
  7. #include "rpcclient.h"
  8. #include "rpcprotocol.h"
  9. #include "util.h"
  10. #include "utilstrencodings.h"
  11. #include <boost/filesystem/operations.hpp>
  12. #include <stdio.h>
  13. #include <event2/event.h>
  14. #include <event2/http.h>
  15. #include <event2/buffer.h>
  16. #include <event2/keyvalq_struct.h>
  17. #include <univalue.h>
  18. using namespace std;
  19. static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
  20. static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
  21. std::string HelpMessageCli()
  22. {
  23. string strUsage;
  24. strUsage += HelpMessageGroup(_("Options:"));
  25. strUsage += HelpMessageOpt("-?", _("This help message"));
  26. strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
  27. strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
  28. AppendParamsHelpMessages(strUsage);
  29. strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
  30. strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort()));
  31. strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
  32. strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
  33. strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
  34. strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
  35. return strUsage;
  36. }
  37. //////////////////////////////////////////////////////////////////////////////
  38. //
  39. // Start
  40. //
  41. //
  42. // Exception thrown on connection error. This error is used to determine
  43. // when to wait if -rpcwait is given.
  44. //
  45. class CConnectionFailed : public std::runtime_error
  46. {
  47. public:
  48. explicit inline CConnectionFailed(const std::string& msg) :
  49. std::runtime_error(msg)
  50. {}
  51. };
  52. static bool AppInitRPC(int argc, char* argv[])
  53. {
  54. //
  55. // Parameters
  56. //
  57. ParseParameters(argc, argv);
  58. if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) {
  59. std::string strUsage = _("Bitcoin Core RPC client version") + " " + FormatFullVersion() + "\n";
  60. if (!mapArgs.count("-version")) {
  61. strUsage += "\n" + _("Usage:") + "\n" +
  62. " bitcoin-cli [options] <command> [params] " + _("Send command to Bitcoin Core") + "\n" +
  63. " bitcoin-cli [options] help " + _("List commands") + "\n" +
  64. " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
  65. strUsage += "\n" + HelpMessageCli();
  66. }
  67. fprintf(stdout, "%s", strUsage.c_str());
  68. return false;
  69. }
  70. if (!boost::filesystem::is_directory(GetDataDir(false))) {
  71. fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
  72. return false;
  73. }
  74. try {
  75. ReadConfigFile(mapArgs, mapMultiArgs);
  76. } catch (const std::exception& e) {
  77. fprintf(stderr,"Error reading configuration file: %s\n", e.what());
  78. return false;
  79. }
  80. // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
  81. try {
  82. SelectBaseParams(ChainNameFromCommandLine());
  83. } catch (const std::exception& e) {
  84. fprintf(stderr, "Error: %s\n", e.what());
  85. return false;
  86. }
  87. if (GetBoolArg("-rpcssl", false))
  88. {
  89. fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
  90. return false;
  91. }
  92. return true;
  93. }
  94. /** Reply structure for request_done to fill in */
  95. struct HTTPReply
  96. {
  97. int status;
  98. std::string body;
  99. };
  100. static void http_request_done(struct evhttp_request *req, void *ctx)
  101. {
  102. HTTPReply *reply = static_cast<HTTPReply*>(ctx);
  103. if (req == NULL) {
  104. /* If req is NULL, it means an error occurred while connecting, but
  105. * I'm not sure how to find out which one. We also don't really care.
  106. */
  107. reply->status = 0;
  108. return;
  109. }
  110. reply->status = evhttp_request_get_response_code(req);
  111. struct evbuffer *buf = evhttp_request_get_input_buffer(req);
  112. if (buf)
  113. {
  114. size_t size = evbuffer_get_length(buf);
  115. const char *data = (const char*)evbuffer_pullup(buf, size);
  116. if (data)
  117. reply->body = std::string(data, size);
  118. evbuffer_drain(buf, size);
  119. }
  120. }
  121. UniValue CallRPC(const string& strMethod, const UniValue& params)
  122. {
  123. std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
  124. int port = GetArg("-rpcport", BaseParams().RPCPort());
  125. // Create event base
  126. struct event_base *base = event_base_new(); // TODO RAII
  127. if (!base)
  128. throw runtime_error("cannot create event_base");
  129. // Synchronously look up hostname
  130. struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
  131. if (evcon == NULL)
  132. throw runtime_error("create connection failed");
  133. evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
  134. HTTPReply response;
  135. struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
  136. if (req == NULL)
  137. throw runtime_error("create http request failed");
  138. // Get credentials
  139. std::string strRPCUserColonPass;
  140. if (mapArgs["-rpcpassword"] == "") {
  141. // Try fall back to cookie-based authentication if no password is provided
  142. if (!GetAuthCookie(&strRPCUserColonPass)) {
  143. throw runtime_error(strprintf(
  144. _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
  145. GetConfigFile().string().c_str()));
  146. }
  147. } else {
  148. strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
  149. }
  150. struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req);
  151. assert(output_headers);
  152. evhttp_add_header(output_headers, "Host", host.c_str());
  153. evhttp_add_header(output_headers, "Connection", "close");
  154. evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
  155. // Attach request data
  156. std::string strRequest = JSONRPCRequest(strMethod, params, 1);
  157. struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req);
  158. assert(output_buffer);
  159. evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
  160. int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/");
  161. if (r != 0) {
  162. evhttp_connection_free(evcon);
  163. event_base_free(base);
  164. throw CConnectionFailed("send http request failed");
  165. }
  166. event_base_dispatch(base);
  167. evhttp_connection_free(evcon);
  168. event_base_free(base);
  169. if (response.status == 0)
  170. throw CConnectionFailed("couldn't connect to server");
  171. else if (response.status == HTTP_UNAUTHORIZED)
  172. throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
  173. else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
  174. throw runtime_error(strprintf("server returned HTTP error %d", response.status));
  175. else if (response.body.empty())
  176. throw runtime_error("no response from server");
  177. // Parse reply
  178. UniValue valReply(UniValue::VSTR);
  179. if (!valReply.read(response.body))
  180. throw runtime_error("couldn't parse reply from server");
  181. const UniValue& reply = valReply.get_obj();
  182. if (reply.empty())
  183. throw runtime_error("expected reply to have result, error and id properties");
  184. return reply;
  185. }
  186. int CommandLineRPC(int argc, char *argv[])
  187. {
  188. string strPrint;
  189. int nRet = 0;
  190. try {
  191. // Skip switches
  192. while (argc > 1 && IsSwitchChar(argv[1][0])) {
  193. argc--;
  194. argv++;
  195. }
  196. // Method
  197. if (argc < 2)
  198. throw runtime_error("too few parameters");
  199. string strMethod = argv[1];
  200. // Parameters default to strings
  201. std::vector<std::string> strParams(&argv[2], &argv[argc]);
  202. UniValue params = RPCConvertValues(strMethod, strParams);
  203. // Execute and handle connection failures with -rpcwait
  204. const bool fWait = GetBoolArg("-rpcwait", false);
  205. do {
  206. try {
  207. const UniValue reply = CallRPC(strMethod, params);
  208. // Parse reply
  209. const UniValue& result = find_value(reply, "result");
  210. const UniValue& error = find_value(reply, "error");
  211. if (!error.isNull()) {
  212. // Error
  213. int code = error["code"].get_int();
  214. if (fWait && code == RPC_IN_WARMUP)
  215. throw CConnectionFailed("server in warmup");
  216. strPrint = "error: " + error.write();
  217. nRet = abs(code);
  218. if (error.isObject())
  219. {
  220. UniValue errCode = find_value(error, "code");
  221. UniValue errMsg = find_value(error, "message");
  222. strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
  223. if (errMsg.isStr())
  224. strPrint += "error message:\n"+errMsg.get_str();
  225. }
  226. } else {
  227. // Result
  228. if (result.isNull())
  229. strPrint = "";
  230. else if (result.isStr())
  231. strPrint = result.get_str();
  232. else
  233. strPrint = result.write(2);
  234. }
  235. // Connection succeeded, no need to retry.
  236. break;
  237. }
  238. catch (const CConnectionFailed&) {
  239. if (fWait)
  240. MilliSleep(1000);
  241. else
  242. throw;
  243. }
  244. } while (fWait);
  245. }
  246. catch (const boost::thread_interrupted&) {
  247. throw;
  248. }
  249. catch (const std::exception& e) {
  250. strPrint = string("error: ") + e.what();
  251. nRet = EXIT_FAILURE;
  252. }
  253. catch (...) {
  254. PrintExceptionContinue(NULL, "CommandLineRPC()");
  255. throw;
  256. }
  257. if (strPrint != "") {
  258. fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
  259. }
  260. return nRet;
  261. }
  262. int main(int argc, char* argv[])
  263. {
  264. SetupEnvironment();
  265. if (!SetupNetworking()) {
  266. fprintf(stderr, "Error: Initializing networking failed\n");
  267. exit(1);
  268. }
  269. try {
  270. if(!AppInitRPC(argc, argv))
  271. return EXIT_FAILURE;
  272. }
  273. catch (const std::exception& e) {
  274. PrintExceptionContinue(&e, "AppInitRPC()");
  275. return EXIT_FAILURE;
  276. } catch (...) {
  277. PrintExceptionContinue(NULL, "AppInitRPC()");
  278. return EXIT_FAILURE;
  279. }
  280. int ret = EXIT_FAILURE;
  281. try {
  282. ret = CommandLineRPC(argc, argv);
  283. }
  284. catch (const std::exception& e) {
  285. PrintExceptionContinue(&e, "CommandLineRPC()");
  286. } catch (...) {
  287. PrintExceptionContinue(NULL, "CommandLineRPC()");
  288. }
  289. return ret;
  290. }