@ -12,6 +12,32 @@
@@ -12,6 +12,32 @@
# include <boost/filesystem/operations.hpp>
using namespace boost ;
using namespace boost : : asio ;
using namespace json_spirit ;
std : : string HelpMessageCli ( )
{
string strUsage ;
strUsage + = _ ( " Options: " ) + " \n " ;
strUsage + = " -? " + _ ( " This help message " ) + " \n " ;
strUsage + = " -conf=<file> " + _ ( " Specify configuration file (default: bitcoin.conf) " ) + " \n " ;
strUsage + = " -datadir=<dir> " + _ ( " Specify data directory " ) + " \n " ;
strUsage + = " -testnet " + _ ( " Use the test network " ) + " \n " ;
strUsage + = " -regtest " + _ ( " Enter regression test mode, which uses a special chain in which blocks can be "
" solved instantly. This is intended for regression testing tools and app development. " ) + " \n " ;
strUsage + = " -rpcconnect=<ip> " + _ ( " Send commands to node running on <ip> (default: 127.0.0.1) " ) + " \n " ;
strUsage + = " -rpcport=<port> " + _ ( " Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332) " ) + " \n " ;
strUsage + = " -rpcwait " + _ ( " Wait for RPC server to start " ) + " \n " ;
strUsage + = " -rpcuser=<user> " + _ ( " Username for JSON-RPC connections " ) + " \n " ;
strUsage + = " -rpcpassword=<pw> " + _ ( " Password for JSON-RPC connections " ) + " \n " ;
strUsage + = " \n " + _ ( " SSL options: (see the Bitcoin Wiki for SSL setup instructions) " ) + " \n " ;
strUsage + = " -rpcssl " + _ ( " Use OpenSSL (https) for JSON-RPC connections " ) + " \n " ;
return strUsage ;
}
//////////////////////////////////////////////////////////////////////////////
//
// Start
@ -49,7 +75,7 @@ static bool AppInitRPC(int argc, char* argv[])
@@ -49,7 +75,7 @@ static bool AppInitRPC(int argc, char* argv[])
" bitcoin-cli [options] help " + _ ( " List commands " ) + " \n " +
" bitcoin-cli [options] help <command> " + _ ( " Get help for a command " ) + " \n " ;
strUsage + = " \n " + HelpMessageCli ( true ) ;
strUsage + = " \n " + HelpMessageCli ( ) ;
}
fprintf ( stdout , " %s " , strUsage . c_str ( ) ) ;
@ -58,6 +84,136 @@ static bool AppInitRPC(int argc, char* argv[])
@@ -58,6 +84,136 @@ static bool AppInitRPC(int argc, char* argv[])
return true ;
}
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 ;
}
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 = EXIT_FAILURE ;
}
catch ( . . . ) {
PrintExceptionContinue ( NULL , " CommandLineRPC() " ) ;
throw ;
}
if ( strPrint ! = " " )
{
fprintf ( ( nRet = = 0 ? stdout : stderr ) , " %s \n " , strPrint . c_str ( ) ) ;
}
return nRet ;
}
int main ( int argc , char * argv [ ] )
{
SetupEnvironment ( ) ;