mirror of https://github.com/lukechilds/komodo.git
Wladimir J. van der Laan
11 years ago
18 changed files with 692 additions and 629 deletions
@ -0,0 +1,246 @@ |
|||
// Copyright (c) 2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2009-2013 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#include "rpcclient.h" |
|||
|
|||
#include "rpcprotocol.h" |
|||
#include "util.h" |
|||
#include "ui_interface.h" |
|||
#include "chainparams.h" // for Params().RPCPort() |
|||
|
|||
#include <stdint.h> |
|||
|
|||
#include <boost/algorithm/string.hpp> |
|||
#include <boost/asio.hpp> |
|||
#include <boost/asio/ssl.hpp> |
|||
#include <boost/bind.hpp> |
|||
#include <boost/filesystem.hpp> |
|||
#include <boost/foreach.hpp> |
|||
#include <boost/iostreams/concepts.hpp> |
|||
#include <boost/iostreams/stream.hpp> |
|||
#include <boost/lexical_cast.hpp> |
|||
#include <boost/shared_ptr.hpp> |
|||
#include "json/json_spirit_writer_template.h" |
|||
|
|||
using namespace std; |
|||
using namespace boost; |
|||
using namespace boost::asio; |
|||
using namespace json_spirit; |
|||
|
|||
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; |
|||
} |
|||
|
|||
template<typename T> |
|||
void ConvertTo(Value& value, bool fAllowNull=false) |
|||
{ |
|||
if (fAllowNull && value.type() == null_type) |
|||
return; |
|||
if (value.type() == str_type) |
|||
{ |
|||
// reinterpret string as unquoted json value
|
|||
Value value2; |
|||
string strJSON = value.get_str(); |
|||
if (!read_string(strJSON, value2)) |
|||
throw runtime_error(string("Error parsing JSON:")+strJSON); |
|||
ConvertTo<T>(value2, fAllowNull); |
|||
value = value2; |
|||
} |
|||
else |
|||
{ |
|||
value = value.get_value<T>(); |
|||
} |
|||
} |
|||
|
|||
// Convert strings to command-specific RPC representation
|
|||
Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams) |
|||
{ |
|||
Array params; |
|||
BOOST_FOREACH(const std::string ¶m, strParams) |
|||
params.push_back(param); |
|||
|
|||
int n = params.size(); |
|||
|
|||
//
|
|||
// Special case non-string parameter types
|
|||
//
|
|||
if (strMethod == "stop" && n > 0) ConvertTo<bool>(params[0]); |
|||
if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo<bool>(params[0]); |
|||
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]); |
|||
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "getnetworkhashps" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "getnetworkhashps" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]); |
|||
if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]); |
|||
if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]); |
|||
if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]); |
|||
if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]); |
|||
if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]); |
|||
if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]); |
|||
if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]); |
|||
if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]); |
|||
if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]); |
|||
if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]); |
|||
if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]); |
|||
if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]); |
|||
if (strMethod == "createmultisig" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]); |
|||
if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]); |
|||
if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]); |
|||
if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]); |
|||
if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]); |
|||
if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true); |
|||
if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true); |
|||
if (strMethod == "sendrawtransaction" && n > 1) ConvertTo<bool>(params[1], true); |
|||
if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]); |
|||
if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); |
|||
if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); |
|||
if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]); |
|||
if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
|||
if (strMethod == "keypoolrefill" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
|||
|
|||
return params; |
|||
} |
|||
|
|||
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 = 87; |
|||
} |
|||
catch (...) { |
|||
PrintException(NULL, "CommandLineRPC()"); |
|||
} |
|||
|
|||
if (strPrint != "") |
|||
{ |
|||
fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str()); |
|||
} |
|||
return nRet; |
|||
} |
@ -0,0 +1,17 @@ |
|||
// Copyright (c) 2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2009-2013 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef _BITCOINRPC_CLIENT_H_ |
|||
#define _BITCOINRPC_CLIENT_H_ 1 |
|||
|
|||
#include "json/json_spirit_reader_template.h" |
|||
#include "json/json_spirit_utils.h" |
|||
#include "json/json_spirit_writer_template.h" |
|||
|
|||
int CommandLineRPC(int argc, char *argv[]); |
|||
|
|||
json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams); |
|||
|
|||
#endif |
@ -0,0 +1,262 @@ |
|||
// Copyright (c) 2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2009-2013 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#include "rpcprotocol.h" |
|||
|
|||
#include "util.h" |
|||
|
|||
#include <stdint.h> |
|||
|
|||
#include <boost/algorithm/string.hpp> |
|||
#include <boost/asio.hpp> |
|||
#include <boost/asio/ssl.hpp> |
|||
#include <boost/bind.hpp> |
|||
#include <boost/filesystem.hpp> |
|||
#include <boost/foreach.hpp> |
|||
#include <boost/iostreams/concepts.hpp> |
|||
#include <boost/iostreams/stream.hpp> |
|||
#include <boost/lexical_cast.hpp> |
|||
#include <boost/shared_ptr.hpp> |
|||
#include "json/json_spirit_writer_template.h" |
|||
|
|||
using namespace std; |
|||
using namespace boost; |
|||
using namespace boost::asio; |
|||
using namespace json_spirit; |
|||
|
|||
//
|
|||
// HTTP protocol
|
|||
//
|
|||
// This ain't Apache. We're just using HTTP header for the length field
|
|||
// and to be compatible with other JSON-RPC implementations.
|
|||
//
|
|||
|
|||
string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders) |
|||
{ |
|||
ostringstream s; |
|||
s << "POST / HTTP/1.1\r\n" |
|||
<< "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n" |
|||
<< "Host: 127.0.0.1\r\n" |
|||
<< "Content-Type: application/json\r\n" |
|||
<< "Content-Length: " << strMsg.size() << "\r\n" |
|||
<< "Connection: close\r\n" |
|||
<< "Accept: application/json\r\n"; |
|||
BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders) |
|||
s << item.first << ": " << item.second << "\r\n"; |
|||
s << "\r\n" << strMsg; |
|||
|
|||
return s.str(); |
|||
} |
|||
|
|||
static string rfc1123Time() |
|||
{ |
|||
char buffer[64]; |
|||
time_t now; |
|||
time(&now); |
|||
struct tm* now_gmt = gmtime(&now); |
|||
string locale(setlocale(LC_TIME, NULL)); |
|||
setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings
|
|||
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt); |
|||
setlocale(LC_TIME, locale.c_str()); |
|||
return string(buffer); |
|||
} |
|||
|
|||
string HTTPReply(int nStatus, const string& strMsg, bool keepalive) |
|||
{ |
|||
if (nStatus == HTTP_UNAUTHORIZED) |
|||
return strprintf("HTTP/1.0 401 Authorization Required\r\n" |
|||
"Date: %s\r\n" |
|||
"Server: bitcoin-json-rpc/%s\r\n" |
|||
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n" |
|||
"Content-Type: text/html\r\n" |
|||
"Content-Length: 296\r\n" |
|||
"\r\n" |
|||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n" |
|||
"\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n" |
|||
"<HTML>\r\n" |
|||
"<HEAD>\r\n" |
|||
"<TITLE>Error</TITLE>\r\n" |
|||
"<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n" |
|||
"</HEAD>\r\n" |
|||
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n" |
|||
"</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str()); |
|||
const char *cStatus; |
|||
if (nStatus == HTTP_OK) cStatus = "OK"; |
|||
else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request"; |
|||
else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden"; |
|||
else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found"; |
|||
else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error"; |
|||
else cStatus = ""; |
|||
return strprintf( |
|||
"HTTP/1.1 %d %s\r\n" |
|||
"Date: %s\r\n" |
|||
"Connection: %s\r\n" |
|||
"Content-Length: %"PRIszu"\r\n" |
|||
"Content-Type: application/json\r\n" |
|||
"Server: bitcoin-json-rpc/%s\r\n" |
|||
"\r\n" |
|||
"%s", |
|||
nStatus, |
|||
cStatus, |
|||
rfc1123Time().c_str(), |
|||
keepalive ? "keep-alive" : "close", |
|||
strMsg.size(), |
|||
FormatFullVersion().c_str(), |
|||
strMsg.c_str()); |
|||
} |
|||
|
|||
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto, |
|||
string& http_method, string& http_uri) |
|||
{ |
|||
string str; |
|||
getline(stream, str); |
|||
|
|||
// HTTP request line is space-delimited
|
|||
vector<string> vWords; |
|||
boost::split(vWords, str, boost::is_any_of(" ")); |
|||
if (vWords.size() < 2) |
|||
return false; |
|||
|
|||
// HTTP methods permitted: GET, POST
|
|||
http_method = vWords[0]; |
|||
if (http_method != "GET" && http_method != "POST") |
|||
return false; |
|||
|
|||
// HTTP URI must be an absolute path, relative to current host
|
|||
http_uri = vWords[1]; |
|||
if (http_uri.size() == 0 || http_uri[0] != '/') |
|||
return false; |
|||
|
|||
// parse proto, if present
|
|||
string strProto = ""; |
|||
if (vWords.size() > 2) |
|||
strProto = vWords[2]; |
|||
|
|||
proto = 0; |
|||
const char *ver = strstr(strProto.c_str(), "HTTP/1."); |
|||
if (ver != NULL) |
|||
proto = atoi(ver+7); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto) |
|||
{ |
|||
string str; |
|||
getline(stream, str); |
|||
vector<string> vWords; |
|||
boost::split(vWords, str, boost::is_any_of(" ")); |
|||
if (vWords.size() < 2) |
|||
return HTTP_INTERNAL_SERVER_ERROR; |
|||
proto = 0; |
|||
const char *ver = strstr(str.c_str(), "HTTP/1."); |
|||
if (ver != NULL) |
|||
proto = atoi(ver+7); |
|||
return atoi(vWords[1].c_str()); |
|||
} |
|||
|
|||
int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet) |
|||
{ |
|||
int nLen = 0; |
|||
while (true) |
|||
{ |
|||
string str; |
|||
std::getline(stream, str); |
|||
if (str.empty() || str == "\r") |
|||
break; |
|||
string::size_type nColon = str.find(":"); |
|||
if (nColon != string::npos) |
|||
{ |
|||
string strHeader = str.substr(0, nColon); |
|||
boost::trim(strHeader); |
|||
boost::to_lower(strHeader); |
|||
string strValue = str.substr(nColon+1); |
|||
boost::trim(strValue); |
|||
mapHeadersRet[strHeader] = strValue; |
|||
if (strHeader == "content-length") |
|||
nLen = atoi(strValue.c_str()); |
|||
} |
|||
} |
|||
return nLen; |
|||
} |
|||
|
|||
|
|||
int ReadHTTPMessage(std::basic_istream<char>& stream, map<string, |
|||
string>& mapHeadersRet, string& strMessageRet, |
|||
int nProto) |
|||
{ |
|||
mapHeadersRet.clear(); |
|||
strMessageRet = ""; |
|||
|
|||
// Read header
|
|||
int nLen = ReadHTTPHeaders(stream, mapHeadersRet); |
|||
if (nLen < 0 || nLen > (int)MAX_SIZE) |
|||
return HTTP_INTERNAL_SERVER_ERROR; |
|||
|
|||
// Read message
|
|||
if (nLen > 0) |
|||
{ |
|||
vector<char> vch(nLen); |
|||
stream.read(&vch[0], nLen); |
|||
strMessageRet = string(vch.begin(), vch.end()); |
|||
} |
|||
|
|||
string sConHdr = mapHeadersRet["connection"]; |
|||
|
|||
if ((sConHdr != "close") && (sConHdr != "keep-alive")) |
|||
{ |
|||
if (nProto >= 1) |
|||
mapHeadersRet["connection"] = "keep-alive"; |
|||
else |
|||
mapHeadersRet["connection"] = "close"; |
|||
} |
|||
|
|||
return HTTP_OK; |
|||
} |
|||
|
|||
//
|
|||
// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
|
|||
// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
|
|||
// unspecified (HTTP errors and contents of 'error').
|
|||
//
|
|||
// 1.0 spec: http://json-rpc.org/wiki/specification
|
|||
// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
|
|||
// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
|
|||
//
|
|||
|
|||
string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id) |
|||
{ |
|||
Object request; |
|||
request.push_back(Pair("method", strMethod)); |
|||
request.push_back(Pair("params", params)); |
|||
request.push_back(Pair("id", id)); |
|||
return write_string(Value(request), false) + "\n"; |
|||
} |
|||
|
|||
Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) |
|||
{ |
|||
Object reply; |
|||
if (error.type() != null_type) |
|||
reply.push_back(Pair("result", Value::null)); |
|||
else |
|||
reply.push_back(Pair("result", result)); |
|||
reply.push_back(Pair("error", error)); |
|||
reply.push_back(Pair("id", id)); |
|||
return reply; |
|||
} |
|||
|
|||
string JSONRPCReply(const Value& result, const Value& error, const Value& id) |
|||
{ |
|||
Object reply = JSONRPCReplyObj(result, error, id); |
|||
return write_string(Value(reply), false) + "\n"; |
|||
} |
|||
|
|||
Object JSONRPCError(int code, const string& message) |
|||
{ |
|||
Object error; |
|||
error.push_back(Pair("code", code)); |
|||
error.push_back(Pair("message", message)); |
|||
return error; |
|||
} |
@ -0,0 +1,138 @@ |
|||
// Copyright (c) 2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2009-2013 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef _BITCOINRPC_PROTOCOL_H_ |
|||
#define _BITCOINRPC_PROTOCOL_H_ 1 |
|||
|
|||
#include <list> |
|||
#include <map> |
|||
#include <stdint.h> |
|||
#include <string> |
|||
#include <boost/iostreams/concepts.hpp> |
|||
#include <boost/iostreams/stream.hpp> |
|||
#include <boost/asio.hpp> |
|||
#include <boost/asio/ssl.hpp> |
|||
|
|||
#include "json/json_spirit_reader_template.h" |
|||
#include "json/json_spirit_utils.h" |
|||
#include "json/json_spirit_writer_template.h" |
|||
|
|||
// HTTP status codes
|
|||
enum HTTPStatusCode |
|||
{ |
|||
HTTP_OK = 200, |
|||
HTTP_BAD_REQUEST = 400, |
|||
HTTP_UNAUTHORIZED = 401, |
|||
HTTP_FORBIDDEN = 403, |
|||
HTTP_NOT_FOUND = 404, |
|||
HTTP_INTERNAL_SERVER_ERROR = 500, |
|||
}; |
|||
|
|||
// Bitcoin RPC error codes
|
|||
enum RPCErrorCode |
|||
{ |
|||
// Standard JSON-RPC 2.0 errors
|
|||
RPC_INVALID_REQUEST = -32600, |
|||
RPC_METHOD_NOT_FOUND = -32601, |
|||
RPC_INVALID_PARAMS = -32602, |
|||
RPC_INTERNAL_ERROR = -32603, |
|||
RPC_PARSE_ERROR = -32700, |
|||
|
|||
// General application defined errors
|
|||
RPC_MISC_ERROR = -1, // std::exception thrown in command handling
|
|||
RPC_FORBIDDEN_BY_SAFE_MODE = -2, // Server is in safe mode, and command is not allowed in safe mode
|
|||
RPC_TYPE_ERROR = -3, // Unexpected type was passed as parameter
|
|||
RPC_INVALID_ADDRESS_OR_KEY = -5, // Invalid address or key
|
|||
RPC_OUT_OF_MEMORY = -7, // Ran out of memory during operation
|
|||
RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter
|
|||
RPC_DATABASE_ERROR = -20, // Database error
|
|||
RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format
|
|||
RPC_SERVER_NOT_STARTED = -18, // RPC server was not started (StartRPCThreads() not called)
|
|||
|
|||
// P2P client errors
|
|||
RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected
|
|||
RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, // Still downloading initial blocks
|
|||
RPC_CLIENT_NODE_ALREADY_ADDED = -23, // Node is already added
|
|||
RPC_CLIENT_NODE_NOT_ADDED = -24, // Node has not been added before
|
|||
|
|||
// Wallet errors
|
|||
RPC_WALLET_ERROR = -4, // Unspecified problem with wallet (key not found etc.)
|
|||
RPC_WALLET_INSUFFICIENT_FUNDS = -6, // Not enough funds in wallet or account
|
|||
RPC_WALLET_INVALID_ACCOUNT_NAME = -11, // Invalid account name
|
|||
RPC_WALLET_KEYPOOL_RAN_OUT = -12, // Keypool ran out, call keypoolrefill first
|
|||
RPC_WALLET_UNLOCK_NEEDED = -13, // Enter the wallet passphrase with walletpassphrase first
|
|||
RPC_WALLET_PASSPHRASE_INCORRECT = -14, // The wallet passphrase entered was incorrect
|
|||
RPC_WALLET_WRONG_ENC_STATE = -15, // Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
|
|||
RPC_WALLET_ENCRYPTION_FAILED = -16, // Failed to encrypt the wallet
|
|||
RPC_WALLET_ALREADY_UNLOCKED = -17, // Wallet is already unlocked
|
|||
}; |
|||
|
|||
//
|
|||
// IOStream device that speaks SSL but can also speak non-SSL
|
|||
//
|
|||
template <typename Protocol> |
|||
class SSLIOStreamDevice : public boost::iostreams::device<boost::iostreams::bidirectional> { |
|||
public: |
|||
SSLIOStreamDevice(boost::asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn) |
|||
{ |
|||
fUseSSL = fUseSSLIn; |
|||
fNeedHandshake = fUseSSLIn; |
|||
} |
|||
|
|||
void handshake(boost::asio::ssl::stream_base::handshake_type role) |
|||
{ |
|||
if (!fNeedHandshake) return; |
|||
fNeedHandshake = false; |
|||
stream.handshake(role); |
|||
} |
|||
std::streamsize read(char* s, std::streamsize n) |
|||
{ |
|||
handshake(boost::asio::ssl::stream_base::server); // HTTPS servers read first
|
|||
if (fUseSSL) return stream.read_some(boost::asio::buffer(s, n)); |
|||
return stream.next_layer().read_some(boost::asio::buffer(s, n)); |
|||
} |
|||
std::streamsize write(const char* s, std::streamsize n) |
|||
{ |
|||
handshake(boost::asio::ssl::stream_base::client); // HTTPS clients write first
|
|||
if (fUseSSL) return boost::asio::write(stream, boost::asio::buffer(s, n)); |
|||
return boost::asio::write(stream.next_layer(), boost::asio::buffer(s, n)); |
|||
} |
|||
bool connect(const std::string& server, const std::string& port) |
|||
{ |
|||
boost::asio::ip::tcp::resolver resolver(stream.get_io_service()); |
|||
boost::asio::ip::tcp::resolver::query query(server.c_str(), port.c_str()); |
|||
boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); |
|||
boost::asio::ip::tcp::resolver::iterator end; |
|||
boost::system::error_code error = boost::asio::error::host_not_found; |
|||
while (error && endpoint_iterator != end) |
|||
{ |
|||
stream.lowest_layer().close(); |
|||
stream.lowest_layer().connect(*endpoint_iterator++, error); |
|||
} |
|||
if (error) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
private: |
|||
bool fNeedHandshake; |
|||
bool fUseSSL; |
|||
boost::asio::ssl::stream<typename Protocol::socket>& stream; |
|||
}; |
|||
|
|||
std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders); |
|||
std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive); |
|||
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto, |
|||
std::string& http_method, std::string& http_uri); |
|||
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto); |
|||
int ReadHTTPHeaders(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet); |
|||
int ReadHTTPMessage(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet, |
|||
std::string& strMessageRet, int nProto); |
|||
std::string JSONRPCRequest(const std::string& strMethod, const json_spirit::Array& params, const json_spirit::Value& id); |
|||
json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id); |
|||
std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id); |
|||
json_spirit::Object JSONRPCError(int code, const std::string& message); |
|||
|
|||
#endif |
Loading…
Reference in new issue