6 #if defined(HAVE_CONFIG_H) 22 #include <event2/buffer.h> 23 #include <event2/keyvalq_struct.h> 30 static const char DEFAULT_RPCCONNECT[] =
"127.0.0.1";
31 static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
32 static const bool DEFAULT_NAMED=
false;
33 static const int CONTINUE_EXECUTION=-1;
35 static void SetupCliArgs()
45 gArgs.
AddArg(
"-getinfo",
"Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)",
false,
OptionsCategory::OPTIONS);
50 gArgs.
AddArg(
"-rpccookiefile=<loc>",
"Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)",
false,
OptionsCategory::OPTIONS);
52 gArgs.
AddArg(
"-rpcport=<port>",
strprintf(
"Connect to JSON-RPC on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()),
false,
OptionsCategory::OPTIONS);
55 gArgs.
AddArg(
"-rpcwallet=<walletname>",
"Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bsha3d)",
false,
OptionsCategory::OPTIONS);
56 gArgs.
AddArg(
"-stdin",
"Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.",
false,
OptionsCategory::OPTIONS);
57 gArgs.
AddArg(
"-stdinrpcpass",
"Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password.",
false,
OptionsCategory::OPTIONS);
65 static void libevent_log_cb(
int severity,
const char *msg)
67 #ifndef EVENT_LOG_ERR // EVENT_LOG_ERR was added in 2.0.19; but before then _EVENT_LOG_ERR existed. 68 # define EVENT_LOG_ERR _EVENT_LOG_ERR 72 throw std::runtime_error(
strprintf(
"libevent error: %s", msg));
90 std::runtime_error(msg)
99 static int AppInitRPC(
int argc,
char* argv[])
107 fprintf(stderr,
"Error parsing command line arguments: %s\n",
error.c_str());
114 "Usage: bsha3-cli [options] <command> [params] Send command to " PACKAGE_NAME "\n" 115 "or: bsha3-cli [options] -named <command> [name=value]... Send command to " PACKAGE_NAME " (with named arguments)\n" 116 "or: bsha3-cli [options] help List commands\n" 117 "or: bsha3-cli [options] help <command> Get help for a command\n";
121 fprintf(stdout,
"%s", strUsage.c_str());
123 fprintf(stderr,
"Error: too few parameters\n");
129 fprintf(stderr,
"Error: Specified data directory \"%s\" does not exist.\n",
gArgs.
GetArg(
"-datadir",
"").c_str());
133 fprintf(stderr,
"Error reading configuration file: %s\n",
error.c_str());
139 }
catch (
const std::exception& e) {
140 fprintf(stderr,
"Error: %s\n", e.what());
143 return CONTINUE_EXECUTION;
157 static const char *http_errorstring(
int code)
160 #if LIBEVENT_VERSION_NUMBER >= 0x02010300 161 case EVREQ_HTTP_TIMEOUT:
162 return "timeout reached";
164 return "EOF reached";
165 case EVREQ_HTTP_INVALID_HEADER:
166 return "error while reading header, or invalid header";
167 case EVREQ_HTTP_BUFFER_ERROR:
168 return "error encountered while reading or writing";
169 case EVREQ_HTTP_REQUEST_CANCEL:
170 return "request was canceled";
171 case EVREQ_HTTP_DATA_TOO_LONG:
172 return "response body is larger than allowed";
179 static void http_request_done(
struct evhttp_request *req,
void *ctx)
183 if (req ==
nullptr) {
191 reply->
status = evhttp_request_get_response_code(req);
193 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
196 size_t size = evbuffer_get_length(buf);
197 const char *data = (
const char*)evbuffer_pullup(buf, size);
199 reply->
body = std::string(data, size);
200 evbuffer_drain(buf, size);
204 #if LIBEVENT_VERSION_NUMBER >= 0x02010300 205 static void http_error_cb(
enum evhttp_request_error err,
void *ctx)
235 throw std::runtime_error(
"-getinfo takes no arguments");
274 if (!batch[
ID_WALLETINFO][
"result"][
"unlocked_until"].isNull()) {
321 evhttp_connection_set_timeout(evcon.get(),
gArgs.
GetArg(
"-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
326 throw std::runtime_error(
"create http request failed");
327 #if LIBEVENT_VERSION_NUMBER >= 0x02010300 328 evhttp_request_set_error_cb(req.get(), http_error_cb);
332 std::string strRPCUserColonPass;
333 bool failedToGetAuthCookie =
false;
337 failedToGetAuthCookie =
true;
343 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
344 assert(output_headers);
345 evhttp_add_header(output_headers,
"Host", host.c_str());
346 evhttp_add_header(output_headers,
"Connection",
"close");
347 evhttp_add_header(output_headers,
"Authorization", (std::string(
"Basic ") +
EncodeBase64(strRPCUserColonPass)).c_str());
351 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
352 assert(output_buffer);
353 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
356 std::string endpoint =
"/";
358 std::string walletName =
gArgs.
GetArg(
"-rpcwallet",
"");
359 char *encodedURI = evhttp_uriencode(walletName.c_str(), walletName.size(),
false);
361 endpoint =
"/wallet/"+ std::string(encodedURI);
368 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
374 event_base_dispatch(base.get());
376 if (response.status == 0) {
377 std::string responseErrorMessage;
378 if (response.error != -1) {
379 responseErrorMessage =
strprintf(
" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
381 throw CConnectionFailed(
strprintf(
"Could not connect to the server %s:%d%s\n\nMake sure the bsha3d server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage));
383 if (failedToGetAuthCookie) {
385 "Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
388 throw std::runtime_error(
"Authorization failed: Incorrect rpcuser or rpcpassword");
391 throw std::runtime_error(
strprintf(
"server returned HTTP error %d", response.status));
392 else if (response.body.empty())
393 throw std::runtime_error(
"no response from server");
397 if (!valReply.read(response.body))
398 throw std::runtime_error(
"couldn't parse reply from server");
401 throw std::runtime_error(
"expected reply to have result, error and id properties");
406 static int CommandLineRPC(
int argc,
char *argv[])
408 std::string strPrint;
418 if (!std::getline(std::cin, rpcPass)) {
419 throw std::runtime_error(
"-stdinrpcpass specified but failed to read from standard input");
423 std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
427 while (std::getline(std::cin, line)) {
428 args.push_back(line);
431 std::unique_ptr<BaseRequestHandler> rh;
438 if (args.size() < 1) {
439 throw std::runtime_error(
"too few parameters (need at least command)");
442 args.erase(args.begin());
449 const UniValue reply = CallRPC(rh.get(), method, args);
455 if (!
error.isNull()) {
457 int code =
error[
"code"].get_int();
460 strPrint =
"error: " +
error.write();
462 if (
error.isObject())
466 strPrint = errCode.
isNull() ?
"" :
"error code: "+errCode.
getValStr()+
"\n";
469 strPrint +=
"error message:\n"+errMsg.
get_str();
472 strPrint +=
"\nTry adding \"-rpcwallet=<filename>\" option to bsha3-cli command line.";
479 else if (result.isStr())
480 strPrint = result.get_str();
482 strPrint = result.write(2);
495 catch (
const boost::thread_interrupted&) {
498 catch (
const std::exception& e) {
499 strPrint = std::string(
"error: ") + e.what();
507 if (strPrint !=
"") {
508 fprintf((nRet == 0 ? stdout : stderr),
"%s\n", strPrint.c_str());
513 int main(
int argc,
char* argv[])
516 util::WinCmdLineArgs winArgs;
517 std::tie(argc, argv) = winArgs.get();
521 fprintf(stderr,
"Error: Initializing networking failed\n");
524 event_set_log_callback(&libevent_log_cb);
527 int ret = AppInitRPC(argc, argv);
528 if (
ret != CONTINUE_EXECUTION)
531 catch (
const std::exception& e) {
539 int ret = EXIT_FAILURE;
541 ret = CommandLineRPC(argc, argv);
543 catch (
const std::exception& e) {
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
No wallet specified (error when there are multiple wallets loaded)
bool HelpRequested(const ArgsManager &args)
std::unique_ptr< CBaseChainParams > CreateBaseChainParams(const std::string &chain)
Creates and returns a std::unique_ptr<CBaseChainParams> of the chosen chain.
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
raii_event_base obtain_event_base()
void MilliSleep(int64_t n)
const char *const BITCOIN_CONF_FILENAME
static const std::string REGTEST
const std::function< std::string(const char *)> G_TRANSLATION_FUN
Translate a message to the native language of the user.
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue ¶ms, const UniValue &id)
JSON-RPC protocol.
UniValue ProcessReply(const UniValue &reply) override
UniValue ret(UniValue::VARR)
virtual ~BaseRequestHandler()
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
const std::string & get_str() const
raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg)
bool ParseParameters(int argc, const char *const argv[], std::string &error)
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
const int ID_BLOCKCHAININFO
void ForceSetArg(const std::string &strArg, const std::string &strValue)
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in, size_t num)
Parse JSON-RPC batch reply into a vector.
const std::string & getValStr() const
virtual UniValue ProcessReply(const UniValue &batch_in)=0
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
Create a simulated getinfo request.
const UniValue & find_value(const UniValue &obj, const std::string &name)
std::string GetHelpMessage() const
Get the help string.
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
bool GetAuthCookie(std::string *cookie_out)
Read the RPC authentication cookie from disk.
bool push_back(const UniValue &val)
virtual UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args)=0
raii_evhttp_connection obtain_evhttp_connection_base(struct event_base *base, std::string host, uint16_t port)
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
bool pushKV(const std::string &key, const UniValue &val)
UniValue ProcessReply(const UniValue &batch_in) override
Collect values from the batch and form a simulated getinfo reply.
Class that handles the conversion from a command-line to a JSON-RPC request, as well as converting ba...
std::string FormatFullVersion()
int main(int argc, char *argv[])
CConnectionFailed(const std::string &msg)
void SetupChainParamsBaseOptions()
Set the arguments for chainparams.
bool IsSwitchChar(char c)
void SplitHostPort(std::string in, int &portOut, std::string &hostOut)
fs::path GetConfigFile(const std::string &confPath)
void AddArg(const std::string &name, const std::string &help, const bool debug_only, const OptionsCategory &cat)
Add argument.
const UniValue & get_obj() const
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Process default single requests.
const UniValue NullUniValue
bool error(const char *fmt, const Args &... args)
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert named arguments to command-specific RPC representation.
static const std::string TESTNET
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
const fs::path & GetDataDir(bool fNetSpecific)
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
void SelectBaseParams(const std::string &chain)
Sets the params returned by Params() to those for the given network.
Process getinfo requests.
Reply structure for request_done to fill in.
std::string EncodeBase64(const unsigned char *pch, size_t len)