1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 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_TRANSACTION_ERROR = -25, // General error during transaction submission
RPC_TRANSACTION_REJECTED = -26, // Transaction was rejected by network rules
RPC_TRANSACTION_ALREADY_IN_CHAIN= -27, // Transaction already in chain
// 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)
{
using namespace boost::asio::ip;
tcp::resolver resolver(stream.get_io_service());
tcp::resolver::iterator endpoint_iterator;
#if BOOST_VERSION >= 104300
try {
#endif
// The default query (flags address_configured) tries IPv6 if
// non-localhost IPv6 configured, and IPv4 if non-localhost IPv4
// configured.
tcp::resolver::query query(server.c_str(), port.c_str());
endpoint_iterator = resolver.resolve(query);
#if BOOST_VERSION >= 104300
} catch(boost::system::system_error &e)
{
// If we at first don't succeed, try blanket lookup (IPv4+IPv6 independent of configured interfaces)
tcp::resolver::query query(server.c_str(), port.c_str(), resolver_query_base::flags());
endpoint_iterator = resolver.resolve(query);
}
#endif
boost::system::error_code error = boost::asio::error::host_not_found;
tcp::resolver::iterator end;
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 HTTPError(int nStatus, bool keepalive,
bool headerOnly = false);
std::string HTTPReplyHeader(int nStatus, bool keepalive, size_t contentLength,
const char *contentType = "application/json");
std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive,
bool headerOnly = false,
const char *contentType = "application/json");
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, size_t max_size);
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
|