aboutsummaryrefslogtreecommitdiff
path: root/src/bitcoin-cli.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bitcoin-cli.cpp')
-rw-r--r--src/bitcoin-cli.cpp257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
new file mode 100644
index 000000000..1269d7a11
--- /dev/null
+++ b/src/bitcoin-cli.cpp
@@ -0,0 +1,257 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "chainparamsbase.h"
+#include "clientversion.h"
+#include "rpcclient.h"
+#include "rpcprotocol.h"
+#include "util.h"
+#include "utilstrencodings.h"
+
+#include <boost/filesystem/operations.hpp>
+
+using namespace std;
+using namespace json_spirit;
+
+std::string HelpMessageCli()
+{
+ string strUsage;
+ strUsage += HelpMessageGroup(_("Options:"));
+ strUsage += HelpMessageOpt("-?", _("This help message"));
+ strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "bitcoin.conf"));
+ strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
+ strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
+ strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be "
+ "solved instantly. This is intended for regression testing tools and app development."));
+ strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1"));
+ strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 8332, 18332));
+ strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
+ strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
+ strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
+
+ strUsage += HelpMessageGroup(_("SSL options: (see the Bitcoin Wiki for SSL setup instructions)"));
+ strUsage += HelpMessageOpt("-rpcssl", _("Use OpenSSL (https) for JSON-RPC connections"));
+
+ return strUsage;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Start
+//
+
+//
+// Exception thrown on connection error. This error is used to determine
+// when to wait if -rpcwait is given.
+//
+class CConnectionFailed : public std::runtime_error
+{
+public:
+
+ explicit inline CConnectionFailed(const std::string& msg) :
+ std::runtime_error(msg)
+ {}
+
+};
+
+static bool AppInitRPC(int argc, char* argv[])
+{
+ //
+ // Parameters
+ //
+ ParseParameters(argc, argv);
+ if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) {
+ std::string strUsage = _("Bitcoin Core RPC client version") + " " + FormatFullVersion() + "\n";
+ if (!mapArgs.count("-version")) {
+ strUsage += "\n" + _("Usage:") + "\n" +
+ " bitcoin-cli [options] <command> [params] " + _("Send command to Bitcoin Core") + "\n" +
+ " bitcoin-cli [options] help " + _("List commands") + "\n" +
+ " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
+
+ strUsage += "\n" + HelpMessageCli();
+ }
+
+ fprintf(stdout, "%s", strUsage.c_str());
+ return false;
+ }
+ if (!boost::filesystem::is_directory(GetDataDir(false))) {
+ fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
+ return false;
+ }
+ try {
+ ReadConfigFile(mapArgs, mapMultiArgs);
+ } catch (const std::exception& e) {
+ fprintf(stderr,"Error reading configuration file: %s\n", e.what());
+ return false;
+ }
+ // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
+ if (!SelectBaseParamsFromCommandLine()) {
+ fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
+ return false;
+ }
+ return true;
+}
+
+Object CallRPC(const string& strMethod, const Array& params)
+{
+ if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+ throw runtime_error(strprintf(
+ _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
+ "If the file does not exist, create it with owner-readable-only file permissions."),
+ GetConfigFile().string().c_str()));
+
+ // Connect to localhost
+ bool fUseSSL = GetBoolArg("-rpcssl", false);
+ boost::asio::io_service io_service;
+ boost::asio::ssl::context context(io_service, boost::asio::ssl::context::sslv23);
+ context.set_options(boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv3);
+ boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslStream(io_service, context);
+ SSLIOStreamDevice<boost::asio::ip::tcp> d(sslStream, fUseSSL);
+ boost::iostreams::stream< SSLIOStreamDevice<boost::asio::ip::tcp> > stream(d);
+
+ const bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(BaseParams().RPCPort())));
+ if (!fConnected)
+ throw CConnectionFailed("couldn't connect to server");
+
+ // HTTP basic authentication
+ string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
+ map<string, string> mapRequestHeaders;
+ mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
+
+ // Send request
+ string strRequest = JSONRPCRequest(strMethod, params, 1);
+ string strPost = HTTPPost(strRequest, mapRequestHeaders);
+ stream << strPost << std::flush;
+
+ // Receive HTTP reply status
+ int nProto = 0;
+ int nStatus = ReadHTTPStatus(stream, nProto);
+
+ // Receive HTTP reply message headers and body
+ map<string, string> mapHeaders;
+ string strReply;
+ ReadHTTPMessage(stream, mapHeaders, strReply, nProto, std::numeric_limits<size_t>::max());
+
+ if (nStatus == HTTP_UNAUTHORIZED)
+ throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
+ else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
+ throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
+ else if (strReply.empty())
+ throw runtime_error("no response from server");
+
+ // Parse reply
+ Value valReply;
+ if (!read_string(strReply, valReply))
+ throw runtime_error("couldn't parse reply from server");
+ const Object& reply = valReply.get_obj();
+ if (reply.empty())
+ throw runtime_error("expected reply to have result, error and id properties");
+
+ return reply;
+}
+
+int CommandLineRPC(int argc, char *argv[])
+{
+ string strPrint;
+ int nRet = 0;
+ try {
+ // Skip switches
+ while (argc > 1 && IsSwitchChar(argv[1][0])) {
+ argc--;
+ argv++;
+ }
+
+ // Method
+ if (argc < 2)
+ throw runtime_error("too few parameters");
+ string strMethod = argv[1];
+
+ // Parameters default to strings
+ std::vector<std::string> strParams(&argv[2], &argv[argc]);
+ Array params = RPCConvertValues(strMethod, strParams);
+
+ // Execute and handle connection failures with -rpcwait
+ const bool fWait = GetBoolArg("-rpcwait", false);
+ do {
+ try {
+ const Object reply = CallRPC(strMethod, params);
+
+ // Parse reply
+ const Value& result = find_value(reply, "result");
+ const Value& error = find_value(reply, "error");
+
+ if (error.type() != null_type) {
+ // Error
+ const int code = find_value(error.get_obj(), "code").get_int();
+ if (fWait && code == RPC_IN_WARMUP)
+ throw CConnectionFailed("server in warmup");
+ strPrint = "error: " + write_string(error, false);
+ nRet = abs(code);
+ } else {
+ // Result
+ if (result.type() == null_type)
+ strPrint = "";
+ else if (result.type() == str_type)
+ strPrint = result.get_str();
+ else
+ strPrint = write_string(result, true);
+ }
+
+ // Connection succeeded, no need to retry.
+ break;
+ }
+ catch (const CConnectionFailed&) {
+ if (fWait)
+ MilliSleep(1000);
+ else
+ throw;
+ }
+ } while (fWait);
+ }
+ catch (const boost::thread_interrupted&) {
+ throw;
+ }
+ catch (const std::exception& e) {
+ strPrint = string("error: ") + e.what();
+ nRet = EXIT_FAILURE;
+ }
+ catch (...) {
+ PrintExceptionContinue(NULL, "CommandLineRPC()");
+ throw;
+ }
+
+ if (strPrint != "") {
+ fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+ }
+ return nRet;
+}
+
+int main(int argc, char* argv[])
+{
+ SetupEnvironment();
+
+ try {
+ if(!AppInitRPC(argc, argv))
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "AppInitRPC()");
+ return EXIT_FAILURE;
+ } catch (...) {
+ PrintExceptionContinue(NULL, "AppInitRPC()");
+ return EXIT_FAILURE;
+ }
+
+ int ret = EXIT_FAILURE;
+ try {
+ ret = CommandLineRPC(argc, argv);
+ }
+ catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "CommandLineRPC()");
+ } catch (...) {
+ PrintExceptionContinue(NULL, "CommandLineRPC()");
+ }
+ return ret;
+}