]> Git Repo - VerusCoin.git/blob - src/bitcoin-cli.cpp
print the caught error instead of raising an error
[VerusCoin.git] / src / bitcoin-cli.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "chainparamsbase.h"
7 #include "clientversion.h"
8 #include "rpcclient.h"
9 #include "rpcprotocol.h"
10 #include "util.h"
11 #include "utilstrencodings.h"
12
13 #include <boost/filesystem/operations.hpp>
14
15 #define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */
16
17 using namespace std;
18 using namespace boost;
19 using namespace boost::asio;
20 using namespace json_spirit;
21
22 std::string HelpMessageCli()
23 {
24     string strUsage;
25     strUsage += _("Options:") + "\n";
26     strUsage += "  -?                     " + _("This help message") + "\n";
27     strUsage += "  -conf=<file>           " + strprintf(_("Specify configuration file (default: %s)"), "bitcoin.conf") + "\n";
28     strUsage += "  -datadir=<dir>         " + _("Specify data directory") + "\n";
29     strUsage += "  -testnet               " + _("Use the test network") + "\n";
30     strUsage += "  -regtest               " + _("Enter regression test mode, which uses a special chain in which blocks can be "
31                                                 "solved instantly. This is intended for regression testing tools and app development.") + "\n";
32     strUsage += "  -rpcconnect=<ip>       " + strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1") + "\n";
33     strUsage += "  -rpcport=<port>        " + strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 8332, 18332) + "\n";
34     strUsage += "  -rpcwait               " + _("Wait for RPC server to start") + "\n";
35     strUsage += "  -rpcuser=<user>        " + _("Username for JSON-RPC connections") + "\n";
36     strUsage += "  -rpcpassword=<pw>      " + _("Password for JSON-RPC connections") + "\n";
37
38     strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
39     strUsage += "  -rpcssl                " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
40
41     return strUsage;
42 }
43
44 //////////////////////////////////////////////////////////////////////////////
45 //
46 // Start
47 //
48
49 //
50 // Exception thrown on connection error.  This error is used to determine
51 // when to wait if -rpcwait is given.
52 //
53 class CConnectionFailed : public std::runtime_error
54 {
55 public:
56
57     explicit inline CConnectionFailed(const std::string& msg) :
58         std::runtime_error(msg)
59     {}
60
61 };
62
63 static bool AppInitRPC(int argc, char* argv[])
64 {
65     //
66     // Parameters
67     //
68     ParseParameters(argc, argv);
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(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 (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) {
85         std::string strUsage = _("Bitcoin Core RPC client version") + " " + FormatFullVersion() + "\n";
86         if (!mapArgs.count("-version")) {
87             strUsage += "\n" + _("Usage:") + "\n" +
88                   "  bitcoin-cli [options] <command> [params]  " + _("Send command to Bitcoin Core") + "\n" +
89                   "  bitcoin-cli [options] help                " + _("List commands") + "\n" +
90                   "  bitcoin-cli [options] help <command>      " + _("Get help for a command") + "\n";
91
92             strUsage += "\n" + HelpMessageCli();
93         }
94
95         fprintf(stdout, "%s", strUsage.c_str());
96         return false;
97     }
98     return true;
99 }
100
101 Object CallRPC(const string& strMethod, const Array& params)
102 {
103     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
104         throw runtime_error(strprintf(
105             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
106               "If the file does not exist, create it with owner-readable-only file permissions."),
107                 GetConfigFile().string().c_str()));
108
109     // Connect to localhost
110     bool fUseSSL = GetBoolArg("-rpcssl", false);
111     asio::io_service io_service;
112     ssl::context context(io_service, ssl::context::sslv23);
113     context.set_options(ssl::context::no_sslv2);
114     asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
115     SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
116     iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
117
118     const bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(BaseParams().RPCPort())));
119     if (!fConnected)
120         throw CConnectionFailed("couldn't connect to server");
121
122     // HTTP basic authentication
123     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
124     map<string, string> mapRequestHeaders;
125     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
126
127     // Send request
128     string strRequest = JSONRPCRequest(strMethod, params, 1);
129     string strPost = HTTPPost(strRequest, mapRequestHeaders);
130     stream << strPost << std::flush;
131
132     // Receive HTTP reply status
133     int nProto = 0;
134     int nStatus = ReadHTTPStatus(stream, nProto);
135
136     // Receive HTTP reply message headers and body
137     map<string, string> mapHeaders;
138     string strReply;
139     ReadHTTPMessage(stream, mapHeaders, strReply, nProto, std::numeric_limits<size_t>::max());
140
141     if (nStatus == HTTP_UNAUTHORIZED)
142         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
143     else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
144         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
145     else if (strReply.empty())
146         throw runtime_error("no response from server");
147
148     // Parse reply
149     Value valReply;
150     if (!read_string(strReply, valReply))
151         throw runtime_error("couldn't parse reply from server");
152     const Object& reply = valReply.get_obj();
153     if (reply.empty())
154         throw runtime_error("expected reply to have result, error and id properties");
155
156     return reply;
157 }
158
159 int CommandLineRPC(int argc, char *argv[])
160 {
161     string strPrint;
162     int nRet = 0;
163     try {
164         // Skip switches
165         while (argc > 1 && IsSwitchChar(argv[1][0])) {
166             argc--;
167             argv++;
168         }
169
170         // Method
171         if (argc < 2)
172             throw runtime_error("too few parameters");
173         string strMethod = argv[1];
174
175         // Parameters default to strings
176         std::vector<std::string> strParams(&argv[2], &argv[argc]);
177         Array params = RPCConvertValues(strMethod, strParams);
178
179         // Execute and handle connection failures with -rpcwait
180         const bool fWait = GetBoolArg("-rpcwait", false);
181         do {
182             try {
183                 const Object reply = CallRPC(strMethod, params);
184
185                 // Parse reply
186                 const Value& result = find_value(reply, "result");
187                 const Value& error  = find_value(reply, "error");
188
189                 if (error.type() != null_type) {
190                     // Error
191                     const int code = find_value(error.get_obj(), "code").get_int();
192                     if (fWait && code == RPC_IN_WARMUP)
193                         throw CConnectionFailed("server in warmup");
194                     strPrint = "error: " + write_string(error, false);
195                     nRet = abs(code);
196                 } else {
197                     // Result
198                     if (result.type() == null_type)
199                         strPrint = "";
200                     else if (result.type() == str_type)
201                         strPrint = result.get_str();
202                     else
203                         strPrint = write_string(result, true);
204                 }
205
206                 // Connection succeeded, no need to retry.
207                 break;
208             }
209             catch (const CConnectionFailed& e) {
210                 if (fWait)
211                     MilliSleep(1000);
212                 else
213                     throw;
214             }
215         } while (fWait);
216     }
217     catch (boost::thread_interrupted) {
218         throw;
219     }
220     catch (std::exception& e) {
221         strPrint = string("error: ") + e.what();
222         nRet = EXIT_FAILURE;
223     }
224     catch (...) {
225         PrintExceptionContinue(NULL, "CommandLineRPC()");
226         throw;
227     }
228
229     if (strPrint != "") {
230         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
231     }
232     return nRet;
233 }
234
235 int main(int argc, char* argv[])
236 {
237     SetupEnvironment();
238
239     try {
240         if(!AppInitRPC(argc, argv))
241             return EXIT_FAILURE;
242     }
243     catch (std::exception& e) {
244         PrintExceptionContinue(&e, "AppInitRPC()");
245         return EXIT_FAILURE;
246     } catch (...) {
247         PrintExceptionContinue(NULL, "AppInitRPC()");
248         return EXIT_FAILURE;
249     }
250
251     int ret = EXIT_FAILURE;
252     try {
253         ret = CommandLineRPC(argc, argv);
254     }
255     catch (std::exception& e) {
256         PrintExceptionContinue(&e, "CommandLineRPC()");
257     } catch (...) {
258         PrintExceptionContinue(NULL, "CommandLineRPC()");
259     }
260     return ret;
261 }
This page took 0.038742 seconds and 4 git commands to generate.