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 11KB

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