mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 05:23:01 +01:00
c912e22db0
1) support varying content types 2) support only sending the header 3) properly deliver error message as content, if HTTP error 4) move AcceptedConnection class to header, for wider use
169 lines
7.2 KiB
C++
169 lines
7.2 KiB
C++
// 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
|
|
};
|
|
|
|
class AcceptedConnection
|
|
{
|
|
public:
|
|
virtual ~AcceptedConnection() {}
|
|
|
|
virtual std::iostream& stream() = 0;
|
|
virtual std::string peer_address_to_string() const = 0;
|
|
virtual void close() = 0;
|
|
};
|
|
|
|
//
|
|
// 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 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);
|
|
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
|