rpcserver.cpp 36 KB
Newer Older
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
Fordy's avatar
Fordy committed
4
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5

6
#include "rpcserver.h"
7
8

#include "base58.h"
9
#include "init.h"
10
#include "main.h"
11
#include "ui_interface.h"
12
#include "util.h"
13
#ifdef ENABLE_WALLET
14
#include "wallet.h"
15
#endif
16

17
#include <boost/algorithm/string.hpp>
18
#include <boost/asio.hpp>
19
#include <boost/asio/ssl.hpp>
20
#include <boost/bind.hpp>
Pieter Wuille's avatar
Pieter Wuille committed
21
#include <boost/filesystem.hpp>
22
#include <boost/foreach.hpp>
23
24
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
25
#include <boost/shared_ptr.hpp>
26
#include "json/json_spirit_writer_template.h"
Gavin Andresen's avatar
Gavin Andresen committed
27

28
29
30
31
32
using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace json_spirit;

33
34
static std::string strRPCUserColonPass;

35
36
// These are created by StartRPCThreads, destroyed in StopRPCThreads
static asio::io_service* rpc_io_service = NULL;
37
static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
38
39
static ssl::context* rpc_ssl_context = NULL;
static boost::thread_group* rpc_worker_group = NULL;
40
static boost::asio::io_service::work *rpc_dummy_work = NULL;
41
static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
42
static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors;
43

44
void RPCTypeCheck(const Array& params,
45
46
                  const list<Value_type>& typesExpected,
                  bool fAllowNull)
47
{
48
    unsigned int i = 0;
49
50
51
52
53
    BOOST_FOREACH(Value_type t, typesExpected)
    {
        if (params.size() <= i)
            break;

54
55
        const Value& v = params[i];
        if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
56
57
58
        {
            string err = strprintf("Expected type %s, got %s",
                                   Value_type_name[t], Value_type_name[v.type()]);
59
            throw JSONRPCError(RPC_TYPE_ERROR, err);
60
61
62
63
64
65
        }
        i++;
    }
}

void RPCTypeCheck(const Object& o,
66
67
                  const map<string, Value_type>& typesExpected,
                  bool fAllowNull)
68
69
70
71
{
    BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
    {
        const Value& v = find_value(o, t.first);
72
        if (!fAllowNull && v.type() == null_type)
73
            throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
74
75

        if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
76
77
        {
            string err = strprintf("Expected type %s for %s, got %s",
78
                                   Value_type_name[t.second], t.first, Value_type_name[v.type()]);
79
            throw JSONRPCError(RPC_TYPE_ERROR, err);
80
81
82
83
        }
    }
}

84
int64_t AmountFromValue(const Value& value)
85
86
87
{
    double dAmount = value.get_real();
    if (dAmount <= 0.0 || dAmount > 21000000.0)
88
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
89
    int64_t nAmount = roundint64(dAmount * COIN);
90
    if (!MoneyRange(nAmount))
91
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
92
93
94
    return nAmount;
}

95
Value ValueFromAmount(int64_t amount)
96
97
98
99
{
    return (double)amount / (double)COIN;
}

100
std::string HexBits(unsigned int nBits)
101
102
103
104
105
106
107
108
109
{
    union {
        int32_t nBits;
        char cBits[4];
    } uBits;
    uBits.nBits = htonl((int32_t)nBits);
    return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
}

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
uint256 ParseHashV(const Value& v, string strName)
{
    string strHex;
    if (v.type() == str_type)
        strHex = v.get_str();
    if (!IsHex(strHex)) // Note: IsHex("") is false
        throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
    uint256 result;
    result.SetHex(strHex);
    return result;
}
uint256 ParseHashO(const Object& o, string strKey)
{
    return ParseHashV(find_value(o, strKey), strKey);
}
vector<unsigned char> ParseHexV(const Value& v, string strName)
{
    string strHex;
    if (v.type() == str_type)
        strHex = v.get_str();
    if (!IsHex(strHex))
        throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
    return ParseHex(strHex);
}
vector<unsigned char> ParseHexO(const Object& o, string strKey)
{
    return ParseHexV(find_value(o, strKey), strKey);
}
138

139

140
141
142
143
///
/// Note: This interface may still be subject to change.
///

144
string CRPCTable::help(string strCommand) const
145
146
147
{
    string strRet;
    set<rpcfn_type> setDone;
148
    for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
149
    {
150
        const CRPCCommand *pcmd = mi->second;
151
        string strMethod = mi->first;
152
        // We already filter duplicates, but these deprecated screw up the sort order
153
        if (strMethod.find("label") != string::npos)
154
155
156
            continue;
        if (strCommand != "" && strMethod != strCommand)
            continue;
157
#ifdef ENABLE_WALLET
158
159
        if (pcmd->reqWallet && !pwalletMain)
            continue;
160
#endif
161

162
163
164
        try
        {
            Array params;
165
            rpcfn_type pfn = pcmd->actor;
166
167
168
169
170
171
172
173
            if (setDone.insert(pfn).second)
                (*pfn)(params, true);
        }
        catch (std::exception& e)
        {
            // Help text is returned in an exception
            string strHelp = string(e.what());
            if (strCommand == "")
174
                if (strHelp.find('\n') != string::npos)
175
176
177
178
179
                    strHelp = strHelp.substr(0, strHelp.find('\n'));
            strRet += strHelp + "\n";
        }
    }
    if (strRet == "")
180
        strRet = strprintf("help: unknown command: %s\n", strCommand);
181
182
183
184
    strRet = strRet.substr(0,strRet.size()-1);
    return strRet;
}

185
186
187
188
Value help(const Array& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw runtime_error(
sje's avatar
sje committed
189
190
191
192
193
194
195
            "help ( \"command\" )\n"
            "\nList all commands, or get help for a specified command.\n"
            "\nArguments:\n"
            "1. \"command\"     (string, optional) The command to get help on\n"
            "\nResult:\n"
            "\"text\"     (string) The help text\n"
        );
196
197
198
199
200
201
202
203

    string strCommand;
    if (params.size() > 0)
        strCommand = params[0].get_str();

    return tableRPC.help(strCommand);
}

204
205
206

Value stop(const Array& params, bool fHelp)
{
207
    // Accept the deprecated and ignored 'detach' boolean argument
208
    if (fHelp || params.size() > 1)
209
        throw runtime_error(
210
            "stop\n"
sje's avatar
sje committed
211
            "\nStop Bitcoin server.");
212
    // Shutdown will take long enough that the response should get back
213
    StartShutdown();
214
    return "Bitcoin server stopping";
215
216
217
218
219
220
221
222
}



//
// Call Table
//

223

224
static const CRPCCommand vRPCCommands[] =
225
226
{ //  name                      actor (function)         okSafeMode threadSafe reqWallet
  //  ------------------------  -----------------------  ---------- ---------- ---------
227
228
    /* Overall control/query calls */
    { "getinfo",                &getinfo,                true,      false,      false }, /* uses wallet if enabled */
229
230
    { "help",                   &help,                   true,      true,       false },
    { "stop",                   &stop,                   true,      true,       false },
231
232

    /* P2P networking */
233
    { "getnetworkinfo",         &getnetworkinfo,         true,      false,      false },
234
235
    { "addnode",                &addnode,                true,      true,       false },
    { "getaddednodeinfo",       &getaddednodeinfo,       true,      true,       false },
236
    { "getconnectioncount",     &getconnectioncount,     true,      false,      false },
Scott Ellis's avatar
Scott Ellis committed
237
    { "getnettotals",           &getnettotals,           true,      true,       false },
238
239
240
241
    { "getpeerinfo",            &getpeerinfo,            true,      false,      false },
    { "ping",                   &ping,                   true,      false,      false },

    /* Block chain and UTXO */
242
    { "getblockchaininfo",      &getblockchaininfo,      true,      false,      false },
243
244
    { "getbestblockhash",       &getbestblockhash,       true,      false,      false },
    { "getblockcount",          &getblockcount,          true,      false,      false },
245
246
    { "getblock",               &getblock,               false,     false,      false },
    { "getblockhash",           &getblockhash,           false,     false,      false },
247
248
    { "getdifficulty",          &getdifficulty,          true,      false,      false },
    { "getrawmempool",          &getrawmempool,          true,      false,      false },
249
    { "gettxout",               &gettxout,               true,      false,      false },
250
    { "gettxoutsetinfo",        &gettxoutsetinfo,        true,      false,      false },
251
252
    { "verifychain",            &verifychain,            true,      false,      false },

253
254
    /* Mining */
    { "getblocktemplate",       &getblocktemplate,       true,      false,      false },
255
256
    { "getmininginfo",          &getmininginfo,          true,      false,      false },
    { "getnetworkhashps",       &getnetworkhashps,       true,      false,      false },
257
    { "submitblock",            &submitblock,            false,     true,       false },
258
259
260
261
262
263
264
265
266
267

    /* Raw transactions */
    { "createrawtransaction",   &createrawtransaction,   false,     false,      false },
    { "decoderawtransaction",   &decoderawtransaction,   false,     false,      false },
    { "decodescript",           &decodescript,           false,     false,      false },
    { "getrawtransaction",      &getrawtransaction,      false,     false,      false },
    { "sendrawtransaction",     &sendrawtransaction,     false,     false,      false },
    { "signrawtransaction",     &signrawtransaction,     false,     false,      false }, /* uses wallet if enabled */

    /* Utility functions */
268
    { "createmultisig",         &createmultisig,         true,      true ,      false },
269
    { "validateaddress",        &validateaddress,        true,      false,      false }, /* uses wallet if enabled */
270
    { "verifymessage",          &verifymessage,          false,     false,      false },
271
272
    { "estimatefee",            &estimatefee,            true,      true,       false },
    { "estimatepriority",       &estimatepriority,       true,      true,       false },
273
274
275

#ifdef ENABLE_WALLET
    /* Wallet */
276
277
278
279
280
    { "addmultisigaddress",     &addmultisigaddress,     false,     false,      true },
    { "backupwallet",           &backupwallet,           true,      false,      true },
    { "dumpprivkey",            &dumpprivkey,            true,      false,      true },
    { "dumpwallet",             &dumpwallet,             true,      false,      true },
    { "encryptwallet",          &encryptwallet,          false,     false,      true },
281
282
283
284
    { "getaccountaddress",      &getaccountaddress,      true,      false,      true },
    { "getaccount",             &getaccount,             false,     false,      true },
    { "getaddressesbyaccount",  &getaddressesbyaccount,  true,      false,      true },
    { "getbalance",             &getbalance,             false,     false,      true },
285
286
287
288
    { "getnewaddress",          &getnewaddress,          true,      false,      true },
    { "getrawchangeaddress",    &getrawchangeaddress,    true,      false,      true },
    { "getreceivedbyaccount",   &getreceivedbyaccount,   false,     false,      true },
    { "getreceivedbyaddress",   &getreceivedbyaddress,   false,     false,      true },
289
    { "gettransaction",         &gettransaction,         false,     false,      true },
290
291
    { "getunconfirmedbalance",  &getunconfirmedbalance,  false,     false,      true },
    { "getwalletinfo",          &getwalletinfo,          true,      false,      true },
292
293
    { "importprivkey",          &importprivkey,          false,     false,      true },
    { "importwallet",           &importwallet,           false,     false,      true },
294
295
296
297
298
299
300
301
    { "keypoolrefill",          &keypoolrefill,          true,      false,      true },
    { "listaccounts",           &listaccounts,           false,     false,      true },
    { "listaddressgroupings",   &listaddressgroupings,   false,     false,      true },
    { "listlockunspent",        &listlockunspent,        false,     false,      true },
    { "listreceivedbyaccount",  &listreceivedbyaccount,  false,     false,      true },
    { "listreceivedbyaddress",  &listreceivedbyaddress,  false,     false,      true },
    { "listsinceblock",         &listsinceblock,         false,     false,      true },
    { "listtransactions",       &listtransactions,       false,     false,      true },
302
303
    { "listunspent",            &listunspent,            false,     false,      true },
    { "lockunspent",            &lockunspent,            false,     false,      true },
304
305
306
307
308
    { "move",                   &movecmd,                false,     false,      true },
    { "sendfrom",               &sendfrom,               false,     false,      true },
    { "sendmany",               &sendmany,               false,     false,      true },
    { "sendtoaddress",          &sendtoaddress,          false,     false,      true },
    { "setaccount",             &setaccount,             true,      false,      true },
309
    { "settxfee",               &settxfee,               false,     false,      true },
310
311
312
313
    { "signmessage",            &signmessage,            false,     false,      true },
    { "walletlock",             &walletlock,             true,      false,      true },
    { "walletpassphrasechange", &walletpassphrasechange, false,     false,      true },
    { "walletpassphrase",       &walletpassphrase,       true,      false,      true },
314
315
316
317

    /* Wallet-enabled mining */
    { "getgenerate",            &getgenerate,            true,      false,      false },
    { "gethashespersec",        &gethashespersec,        true,      false,      false },
318
    { "setgenerate",            &setgenerate,            true,      true,       false },
319
#endif // ENABLE_WALLET
320
321
};

322
CRPCTable::CRPCTable()
323
324
325
326
{
    unsigned int vcidx;
    for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
    {
327
        const CRPCCommand *pcmd;
328

329
330
331
332
        pcmd = &vRPCCommands[vcidx];
        mapCommands[pcmd->name] = pcmd;
    }
}
333

334
335
336
337
338
339
340
const CRPCCommand *CRPCTable::operator[](string name) const
{
    map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
    if (it == mapCommands.end())
        return NULL;
    return (*it).second;
}
341
342
343
344
345
346
347
348
349


bool HTTPAuthorized(map<string, string>& mapHeaders)
{
    string strAuth = mapHeaders["authorization"];
    if (strAuth.substr(0,6) != "Basic ")
        return false;
    string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
    string strUserPass = DecodeBase64(strUserPass64);
350
    return TimingResistantEqual(strUserPass, strRPCUserColonPass);
351
352
353
354
355
}

void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
{
    // Send error reply from json-rpc error object
356
    int nStatus = HTTP_INTERNAL_SERVER_ERROR;
357
    int code = find_value(objError, "code").get_int();
358
359
    if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
    else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
360
    string strReply = JSONRPCReply(Value::null, objError, id);
361
    stream << HTTPReply(nStatus, strReply, false) << std::flush;
362
363
}

364
CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address)
365
{
366
    CNetAddr netaddr;
367
368
369
370
    // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
    if (address.is_v6()
     && (address.to_v6().is_v4_compatible()
      || address.to_v6().is_v4_mapped()))
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
        address = address.to_v6().to_v4();

    if(address.is_v4())
    {
        boost::asio::ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();
        netaddr.SetRaw(NET_IPV4, &bytes[0]);
    }
    else
    {
        boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
        netaddr.SetRaw(NET_IPV6, &bytes[0]);
    }
    return netaddr;
}

bool ClientAllowed(const boost::asio::ip::address& address)
{
    CNetAddr netaddr = BoostAsioToCNetAddr(address);
    BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
        if (subnet.Match(netaddr))
391
392
393
394
            return true;
    return false;
}

395
396
class AcceptedConnection
{
397
398
399
400
401
402
403
public:
    virtual ~AcceptedConnection() {}

    virtual std::iostream& stream() = 0;
    virtual std::string peer_address_to_string() const = 0;
    virtual void close() = 0;
};
404

405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
template <typename Protocol>
class AcceptedConnectionImpl : public AcceptedConnection
{
public:
    AcceptedConnectionImpl(
            asio::io_service& io_service,
            ssl::context &context,
            bool fUseSSL) :
        sslStream(io_service, context),
        _d(sslStream, fUseSSL),
        _stream(_d)
    {
    }

    virtual std::iostream& stream()
    {
        return _stream;
    }

    virtual std::string peer_address_to_string() const
    {
        return peer.address().to_string();
    }
428

429
430
431
432
433
434
435
436
437
438
439
    virtual void close()
    {
        _stream.close();
    }

    typename Protocol::endpoint peer;
    asio::ssl::stream<typename Protocol::socket> sslStream;

private:
    SSLIOStreamDevice<Protocol> _d;
    iostreams::stream< SSLIOStreamDevice<Protocol> > _stream;
440
441
};

442
void ServiceConnection(AcceptedConnection *conn);
443

444
// Forward declaration required for RPCListen
445
446
template <typename Protocol, typename SocketAcceptorService>
static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
447
448
                             ssl::context& context,
                             bool fUseSSL,
449
                             boost::shared_ptr< AcceptedConnection > conn,
450
451
452
453
454
                             const boost::system::error_code& error);

/**
 * Sets up I/O resources to accept and handle a new connection.
 */
455
456
template <typename Protocol, typename SocketAcceptorService>
static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
457
458
459
460
                   ssl::context& context,
                   const bool fUseSSL)
{
    // Accept connection
461
    boost::shared_ptr< AcceptedConnectionImpl<Protocol> > conn(new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL));
462
463
464
465

    acceptor->async_accept(
            conn->sslStream.lowest_layer(),
            conn->peer,
466
            boost::bind(&RPCAcceptHandler<Protocol, SocketAcceptorService>,
467
468
469
470
                acceptor,
                boost::ref(context),
                fUseSSL,
                conn,
471
                _1));
472
473
}

474

475
476
477
/**
 * Accept and handle incoming connection.
 */
478
479
template <typename Protocol, typename SocketAcceptorService>
static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
480
481
                             ssl::context& context,
                             const bool fUseSSL,
482
                             boost::shared_ptr< AcceptedConnection > conn,
483
484
                             const boost::system::error_code& error)
{
485
    // Immediately start accepting new connections, except when we're cancelled or our socket is closed.
486
    if (error != asio::error::operation_aborted && acceptor->is_open())
487
        RPCListen(acceptor, context, fUseSSL);
488

489
    AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn.get());
490

491
492
    if (error)
    {
493
494
        // TODO: Actually handle errors
        LogPrintf("%s: Error: %s\n", __func__, error.message());
495
496
497
498
    }
    // Restrict callers by IP.  It is important to
    // do this before starting client thread, to filter out
    // certain DoS and misbehaving clients.
499
    else if (tcp_conn && !ClientAllowed(tcp_conn->peer.address()))
500
501
502
    {
        // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
        if (!fUseSSL)
503
            conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
504
        conn->close();
505
    }
506
    else {
507
        ServiceConnection(conn.get());
508
        conn->close();
509
510
511
    }
}

512
513
514
515
516
517
518
519
static ip::tcp::endpoint ParseEndpoint(const std::string &strEndpoint, int defaultPort)
{
    std::string addr;
    int port = defaultPort;
    SplitHostPort(strEndpoint, port, addr);
    return ip::tcp::endpoint(asio::ip::address::from_string(addr), port);
}

520
void StartRPCThreads()
521
{
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
    rpc_allow_subnets.clear();
    rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
    rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
    if (mapMultiArgs.count("-rpcallowip"))
    {
        const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
        BOOST_FOREACH(string strAllow, vAllow)
        {
            CSubNet subnet(strAllow);
            if(!subnet.IsValid())
            {
                uiInterface.ThreadSafeMessageBox(
                    strprintf("Invalid -rpcallowip subnet specification: %s", strAllow),
                    "", CClientUIInterface::MSG_ERROR);
                StartShutdown();
                return;
            }
            rpc_allow_subnets.push_back(subnet);
        }
    }
    std::string strAllowed;
    BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
        strAllowed += subnet.ToString() + " ";
    LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);

547
    strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
548
549
    if (((mapArgs["-rpcpassword"] == "") ||
         (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
550
    {
551
552
        unsigned char rand_pwd[32];
        RAND_bytes(rand_pwd, 32);
553
554
555
556
557
        string strWhatAmI = "To use bitcoind";
        if (mapArgs.count("-server"))
            strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
        else if (mapArgs.count("-daemon"))
            strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
558
        uiInterface.ThreadSafeMessageBox(strprintf(
559
560
            _("%s, you must set a rpcpassword in the configuration file:\n"
              "%s\n"
561
562
563
564
              "It is recommended you use the following random password:\n"
              "rpcuser=bitcoinrpc\n"
              "rpcpassword=%s\n"
              "(you do not need to remember this password)\n"
565
              "The username and password MUST NOT be the same.\n"
Gavin Andresen's avatar
Gavin Andresen committed
566
567
568
              "If the file does not exist, create it with owner-readable-only file permissions.\n"
              "It is also recommended to set alertnotify so you are notified of problems;\n"
              "for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@foo.com\n"),
569
570
571
                strWhatAmI,
                GetConfigFile().string(),
                EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
572
                "", CClientUIInterface::MSG_ERROR);
573
        StartShutdown();
574
575
576
        return;
    }

577
578
579
    assert(rpc_io_service == NULL);
    rpc_io_service = new asio::io_service();
    rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23);
580

581
    const bool fUseSSL = GetBoolArg("-rpcssl", false);
582

583
584
    if (fUseSSL)
    {
585
        rpc_ssl_context->set_options(ssl::context::no_sslv2);
586
587
588

        filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
        if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
589
        if (filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string());
590
        else LogPrintf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string());
591
592
593

        filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
        if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
594
        if (filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem);
595
        else LogPrintf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string());
596

597
        string strCiphers = GetArg("-rpcsslciphers", "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH");
598
        SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str());
599
600
    }

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
    std::vector<ip::tcp::endpoint> vEndpoints;
    bool bBindAny = false;
    int defaultPort = GetArg("-rpcport", Params().RPCPort());
    if (!mapArgs.count("-rpcallowip")) // Default to loopback if not allowing external IPs
    {
        vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::loopback(), defaultPort));
        vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v4::loopback(), defaultPort));
        if (mapArgs.count("-rpcbind"))
        {
            LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
        }
    } else if (mapArgs.count("-rpcbind")) // Specific bind address
    {
        BOOST_FOREACH(const std::string &addr, mapMultiArgs["-rpcbind"])
        {
            try {
                vEndpoints.push_back(ParseEndpoint(addr, defaultPort));
            }
            catch(boost::system::system_error &e)
            {
                uiInterface.ThreadSafeMessageBox(
                    strprintf(_("Could not parse -rpcbind value %s as network address"), addr),
                    "", CClientUIInterface::MSG_ERROR);
                StartShutdown();
                return;
            }
        }
    } else { // No specific bind address specified, bind to any
        vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::any(), defaultPort));
        vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v4::any(), defaultPort));
        // Prefer making the socket dual IPv6/IPv4 instead of binding
        // to both addresses seperately.
        bBindAny = true;
    }
635

636
637
    bool fListening = false;
    std::string strerr;
638
    BOOST_FOREACH(const ip::tcp::endpoint &endpoint, vEndpoints)
639
    {
640
641
642
        asio::ip::address bindAddress = endpoint.address();
        LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", bindAddress.to_string(), endpoint.port(), bBindAny);
        boost::system::error_code v6_only_error;
643
        boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
644

645
        try {
646
647
            acceptor->open(endpoint.protocol());
            acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
648
649
650
651
652

            // Try making the socket dual IPv6/IPv4 when listening on the IPv6 "any" address
            acceptor->set_option(boost::asio::ip::v6_only(
                !bBindAny || bindAddress != asio::ip::address_v6::any()), v6_only_error);

653
654
655
            acceptor->bind(endpoint);
            acceptor->listen(socket_base::max_connections);

656
            RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
657
658

            fListening = true;
659
            rpc_acceptors.push_back(acceptor);
660
661
662
663
664
665
666
667
            // If dual IPv6/IPv4 bind succesful, skip binding to IPv4 separately
            if(bBindAny && bindAddress == asio::ip::address_v6::any() && !v6_only_error)
                break;
        }
        catch(boost::system::system_error &e)
        {
            LogPrintf("ERROR: Binding RPC on address %s port %i failed: %s\n", bindAddress.to_string(), endpoint.port(), e.what());
            strerr = strprintf(_("An error occurred while setting up the RPC address %s port %u for listening: %s"), bindAddress.to_string(), endpoint.port(), e.what());
668
        }
669
670
671
    }

    if (!fListening) {
672
        uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR);
673
        StartShutdown();
674
675
        return;
    }
676

677
678
679
680
681
    rpc_worker_group = new boost::thread_group();
    for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
        rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
}

682
683
684
685
686
687
688
689
690
691
692
693
694
void StartDummyRPCThread()
{
    if(rpc_io_service == NULL)
    {
        rpc_io_service = new asio::io_service();
        /* Create dummy "work" to keep the thread from exiting when no timeouts active,
         * see http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/io_service.html#boost_asio.reference.io_service.stopping_the_io_service_from_running_out_of_work */
        rpc_dummy_work = new asio::io_service::work(*rpc_io_service);
        rpc_worker_group = new boost::thread_group();
        rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
    }
}

695
696
697
698
void StopRPCThreads()
{
    if (rpc_io_service == NULL) return;

699
700
701
    // First, cancel all timers and acceptors
    // This is not done automatically by ->stop(), and in some cases the destructor of
    // asio::io_service can hang if this is skipped.
702
    boost::system::error_code ec;
703
    BOOST_FOREACH(const boost::shared_ptr<ip::tcp::acceptor> &acceptor, rpc_acceptors)
704
705
706
707
708
    {
        acceptor->cancel(ec);
        if (ec)
            LogPrintf("%s: Warning: %s when cancelling acceptor", __func__, ec.message());
    }
709
710
    rpc_acceptors.clear();
    BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr<deadline_timer>) &timer, deadlineTimers)
711
712
713
714
715
    {
        timer.second->cancel(ec);
        if (ec)
            LogPrintf("%s: Warning: %s when cancelling timer", __func__, ec.message());
    }
716
    deadlineTimers.clear();
717

718
    rpc_io_service->stop();
719
720
    if (rpc_worker_group != NULL)
        rpc_worker_group->join_all();
721
    delete rpc_dummy_work; rpc_dummy_work = NULL;
722
723
724
    delete rpc_worker_group; rpc_worker_group = NULL;
    delete rpc_ssl_context; rpc_ssl_context = NULL;
    delete rpc_io_service; rpc_io_service = NULL;
725
726
}

727
728
729
730
731
732
void RPCRunHandler(const boost::system::error_code& err, boost::function<void(void)> func)
{
    if (!err)
        func();
}

733
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
734
735
736
737
738
739
740
741
742
743
744
745
{
    assert(rpc_io_service != NULL);

    if (deadlineTimers.count(name) == 0)
    {
        deadlineTimers.insert(make_pair(name,
                                        boost::shared_ptr<deadline_timer>(new deadline_timer(*rpc_io_service))));
    }
    deadlineTimers[name]->expires_from_now(posix_time::seconds(nSeconds));
    deadlineTimers[name]->async_wait(boost::bind(RPCRunHandler, _1, func));
}

746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
class JSONRequest
{
public:
    Value id;
    string strMethod;
    Array params;

    JSONRequest() { id = Value::null; }
    void parse(const Value& valRequest);
};

void JSONRequest::parse(const Value& valRequest)
{
    // Parse request
    if (valRequest.type() != obj_type)
761
        throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
762
763
764
765
766
767
768
769
    const Object& request = valRequest.get_obj();

    // Parse id now so errors from here on will have the id
    id = find_value(request, "id");

    // Parse method
    Value valMethod = find_value(request, "method");
    if (valMethod.type() == null_type)
770
        throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
771
    if (valMethod.type() != str_type)
772
        throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
773
    strMethod = valMethod.get_str();
Pieter Wuille's avatar
Pieter Wuille committed
774
    if (strMethod != "getblocktemplate")
775
        LogPrint("rpc", "ThreadRPCServer method=%s\n", strMethod);
776
777
778
779
780
781
782
783

    // Parse params
    Value valParams = find_value(request, "params");
    if (valParams.type() == array_type)
        params = valParams.get_array();
    else if (valParams.type() == null_type)
        params = Array();
    else
784
        throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
785
786
}

787

788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
static Object JSONRPCExecOne(const Value& req)
{
    Object rpc_result;

    JSONRequest jreq;
    try {
        jreq.parse(req);

        Value result = tableRPC.execute(jreq.strMethod, jreq.params);
        rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
    }
    catch (Object& objError)
    {
        rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
    }
    catch (std::exception& e)
    {
        rpc_result = JSONRPCReplyObj(Value::null,
806
                                     JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
807
808
809
810
811
812
813
814
815
816
817
    }

    return rpc_result;
}

static string JSONRPCExecBatch(const Array& vReq)
{
    Array ret;
    for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
        ret.push_back(JSONRPCExecOne(vReq[reqIdx]));

818
    return write_string(Value(ret), false) + "\n";
819
820
}

821
void ServiceConnection(AcceptedConnection *conn)
822
{
823
    bool fRun = true;
Gavin Andresen's avatar
Gavin Andresen committed
824
    while (fRun && !ShutdownRequested())
825
    {
826
        int nProto = 0;
827
        map<string, string> mapHeaders;
828
829
830
831
832
        string strRequest, strMethod, strURI;

        // Read HTTP request line
        if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI))
            break;
833

834
835
        // Read HTTP message headers and body
        ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
836

837
838
839
840
841
        if (strURI != "/") {
            conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
            break;
        }

842
843
844
        // Check authorization
        if (mapHeaders.count("authorization") == 0)
        {
845
            conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
846
            break;
847
848
849
        }
        if (!HTTPAuthorized(mapHeaders))
        {
850
            LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
851
            /* Deter brute-forcing short passwords.
852
853
               If this results in a DoS the user really
               shouldn't have their RPC port exposed. */
854
            if (mapArgs["-rpcpassword"].size() < 20)
855
                MilliSleep(250);
856

857
            conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
858
            break;
859
        }
860
861
        if (mapHeaders["connection"] == "close")
            fRun = false;
862

863
        JSONRequest jreq;
864
865
866
867
        try
        {
            // Parse request
            Value valRequest;
868
            if (!read_string(strRequest, valRequest))
869
                throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
870

871
872
873
874
875
            string strReply;

            // singleton request
            if (valRequest.type() == obj_type) {
                jreq.parse(valRequest);
876

877
                Value result = tableRPC.execute(jreq.strMethod, jreq.params);
878

879
880
881
882
883
884
885
                // Send reply
                strReply = JSONRPCReply(result, Value::null, jreq.id);

            // array of requests
            } else if (valRequest.type() == array_type)
                strReply = JSONRPCExecBatch(valRequest.get_array());
            else
886
                throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
887

888
            conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
889
890
891
        }
        catch (Object& objError)
        {
892
            ErrorReply(conn->stream(), objError, jreq.id);
893
            break;
894
895
896
        }
        catch (std::exception& e)
        {
897
            ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
898
            break;
899
900
901
902
        }
    }
}

903
904
905
906
907
json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
{
    // Find method
    const CRPCCommand *pcmd = tableRPC[strMethod];
    if (!pcmd)
908
        throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
909
#ifdef ENABLE_WALLET
910
911
    if (pcmd->reqWallet && !pwalletMain)
        throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
912
#endif
913

914
915
    // Observe safe mode
    string strWarning = GetWarnings("rpc");
916
    if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
917
        !pcmd->okSafeMode)
918
        throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
919
920
921
922
923
924

    try
    {
        // Execute
        Value result;
        {
925
            if (pcmd->threadSafe)
926
                result = pcmd->actor(params, false);
927
#ifdef ENABLE_WALLET
928
929
930
931
            else if (!pwalletMain) {
                LOCK(cs_main);
                result = pcmd->actor(params, false);
            } else {
932
933
934
                LOCK2(cs_main, pwalletMain->cs_wallet);
                result = pcmd->actor(params, false);
            }
935
936
937
938
939
940
#else // ENABLE_WALLET
            else {
                LOCK(cs_main);
                result = pcmd->actor(params, false);
            }
#endif // !ENABLE_WALLET
941
942
943
944
945
        }
        return result;
    }
    catch (std::exception& e)
    {
946
        throw JSONRPCError(RPC_MISC_ERROR, e.what());
947
948
    }
}
949

950
951
952
953
954
955
956
957
958
std::string HelpExampleCli(string methodname, string args){
    return "> bitcoin-cli " + methodname + " " + args + "\n";
}

std::string HelpExampleRpc(string methodname, string args){
    return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
        "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
}

959
const CRPCTable tableRPC;