aboutsummaryrefslogtreecommitdiff
path: root/src/bitcoin-cli.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-05-26 11:38:44 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2014-06-15 15:38:22 +0200
commitb750cf1fb9b6529ab1761b22947677ca78a2c626 (patch)
treed0afe7a6b7f4a33be306f259af83fa871c29146b /src/bitcoin-cli.cpp
parent0cafb630254c6459ea02f6fc47e1c37bb81a1238 (diff)
Remove cli functionality from bitcoind
As it says on the tin. It was deprecated in version 0.9, and at some point it should be removed. Removes the dependency of bitcoind on libbitcoin-cli.a. Move some functions that used to be shared but are now only used in bitcoin-cli.cpp to that file. After this change, an error is printed (and exit code 1 is returned) when the user tries to send RPC commands using bitcoind.
Diffstat (limited to 'src/bitcoin-cli.cpp')
-rw-r--r--src/bitcoin-cli.cpp158
1 files changed, 157 insertions, 1 deletions
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 0c7d6fe5ac..c7327fd7c9 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -12,6 +12,32 @@
#include <boost/filesystem/operations.hpp>
+using namespace boost;
+using namespace boost::asio;
+using namespace json_spirit;
+
+std::string HelpMessageCli()
+{
+ string strUsage;
+ strUsage += _("Options:") + "\n";
+ strUsage += " -? " + _("This help message") + "\n";
+ strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
+ strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
+ strUsage += " -testnet " + _("Use the test network") + "\n";
+ strUsage += " -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.") + "\n";
+ strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
+ strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
+ strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
+ strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
+ strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
+
+ strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
+ strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
+
+ return strUsage;
+}
+
//////////////////////////////////////////////////////////////////////////////
//
// Start
@@ -49,7 +75,7 @@ static bool AppInitRPC(int argc, char* argv[])
" bitcoin-cli [options] help " + _("List commands") + "\n" +
" bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
- strUsage += "\n" + HelpMessageCli(true);
+ strUsage += "\n" + HelpMessageCli();
}
fprintf(stdout, "%s", strUsage.c_str());
@@ -58,6 +84,136 @@ static bool AppInitRPC(int argc, char* argv[])
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);
+ asio::io_service io_service;
+ ssl::context context(io_service, ssl::context::sslv23);
+ context.set_options(ssl::context::no_sslv2);
+ asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
+ SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
+ iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
+
+ bool fWait = GetBoolArg("-rpcwait", false); // -rpcwait means try until server has started
+ do {
+ bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort())));
+ if (fConnected) break;
+ if (fWait)
+ MilliSleep(1000);
+ else
+ throw runtime_error("couldn't connect to server");
+ } while (fWait);
+
+ // 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);
+
+ 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
+ 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
+ strPrint = "error: " + write_string(error, false);
+ int code = find_value(error.get_obj(), "code").get_int();
+ 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);
+ }
+ }
+ catch (boost::thread_interrupted) {
+ throw;
+ }
+ catch (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();