1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 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.
6 #ifndef _BITCOINRPC_PROTOCOL_H_
7 #define _BITCOINRPC_PROTOCOL_H_ 1
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/asio.hpp>
16 #include <boost/asio/ssl.hpp>
18 #include "json/json_spirit_reader_template.h"
19 #include "json/json_spirit_utils.h"
20 #include "json/json_spirit_writer_template.h"
26 HTTP_BAD_REQUEST
= 400,
27 HTTP_UNAUTHORIZED
= 401,
30 HTTP_INTERNAL_SERVER_ERROR
= 500,
33 // Bitcoin RPC error codes
36 // Standard JSON-RPC 2.0 errors
37 RPC_INVALID_REQUEST
= -32600,
38 RPC_METHOD_NOT_FOUND
= -32601,
39 RPC_INVALID_PARAMS
= -32602,
40 RPC_INTERNAL_ERROR
= -32603,
41 RPC_PARSE_ERROR
= -32700,
43 // General application defined errors
44 RPC_MISC_ERROR
= -1, // std::exception thrown in command handling
45 RPC_FORBIDDEN_BY_SAFE_MODE
= -2, // Server is in safe mode, and command is not allowed in safe mode
46 RPC_TYPE_ERROR
= -3, // Unexpected type was passed as parameter
47 RPC_INVALID_ADDRESS_OR_KEY
= -5, // Invalid address or key
48 RPC_OUT_OF_MEMORY
= -7, // Ran out of memory during operation
49 RPC_INVALID_PARAMETER
= -8, // Invalid, missing or duplicate parameter
50 RPC_DATABASE_ERROR
= -20, // Database error
51 RPC_DESERIALIZATION_ERROR
= -22, // Error parsing or validating structure in raw format
52 RPC_TRANSACTION_ERROR
= -25, // General error during transaction submission
53 RPC_TRANSACTION_REJECTED
= -26, // Transaction was rejected by network rules
54 RPC_TRANSACTION_ALREADY_IN_CHAIN
= -27, // Transaction already in chain
57 RPC_CLIENT_NOT_CONNECTED
= -9, // Bitcoin is not connected
58 RPC_CLIENT_IN_INITIAL_DOWNLOAD
= -10, // Still downloading initial blocks
59 RPC_CLIENT_NODE_ALREADY_ADDED
= -23, // Node is already added
60 RPC_CLIENT_NODE_NOT_ADDED
= -24, // Node has not been added before
63 RPC_WALLET_ERROR
= -4, // Unspecified problem with wallet (key not found etc.)
64 RPC_WALLET_INSUFFICIENT_FUNDS
= -6, // Not enough funds in wallet or account
65 RPC_WALLET_INVALID_ACCOUNT_NAME
= -11, // Invalid account name
66 RPC_WALLET_KEYPOOL_RAN_OUT
= -12, // Keypool ran out, call keypoolrefill first
67 RPC_WALLET_UNLOCK_NEEDED
= -13, // Enter the wallet passphrase with walletpassphrase first
68 RPC_WALLET_PASSPHRASE_INCORRECT
= -14, // The wallet passphrase entered was incorrect
69 RPC_WALLET_WRONG_ENC_STATE
= -15, // Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
70 RPC_WALLET_ENCRYPTION_FAILED
= -16, // Failed to encrypt the wallet
71 RPC_WALLET_ALREADY_UNLOCKED
= -17, // Wallet is already unlocked
75 // IOStream device that speaks SSL but can also speak non-SSL
77 template <typename Protocol
>
78 class SSLIOStreamDevice
: public boost::iostreams::device
<boost::iostreams::bidirectional
> {
80 SSLIOStreamDevice(boost::asio::ssl::stream
<typename
Protocol::socket
> &streamIn
, bool fUseSSLIn
) : stream(streamIn
)
83 fNeedHandshake
= fUseSSLIn
;
86 void handshake(boost::asio::ssl::stream_base::handshake_type role
)
88 if (!fNeedHandshake
) return;
89 fNeedHandshake
= false;
90 stream
.handshake(role
);
92 std::streamsize
read(char* s
, std::streamsize n
)
94 handshake(boost::asio::ssl::stream_base::server
); // HTTPS servers read first
95 if (fUseSSL
) return stream
.read_some(boost::asio::buffer(s
, n
));
96 return stream
.next_layer().read_some(boost::asio::buffer(s
, n
));
98 std::streamsize
write(const char* s
, std::streamsize n
)
100 handshake(boost::asio::ssl::stream_base::client
); // HTTPS clients write first
101 if (fUseSSL
) return boost::asio::write(stream
, boost::asio::buffer(s
, n
));
102 return boost::asio::write(stream
.next_layer(), boost::asio::buffer(s
, n
));
104 bool connect(const std::string
& server
, const std::string
& port
)
106 using namespace boost::asio::ip
;
107 tcp::resolver
resolver(stream
.get_io_service());
108 tcp::resolver::iterator endpoint_iterator
;
109 #if BOOST_VERSION >= 104300
112 // The default query (flags address_configured) tries IPv6 if
113 // non-localhost IPv6 configured, and IPv4 if non-localhost IPv4
115 tcp::resolver::query
query(server
.c_str(), port
.c_str());
116 endpoint_iterator
= resolver
.resolve(query
);
117 #if BOOST_VERSION >= 104300
118 } catch(boost::system::system_error
&e
)
120 // If we at first don't succeed, try blanket lookup (IPv4+IPv6 independent of configured interfaces)
121 tcp::resolver::query
query(server
.c_str(), port
.c_str(), resolver_query_base::flags());
122 endpoint_iterator
= resolver
.resolve(query
);
125 boost::system::error_code error
= boost::asio::error::host_not_found
;
126 tcp::resolver::iterator end
;
127 while (error
&& endpoint_iterator
!= end
)
129 stream
.lowest_layer().close();
130 stream
.lowest_layer().connect(*endpoint_iterator
++, error
);
140 boost::asio::ssl::stream
<typename
Protocol::socket
>& stream
;
143 std::string
HTTPPost(const std::string
& strMsg
, const std::map
<std::string
,std::string
>& mapRequestHeaders
);
144 std::string
HTTPError(int nStatus
, bool keepalive
,
145 bool headerOnly
= false);
146 std::string
HTTPReplyHeader(int nStatus
, bool keepalive
, size_t contentLength
,
147 const char *contentType
= "application/json");
148 std::string
HTTPReply(int nStatus
, const std::string
& strMsg
, bool keepalive
,
149 bool headerOnly
= false,
150 const char *contentType
= "application/json");
151 bool ReadHTTPRequestLine(std::basic_istream
<char>& stream
, int &proto
,
152 std::string
& http_method
, std::string
& http_uri
);
153 int ReadHTTPStatus(std::basic_istream
<char>& stream
, int &proto
);
154 int ReadHTTPHeaders(std::basic_istream
<char>& stream
, std::map
<std::string
, std::string
>& mapHeadersRet
);
155 int ReadHTTPMessage(std::basic_istream
<char>& stream
, std::map
<std::string
, std::string
>& mapHeadersRet
,
156 std::string
& strMessageRet
, int nProto
, size_t max_size
);
157 std::string
JSONRPCRequest(const std::string
& strMethod
, const json_spirit::Array
& params
, const json_spirit::Value
& id
);
158 json_spirit::Object
JSONRPCReplyObj(const json_spirit::Value
& result
, const json_spirit::Value
& error
, const json_spirit::Value
& id
);
159 std::string
JSONRPCReply(const json_spirit::Value
& result
, const json_spirit::Value
& error
, const json_spirit::Value
& id
);
160 json_spirit::Object
JSONRPCError(int code
, const std::string
& message
);