Merge remote branch 'refs/remotes/svn/trunk' into svn
[novacoin.git] / rpc.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "headers.h"
6 #undef printf
7 #include <boost/asio.hpp>
8 #include <boost/iostreams/concepts.hpp>
9 #include <boost/iostreams/stream.hpp>
10 #ifdef USE_SSL
11 #include <boost/asio/ssl.hpp> 
12 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
13 #endif
14 #include "json/json_spirit_reader_template.h"
15 #include "json/json_spirit_writer_template.h"
16 #include "json/json_spirit_utils.h"
17 #define printf OutputDebugStringF
18 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
19 // precompiled in headers.h.  The problem might be when the pch file goes over
20 // a certain size around 145MB.  If we need access to json_spirit outside this
21 // file, we could use the compiled json_spirit option.
22
23 using namespace boost::asio;
24 using namespace json_spirit;
25
26 void ThreadRPCServer2(void* parg);
27 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
28 extern map<string, rpcfn_type> mapCallTable;
29
30
31 Object JSONRPCError(int code, const string& message)
32 {
33     Object error;
34     error.push_back(Pair("code", code));
35     error.push_back(Pair("message", message));
36     return error;
37 }
38
39
40 void PrintConsole(const char* format, ...)
41 {
42     char buffer[50000];
43     int limit = sizeof(buffer);
44     va_list arg_ptr;
45     va_start(arg_ptr, format);
46     int ret = _vsnprintf(buffer, limit, format, arg_ptr);
47     va_end(arg_ptr);
48     if (ret < 0 || ret >= limit)
49     {
50         ret = limit - 1;
51         buffer[limit-1] = 0;
52     }
53 #if defined(__WXMSW__) && defined(GUI)
54     MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
55 #else
56     fprintf(stdout, "%s", buffer);
57 #endif
58 }
59
60
61
62
63
64
65
66 ///
67 /// Note: This interface may still be subject to change.
68 ///
69
70
71 Value help(const Array& params, bool fHelp)
72 {
73     if (fHelp || params.size() > 1)
74         throw runtime_error(
75             "help [command]\n"
76             "List commands, or get help for a command.");
77
78     string strCommand;
79     if (params.size() > 0)
80         strCommand = params[0].get_str();
81
82     string strRet;
83     set<rpcfn_type> setDone;
84     for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
85     {
86         string strMethod = (*mi).first;
87         // We already filter duplicates, but these deprecated screw up the sort order
88         if (strMethod == "getamountreceived" ||
89             strMethod == "getallreceived")
90             continue;
91         if (strCommand != "" && strMethod != strCommand)
92             continue;
93         try
94         {
95             Array params;
96             rpcfn_type pfn = (*mi).second;
97             if (setDone.insert(pfn).second)
98                 (*pfn)(params, true);
99         }
100         catch (std::exception& e)
101         {
102             // Help text is returned in an exception
103             string strHelp = string(e.what());
104             if (strCommand == "")
105                 if (strHelp.find('\n') != -1)
106                     strHelp = strHelp.substr(0, strHelp.find('\n'));
107             strRet += strHelp + "\n";
108         }
109     }
110     if (strRet == "")
111         strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
112     strRet = strRet.substr(0,strRet.size()-1);
113     return strRet;
114 }
115
116
117 Value stop(const Array& params, bool fHelp)
118 {
119     if (fHelp || params.size() != 0)
120         throw runtime_error(
121             "stop\n"
122             "Stop bitcoin server.");
123
124     // Shutdown will take long enough that the response should get back
125     CreateThread(Shutdown, NULL);
126     return "bitcoin server stopping";
127 }
128
129
130 Value getblockcount(const Array& params, bool fHelp)
131 {
132     if (fHelp || params.size() != 0)
133         throw runtime_error(
134             "getblockcount\n"
135             "Returns the number of blocks in the longest block chain.");
136
137     return nBestHeight;
138 }
139
140
141 Value getblocknumber(const Array& params, bool fHelp)
142 {
143     if (fHelp || params.size() != 0)
144         throw runtime_error(
145             "getblocknumber\n"
146             "Returns the block number of the latest block in the longest block chain.");
147
148     return nBestHeight;
149 }
150
151
152 Value getconnectioncount(const Array& params, bool fHelp)
153 {
154     if (fHelp || params.size() != 0)
155         throw runtime_error(
156             "getconnectioncount\n"
157             "Returns the number of connections to other nodes.");
158
159     return (int)vNodes.size();
160 }
161
162
163 double GetDifficulty()
164 {
165     // Floating point number that is a multiple of the minimum difficulty,
166     // minimum difficulty = 1.0.
167     if (pindexBest == NULL)
168         return 1.0;
169     int nShift = 256 - 32 - 31; // to fit in a uint
170     double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint();
171     double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint();
172     return dMinimum / dCurrently;
173 }
174
175 Value getdifficulty(const Array& params, bool fHelp)
176 {
177     if (fHelp || params.size() != 0)
178         throw runtime_error(
179             "getdifficulty\n"
180             "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
181
182     return GetDifficulty();
183 }
184
185
186 Value getbalance(const Array& params, bool fHelp)
187 {
188     if (fHelp || params.size() != 0)
189         throw runtime_error(
190             "getbalance\n"
191             "Returns the server's available balance.");
192
193     return ((double)GetBalance() / (double)COIN);
194 }
195
196
197 Value getgenerate(const Array& params, bool fHelp)
198 {
199     if (fHelp || params.size() != 0)
200         throw runtime_error(
201             "getgenerate\n"
202             "Returns true or false.");
203
204     return (bool)fGenerateBitcoins;
205 }
206
207
208 Value setgenerate(const Array& params, bool fHelp)
209 {
210     if (fHelp || params.size() < 1 || params.size() > 2)
211         throw runtime_error(
212             "setgenerate <generate> [genproclimit]\n"
213             "<generate> is true or false to turn generation on or off.\n"
214             "Generation is limited to [genproclimit] processors, -1 is unlimited.");
215
216     bool fGenerate = true;
217     if (params.size() > 0)
218         fGenerate = params[0].get_bool();
219
220     if (params.size() > 1)
221     {
222         int nGenProcLimit = params[1].get_int();
223         fLimitProcessors = (nGenProcLimit != -1);
224         CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors);
225         if (nGenProcLimit != -1)
226             CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
227     }
228
229     GenerateBitcoins(fGenerate);
230     return Value::null;
231 }
232
233
234 Value gethashespersec(const Array& params, bool fHelp)
235 {
236     if (fHelp || params.size() != 0)
237         throw runtime_error(
238             "gethashespersec\n"
239             "Returns a recent hashes per second performance measurement while generating.");
240
241     if (GetTimeMillis() - nHPSTimerStart > 8000)
242         return (boost::int64_t)0;
243     return (boost::int64_t)dHashesPerSec;
244 }
245
246
247 Value getinfo(const Array& params, bool fHelp)
248 {
249     if (fHelp || params.size() != 0)
250         throw runtime_error(
251             "getinfo\n"
252             "Returns an object containing various state info.");
253
254     Object obj;
255     obj.push_back(Pair("version",       (int)VERSION));
256     obj.push_back(Pair("balance",       (double)GetBalance() / (double)COIN));
257     obj.push_back(Pair("blocks",        (int)nBestHeight));
258     obj.push_back(Pair("connections",   (int)vNodes.size()));
259     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
260     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
261     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
262     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
263     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
264     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
265     return obj;
266 }
267
268
269 Value getnewaddress(const Array& params, bool fHelp)
270 {
271     if (fHelp || params.size() > 1)
272         throw runtime_error(
273             "getnewaddress [label]\n"
274             "Returns a new bitcoin address for receiving payments.  "
275             "If [label] is specified (recommended), it is added to the address book "
276             "so payments received with the address will be labeled.");
277
278     // Parse the label first so we don't generate a key if there's an error
279     string strLabel;
280     if (params.size() > 0)
281         strLabel = params[0].get_str();
282
283     // Generate a new key that is added to wallet
284     string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
285
286     SetAddressBookName(strAddress, strLabel);
287     return strAddress;
288 }
289
290
291 Value setlabel(const Array& params, bool fHelp)
292 {
293     if (fHelp || params.size() < 1 || params.size() > 2)
294         throw runtime_error(
295             "setlabel <bitcoinaddress> <label>\n"
296             "Sets the label associated with the given address.");
297
298     string strAddress = params[0].get_str();
299     string strLabel;
300     if (params.size() > 1)
301         strLabel = params[1].get_str();
302
303     SetAddressBookName(strAddress, strLabel);
304     return Value::null;
305 }
306
307
308 Value getlabel(const Array& params, bool fHelp)
309 {
310     if (fHelp || params.size() != 1)
311         throw runtime_error(
312             "getlabel <bitcoinaddress>\n"
313             "Returns the label associated with the given address.");
314
315     string strAddress = params[0].get_str();
316
317     string strLabel;
318     CRITICAL_BLOCK(cs_mapAddressBook)
319     {
320         map<string, string>::iterator mi = mapAddressBook.find(strAddress);
321         if (mi != mapAddressBook.end() && !(*mi).second.empty())
322             strLabel = (*mi).second;
323     }
324     return strLabel;
325 }
326
327
328 Value getaddressesbylabel(const Array& params, bool fHelp)
329 {
330     if (fHelp || params.size() != 1)
331         throw runtime_error(
332             "getaddressesbylabel <label>\n"
333             "Returns the list of addresses with the given label.");
334
335     string strLabel = params[0].get_str();
336
337     // Find all addresses that have the given label
338     Array ret;
339     CRITICAL_BLOCK(cs_mapAddressBook)
340     {
341         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
342         {
343             const string& strAddress = item.first;
344             const string& strName = item.second;
345             if (strName == strLabel)
346             {
347                 // We're only adding valid bitcoin addresses and not ip addresses
348                 CScript scriptPubKey;
349                 if (scriptPubKey.SetBitcoinAddress(strAddress))
350                     ret.push_back(strAddress);
351             }
352         }
353     }
354     return ret;
355 }
356
357
358 Value sendtoaddress(const Array& params, bool fHelp)
359 {
360     if (fHelp || params.size() < 2 || params.size() > 4)
361         throw runtime_error(
362             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
363             "<amount> is a real and is rounded to the nearest 0.01");
364
365     string strAddress = params[0].get_str();
366
367     // Amount
368     if (params[1].get_real() <= 0.0 || params[1].get_real() > 21000000.0)
369         throw JSONRPCError(-3, "Invalid amount");
370     int64 nAmount = roundint64(params[1].get_real() * 100.00) * CENT;
371
372     // Wallet comments
373     CWalletTx wtx;
374     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
375         wtx.mapValue["message"] = params[2].get_str();
376     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
377         wtx.mapValue["to"]      = params[3].get_str();
378
379     string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
380     if (strError != "")
381         throw JSONRPCError(-4, strError);
382     return "sent";
383 }
384
385
386 Value listtransactions(const Array& params, bool fHelp)
387 {
388     if (fHelp || params.size() > 2)
389         throw runtime_error(
390             "listtransactions [count=10] [includegenerated=false]\n"
391             "Returns up to [count] most recent transactions.");
392
393     int64 nCount = 10;
394     if (params.size() > 0)
395         nCount = params[0].get_int64();
396     bool fGenerated = false;
397     if (params.size() > 1)
398         fGenerated = params[1].get_bool();
399
400     Array ret;
401     //// not finished
402     ret.push_back("not implemented yet");
403     return ret;
404 }
405
406
407 Value getreceivedbyaddress(const Array& params, bool fHelp)
408 {
409     if (fHelp || params.size() < 1 || params.size() > 2)
410         throw runtime_error(
411             "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
412             "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
413
414     // Bitcoin address
415     string strAddress = params[0].get_str();
416     CScript scriptPubKey;
417     if (!scriptPubKey.SetBitcoinAddress(strAddress))
418         throw JSONRPCError(-5, "Invalid bitcoin address");
419     if (!IsMine(scriptPubKey))
420         return (double)0.0;
421
422     // Minimum confirmations
423     int nMinDepth = 1;
424     if (params.size() > 1)
425         nMinDepth = params[1].get_int();
426
427     // Tally
428     int64 nAmount = 0;
429     CRITICAL_BLOCK(cs_mapWallet)
430     {
431         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
432         {
433             const CWalletTx& wtx = (*it).second;
434             if (wtx.IsCoinBase() || !wtx.IsFinal())
435                 continue;
436
437             foreach(const CTxOut& txout, wtx.vout)
438                 if (txout.scriptPubKey == scriptPubKey)
439                     if (wtx.GetDepthInMainChain() >= nMinDepth)
440                         nAmount += txout.nValue;
441         }
442     }
443
444     return (double)nAmount / (double)COIN;
445 }
446
447
448 Value getreceivedbylabel(const Array& params, bool fHelp)
449 {
450     if (fHelp || params.size() < 1 || params.size() > 2)
451         throw runtime_error(
452             "getreceivedbylabel <label> [minconf=1]\n"
453             "Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");
454
455     // Get the set of pub keys that have the label
456     string strLabel = params[0].get_str();
457     set<CScript> setPubKey;
458     CRITICAL_BLOCK(cs_mapAddressBook)
459     {
460         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
461         {
462             const string& strAddress = item.first;
463             const string& strName = item.second;
464             if (strName == strLabel)
465             {
466                 // We're only counting our own valid bitcoin addresses and not ip addresses
467                 CScript scriptPubKey;
468                 if (scriptPubKey.SetBitcoinAddress(strAddress))
469                     if (IsMine(scriptPubKey))
470                         setPubKey.insert(scriptPubKey);
471             }
472         }
473     }
474
475     // Minimum confirmations
476     int nMinDepth = 1;
477     if (params.size() > 1)
478         nMinDepth = params[1].get_int();
479
480     // Tally
481     int64 nAmount = 0;
482     CRITICAL_BLOCK(cs_mapWallet)
483     {
484         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
485         {
486             const CWalletTx& wtx = (*it).second;
487             if (wtx.IsCoinBase() || !wtx.IsFinal())
488                 continue;
489
490             foreach(const CTxOut& txout, wtx.vout)
491                 if (setPubKey.count(txout.scriptPubKey))
492                     if (wtx.GetDepthInMainChain() >= nMinDepth)
493                         nAmount += txout.nValue;
494         }
495     }
496
497     return (double)nAmount / (double)COIN;
498 }
499
500
501
502 struct tallyitem
503 {
504     int64 nAmount;
505     int nConf;
506     tallyitem()
507     {
508         nAmount = 0;
509         nConf = INT_MAX;
510     }
511 };
512
513 Value ListReceived(const Array& params, bool fByLabels)
514 {
515     // Minimum confirmations
516     int nMinDepth = 1;
517     if (params.size() > 0)
518         nMinDepth = params[0].get_int();
519
520     // Whether to include empty accounts
521     bool fIncludeEmpty = false;
522     if (params.size() > 1)
523         fIncludeEmpty = params[1].get_bool();
524
525     // Tally
526     map<uint160, tallyitem> mapTally;
527     CRITICAL_BLOCK(cs_mapWallet)
528     {
529         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
530         {
531             const CWalletTx& wtx = (*it).second;
532             if (wtx.IsCoinBase() || !wtx.IsFinal())
533                 continue;
534
535             int nDepth = wtx.GetDepthInMainChain();
536             if (nDepth < nMinDepth)
537                 continue;
538
539             foreach(const CTxOut& txout, wtx.vout)
540             {
541                 // Only counting our own bitcoin addresses and not ip addresses
542                 uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160();
543                 if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine
544                     continue;
545
546                 tallyitem& item = mapTally[hash160];
547                 item.nAmount += txout.nValue;
548                 item.nConf = min(item.nConf, nDepth);
549             }
550         }
551     }
552
553     // Reply
554     Array ret;
555     map<string, tallyitem> mapLabelTally;
556     CRITICAL_BLOCK(cs_mapAddressBook)
557     {
558         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
559         {
560             const string& strAddress = item.first;
561             const string& strLabel = item.second;
562             uint160 hash160;
563             if (!AddressToHash160(strAddress, hash160))
564                 continue;
565             map<uint160, tallyitem>::iterator it = mapTally.find(hash160);
566             if (it == mapTally.end() && !fIncludeEmpty)
567                 continue;
568
569             int64 nAmount = 0;
570             int nConf = INT_MAX;
571             if (it != mapTally.end())
572             {
573                 nAmount = (*it).second.nAmount;
574                 nConf = (*it).second.nConf;
575             }
576
577             if (fByLabels)
578             {
579                 tallyitem& item = mapLabelTally[strLabel];
580                 item.nAmount += nAmount;
581                 item.nConf = min(item.nConf, nConf);
582             }
583             else
584             {
585                 Object obj;
586                 obj.push_back(Pair("address",       strAddress));
587                 obj.push_back(Pair("label",         strLabel));
588                 obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
589                 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
590                 ret.push_back(obj);
591             }
592         }
593     }
594
595     if (fByLabels)
596     {
597         for (map<string, tallyitem>::iterator it = mapLabelTally.begin(); it != mapLabelTally.end(); ++it)
598         {
599             int64 nAmount = (*it).second.nAmount;
600             int nConf = (*it).second.nConf;
601             Object obj;
602             obj.push_back(Pair("label",         (*it).first));
603             obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
604             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
605             ret.push_back(obj);
606         }
607     }
608
609     return ret;
610 }
611
612 Value listreceivedbyaddress(const Array& params, bool fHelp)
613 {
614     if (fHelp || params.size() > 2)
615         throw runtime_error(
616             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
617             "[minconf] is the minimum number of confirmations before payments are included.\n"
618             "[includeempty] whether to include addresses that haven't received any payments.\n"
619             "Returns an array of objects containing:\n"
620             "  \"address\" : receiving address\n"
621             "  \"label\" : the label of the receiving address\n"
622             "  \"amount\" : total amount received by the address\n"
623             "  \"confirmations\" : number of confirmations of the most recent transaction included");
624
625     return ListReceived(params, false);
626 }
627
628 Value listreceivedbylabel(const Array& params, bool fHelp)
629 {
630     if (fHelp || params.size() > 2)
631         throw runtime_error(
632             "listreceivedbylabel [minconf=1] [includeempty=false]\n"
633             "[minconf] is the minimum number of confirmations before payments are included.\n"
634             "[includeempty] whether to include labels that haven't received any payments.\n"
635             "Returns an array of objects containing:\n"
636             "  \"label\" : the label of the receiving addresses\n"
637             "  \"amount\" : total amount received by addresses with this label\n"
638             "  \"confirmations\" : number of confirmations of the most recent transaction included");
639
640     return ListReceived(params, true);
641 }
642
643
644 Value backupwallet(const Array& params, bool fHelp)
645 {
646     if (fHelp || params.size() != 1)
647         throw runtime_error(
648             "backupwallet <destination>\n"
649             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
650
651     string strDest = params[0].get_str();
652     BackupWallet(strDest);
653
654     return Value::null;
655 }
656
657
658
659
660
661
662
663
664
665
666
667
668
669 //
670 // Call Table
671 //
672
673 pair<string, rpcfn_type> pCallTable[] =
674 {
675     make_pair("help",                  &help),
676     make_pair("stop",                  &stop),
677     make_pair("getblockcount",         &getblockcount),
678     make_pair("getblocknumber",        &getblocknumber),
679     make_pair("getconnectioncount",    &getconnectioncount),
680     make_pair("getdifficulty",         &getdifficulty),
681     make_pair("getbalance",            &getbalance),
682     make_pair("getgenerate",           &getgenerate),
683     make_pair("setgenerate",           &setgenerate),
684     make_pair("gethashespersec",       &gethashespersec),
685     make_pair("getinfo",               &getinfo),
686     make_pair("getnewaddress",         &getnewaddress),
687     make_pair("setlabel",              &setlabel),
688     make_pair("getlabel",              &getlabel),
689     make_pair("getaddressesbylabel",   &getaddressesbylabel),
690     make_pair("sendtoaddress",         &sendtoaddress),
691     make_pair("getamountreceived",     &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
692     make_pair("getallreceived",        &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
693     make_pair("getreceivedbyaddress",  &getreceivedbyaddress),
694     make_pair("getreceivedbylabel",    &getreceivedbylabel),
695     make_pair("listreceivedbyaddress", &listreceivedbyaddress),
696     make_pair("listreceivedbylabel",   &listreceivedbylabel),
697     make_pair("backupwallet",          &backupwallet),
698 };
699 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
700
701 string pAllowInSafeMode[] =
702 {
703     "help",
704     "stop",
705     "getblockcount",
706     "getblocknumber",
707     "getconnectioncount",
708     "getdifficulty",
709     "getgenerate",
710     "setgenerate",
711     "gethashespersec",
712     "getinfo",
713     "getnewaddress",
714     "setlabel",
715     "getlabel",
716     "getaddressesbylabel",
717     "backupwallet",
718 };
719 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
720
721
722
723
724 //
725 // HTTP protocol
726 //
727 // This ain't Apache.  We're just using HTTP header for the length field
728 // and to be compatible with other JSON-RPC implementations.
729 //
730
731 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
732 {
733     ostringstream s;
734     s << "POST / HTTP/1.1\r\n"
735       << "User-Agent: json-rpc/1.0\r\n"
736       << "Host: 127.0.0.1\r\n"
737       << "Content-Type: application/json\r\n"
738       << "Content-Length: " << strMsg.size() << "\r\n"
739       << "Accept: application/json\r\n";
740     foreach(const PAIRTYPE(string, string)& item, mapRequestHeaders)
741         s << item.first << ": " << item.second << "\r\n";
742     s << "\r\n" << strMsg;
743
744     return s.str();
745 }
746
747 string HTTPReply(int nStatus, const string& strMsg)
748 {
749     if (nStatus == 401)
750         return "HTTP/1.0 401 Authorization Required\r\n"
751             "Server: HTTPd/1.0\r\n"
752             "Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"
753             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
754             "Content-Type: text/html\r\n"
755             "Content-Length: 311\r\n"
756             "\r\n"
757             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
758             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
759             "<HTML>\r\n"
760             "<HEAD>\r\n"
761             "<TITLE>Error</TITLE>\r\n"
762             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
763             "</HEAD>\r\n"
764             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
765             "</HTML>\r\n";
766     string strStatus;
767          if (nStatus == 200) strStatus = "OK";
768     else if (nStatus == 400) strStatus = "Bad Request";
769     else if (nStatus == 404) strStatus = "Not Found";
770     else if (nStatus == 500) strStatus = "Internal Server Error";
771     return strprintf(
772             "HTTP/1.1 %d %s\r\n"
773             "Connection: close\r\n"
774             "Content-Length: %d\r\n"
775             "Content-Type: application/json\r\n"
776             "Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"
777             "Server: json-rpc/1.0\r\n"
778             "\r\n"
779             "%s",
780         nStatus,
781         strStatus.c_str(),
782         strMsg.size(),
783         strMsg.c_str());
784 }
785
786 int ReadHTTPStatus(std::basic_istream<char>& stream)
787 {
788     string str;
789     getline(stream, str);
790     vector<string> vWords;
791     boost::split(vWords, str, boost::is_any_of(" "));
792     if (vWords.size() < 2)
793         return 500;
794     return atoi(vWords[1].c_str());
795 }
796
797 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
798 {
799     int nLen = 0;
800     loop
801     {
802         string str;
803         std::getline(stream, str);
804         if (str.empty() || str == "\r")
805             break;
806         string::size_type nColon = str.find(":");
807         if (nColon != string::npos)
808         {
809             string strHeader = str.substr(0, nColon);
810             boost::trim(strHeader);
811             string strValue = str.substr(nColon+1);
812             boost::trim(strValue);
813             mapHeadersRet[strHeader] = strValue;
814             if (strHeader == "Content-Length")
815                 nLen = atoi(strValue.c_str());
816         }
817     }
818     return nLen;
819 }
820
821 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
822 {
823     mapHeadersRet.clear();
824     strMessageRet = "";
825
826     // Read status
827     int nStatus = ReadHTTPStatus(stream);
828
829     // Read header
830     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
831     if (nLen < 0 || nLen > MAX_SIZE)
832         return 500;
833
834     // Read message
835     if (nLen > 0)
836     {
837         vector<char> vch(nLen);
838         stream.read(&vch[0], nLen);
839         strMessageRet = string(vch.begin(), vch.end());
840     }
841
842     return nStatus;
843 }
844
845 string EncodeBase64(string s)
846 {
847     BIO *b64, *bmem;
848     BUF_MEM *bptr;
849
850     b64 = BIO_new(BIO_f_base64());
851     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
852     bmem = BIO_new(BIO_s_mem());
853     b64 = BIO_push(b64, bmem);
854     BIO_write(b64, s.c_str(), s.size());
855     BIO_flush(b64);
856     BIO_get_mem_ptr(b64, &bptr);
857
858     string result(bptr->data, bptr->length);
859     BIO_free_all(b64);
860
861     return result;
862 }
863
864 string DecodeBase64(string s)
865 {
866     BIO *b64, *bmem;
867
868     char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
869
870     b64 = BIO_new(BIO_f_base64());
871     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
872     bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
873     bmem = BIO_push(b64, bmem);
874     BIO_read(bmem, buffer, s.size());
875     BIO_free_all(bmem);
876
877     string result(buffer);
878     free(buffer);
879     return result;
880 }
881
882 bool HTTPAuthorized(map<string, string>& mapHeaders)
883 {
884     string strAuth = mapHeaders["Authorization"];
885     if (strAuth.substr(0,6) != "Basic ")
886         return false;
887     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
888     string strUserPass = DecodeBase64(strUserPass64);
889     string::size_type nColon = strUserPass.find(":");
890     if (nColon == string::npos)
891         return false;
892     string strUser = strUserPass.substr(0, nColon);
893     string strPassword = strUserPass.substr(nColon+1);
894     return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
895 }
896
897 //
898 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
899 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
900 // unspecified (HTTP errors and contents of 'error').
901 //
902 // 1.0 spec: http://json-rpc.org/wiki/specification
903 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
904 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
905 //
906
907 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
908 {
909     Object request;
910     request.push_back(Pair("method", strMethod));
911     request.push_back(Pair("params", params));
912     request.push_back(Pair("id", id));
913     return write_string(Value(request), false) + "\n";
914 }
915
916 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
917 {
918     Object reply;
919     if (error.type() != null_type)
920         reply.push_back(Pair("result", Value::null));
921     else
922         reply.push_back(Pair("result", result));
923     reply.push_back(Pair("error", error));
924     reply.push_back(Pair("id", id));
925     return write_string(Value(reply), false) + "\n";
926 }
927
928 bool ClientAllowed(const string& strAddress)
929 {
930     if (strAddress == asio::ip::address_v4::loopback().to_string())
931         return true;
932     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
933     foreach(string strAllow, vAllow)
934         if (WildcardMatch(strAddress, strAllow))
935             return true;
936     return false;
937 }
938
939 #ifdef USE_SSL
940 //
941 // IOStream device that speaks SSL but can also speak non-SSL
942 //
943 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
944 public:
945     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
946     {
947         fUseSSL = fUseSSLIn;
948         fNeedHandshake = fUseSSLIn;
949     }
950
951     void handshake(ssl::stream_base::handshake_type role)
952     {
953         if (!fNeedHandshake) return;
954         fNeedHandshake = false;
955         stream.handshake(role);
956     }
957     std::streamsize read(char* s, std::streamsize n)
958     {
959         handshake(ssl::stream_base::server); // HTTPS servers read first
960         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
961         return stream.next_layer().read_some(asio::buffer(s, n));
962     }
963     std::streamsize write(const char* s, std::streamsize n)
964     {
965         handshake(ssl::stream_base::client); // HTTPS clients write first
966         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
967         return asio::write(stream.next_layer(), asio::buffer(s, n));
968     }
969     bool connect(const std::string& server, const std::string& port)
970     {
971         ip::tcp::resolver resolver(stream.get_io_service());
972         ip::tcp::resolver::query query(server.c_str(), port.c_str());
973         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
974         ip::tcp::resolver::iterator end;
975         boost::system::error_code error = asio::error::host_not_found;
976         while (error && endpoint_iterator != end)
977         {
978             stream.lowest_layer().close();
979             stream.lowest_layer().connect(*endpoint_iterator++, error);
980         }
981         if (error)
982             return false;
983         return true;
984     }
985
986 private:
987     bool fNeedHandshake;
988     bool fUseSSL;
989     SSLStream& stream;
990 };
991 #endif
992
993 void ThreadRPCServer(void* parg)
994 {
995     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
996     try
997     {
998         vnThreadsRunning[4]++;
999         ThreadRPCServer2(parg);
1000         vnThreadsRunning[4]--;
1001     }
1002     catch (std::exception& e) {
1003         vnThreadsRunning[4]--;
1004         PrintException(&e, "ThreadRPCServer()");
1005     } catch (...) {
1006         vnThreadsRunning[4]--;
1007         PrintException(NULL, "ThreadRPCServer()");
1008     }
1009     printf("ThreadRPCServer exiting\n");
1010 }
1011
1012 void ThreadRPCServer2(void* parg)
1013 {
1014     printf("ThreadRPCServer started\n");
1015
1016     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1017     {
1018         string strWhatAmI = "To use bitcoind";
1019         if (mapArgs.count("-server"))
1020             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
1021         else if (mapArgs.count("-daemon"))
1022             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
1023         PrintConsole(
1024             _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
1025               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
1026                 strWhatAmI.c_str(),
1027                 GetConfigFile().c_str());
1028         CreateThread(Shutdown, NULL);
1029         return;
1030     }
1031
1032     bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
1033     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
1034
1035     asio::io_service io_service;
1036     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
1037     ip::tcp::acceptor acceptor(io_service, endpoint);
1038
1039 #ifdef USE_SSL
1040     ssl::context context(io_service, ssl::context::sslv23);
1041     if (fUseSSL)
1042     {
1043         context.set_options(ssl::context::no_sslv2);
1044         filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
1045         if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
1046         if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
1047         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
1048         filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
1049         if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
1050         if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
1051         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
1052
1053         string ciphers = GetArg("-rpcsslciphers",
1054                                          "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
1055         SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
1056     }
1057 #else
1058     if (fUseSSL)
1059         throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
1060 #endif
1061
1062     loop
1063     {
1064         // Accept connection
1065 #ifdef USE_SSL
1066         SSLStream sslStream(io_service, context);
1067         SSLIOStreamDevice d(sslStream, fUseSSL);
1068         iostreams::stream<SSLIOStreamDevice> stream(d);
1069 #else
1070         ip::tcp::iostream stream;
1071 #endif
1072
1073         ip::tcp::endpoint peer;
1074         vnThreadsRunning[4]--;
1075 #ifdef USE_SSL
1076         acceptor.accept(sslStream.lowest_layer(), peer);
1077 #else
1078         acceptor.accept(*stream.rdbuf(), peer);
1079 #endif
1080         vnThreadsRunning[4]++;
1081         if (fShutdown)
1082             return;
1083
1084         // Restrict callers by IP
1085         if (!ClientAllowed(peer.address().to_string()))
1086             continue;
1087
1088         // Receive request
1089         map<string, string> mapHeaders;
1090         string strRequest;
1091         ReadHTTP(stream, mapHeaders, strRequest);
1092
1093         // Check authorization
1094         if (mapHeaders.count("Authorization") == 0)
1095         {
1096             stream << HTTPReply(401, "") << std::flush;
1097             continue;
1098         }
1099         if (!HTTPAuthorized(mapHeaders))
1100         {
1101             // Deter brute-forcing short passwords
1102             if (mapArgs["-rpcpassword"].size() < 15)
1103                 Sleep(50);
1104
1105             stream << HTTPReply(401, "") << std::flush;
1106             printf("ThreadRPCServer incorrect password attempt\n");
1107             continue;
1108         }
1109
1110         Value id = Value::null;
1111         try
1112         {
1113             // Parse request
1114             Value valRequest;
1115             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
1116                 throw JSONRPCError(-32700, "Parse error");
1117             const Object& request = valRequest.get_obj();
1118
1119             // Parse id now so errors from here on will have the id
1120             id = find_value(request, "id");
1121
1122             // Parse method
1123             Value valMethod = find_value(request, "method");
1124             if (valMethod.type() == null_type)
1125                 throw JSONRPCError(-32600, "Missing method");
1126             if (valMethod.type() != str_type)
1127                 throw JSONRPCError(-32600, "Method must be a string");
1128             string strMethod = valMethod.get_str();
1129             printf("ThreadRPCServer method=%s\n", strMethod.c_str());
1130
1131             // Parse params
1132             Value valParams = find_value(request, "params");
1133             Array params;
1134             if (valParams.type() == array_type)
1135                 params = valParams.get_array();
1136             else if (valParams.type() == null_type)
1137                 params = Array();
1138             else
1139                 throw JSONRPCError(-32600, "Params must be an array");
1140
1141             // Find method
1142             map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
1143             if (mi == mapCallTable.end())
1144                 throw JSONRPCError(-32601, "Method not found");
1145
1146             // Observe safe mode
1147             string strWarning = GetWarnings("rpc");
1148             if (strWarning != "" && !mapArgs.count("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
1149                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
1150
1151             try
1152             {
1153                 // Execute
1154                 Value result = (*(*mi).second)(params, false);
1155
1156                 // Send reply
1157                 string strReply = JSONRPCReply(result, Value::null, id);
1158                 stream << HTTPReply(200, strReply) << std::flush;
1159             }
1160             catch (std::exception& e)
1161             {
1162                 // Send error reply from method
1163                 string strReply = JSONRPCReply(Value::null, JSONRPCError(-1, e.what()), id);
1164                 stream << HTTPReply(500, strReply) << std::flush;
1165             }
1166         }
1167         catch (Object& objError)
1168         {
1169             // Send error reply from json-rpc error object
1170             int nStatus = 500;
1171             int code = find_value(objError, "code").get_int();
1172             if (code == -32600) nStatus = 400;
1173             else if (code == -32601) nStatus = 404;
1174             string strReply = JSONRPCReply(Value::null, objError, id);
1175             stream << HTTPReply(nStatus, strReply) << std::flush;
1176         }
1177         catch (std::exception& e)
1178         {
1179             // Send error reply from other json-rpc parsing errors
1180             string strReply = JSONRPCReply(Value::null, JSONRPCError(-32700, e.what()), id);
1181             stream << HTTPReply(500, strReply) << std::flush;
1182         }
1183     }
1184 }
1185
1186
1187
1188
1189 Object CallRPC(const string& strMethod, const Array& params)
1190 {
1191     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1192         throw runtime_error(strprintf(
1193             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
1194               "If the file does not exist, create it with owner-readable-only file permissions."),
1195                 GetConfigFile().c_str()));
1196
1197     // Connect to localhost
1198     bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
1199 #ifdef USE_SSL
1200     asio::io_service io_service;
1201     ssl::context context(io_service, ssl::context::sslv23);
1202     context.set_options(ssl::context::no_sslv2);
1203     SSLStream sslStream(io_service, context);
1204     SSLIOStreamDevice d(sslStream, fUseSSL);
1205     iostreams::stream<SSLIOStreamDevice> stream(d);
1206     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
1207         throw runtime_error("couldn't connect to server");
1208 #else
1209     if (fUseSSL)
1210         throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
1211
1212     ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
1213     if (stream.fail())
1214         throw runtime_error("couldn't connect to server");
1215 #endif
1216
1217
1218     // HTTP basic authentication
1219     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
1220     map<string, string> mapRequestHeaders;
1221     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
1222
1223     // Send request
1224     string strRequest = JSONRPCRequest(strMethod, params, 1);
1225     string strPost = HTTPPost(strRequest, mapRequestHeaders);
1226     stream << strPost << std::flush;
1227
1228     // Receive reply
1229     map<string, string> mapHeaders;
1230     string strReply;
1231     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
1232     if (nStatus == 401)
1233         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
1234     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
1235         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
1236     else if (strReply.empty())
1237         throw runtime_error("no response from server");
1238
1239     // Parse reply
1240     Value valReply;
1241     if (!read_string(strReply, valReply))
1242         throw runtime_error("couldn't parse reply from server");
1243     const Object& reply = valReply.get_obj();
1244     if (reply.empty())
1245         throw runtime_error("expected reply to have result, error and id properties");
1246
1247     return reply;
1248 }
1249
1250
1251
1252
1253 template<typename T>
1254 void ConvertTo(Value& value)
1255 {
1256     if (value.type() == str_type)
1257     {
1258         // reinterpret string as unquoted json value
1259         Value value2;
1260         if (!read_string(value.get_str(), value2))
1261             throw runtime_error("type mismatch");
1262         value = value2.get_value<T>();
1263     }
1264     else
1265     {
1266         value = value.get_value<T>();
1267     }
1268 }
1269
1270 int CommandLineRPC(int argc, char *argv[])
1271 {
1272     string strPrint;
1273     int nRet = 0;
1274     try
1275     {
1276         // Skip switches
1277         while (argc > 1 && IsSwitchChar(argv[1][0]))
1278         {
1279             argc--;
1280             argv++;
1281         }
1282
1283         // Method
1284         if (argc < 2)
1285             throw runtime_error("too few parameters");
1286         string strMethod = argv[1];
1287
1288         // Parameters default to strings
1289         Array params;
1290         for (int i = 2; i < argc; i++)
1291             params.push_back(argv[i]);
1292         int n = params.size();
1293
1294         //
1295         // Special case non-string parameter types
1296         //
1297         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
1298         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
1299         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
1300         if (strMethod == "listtransactions"       && n > 0) ConvertTo<boost::int64_t>(params[0]);
1301         if (strMethod == "listtransactions"       && n > 1) ConvertTo<bool>(params[1]);
1302         if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
1303         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
1304         if (strMethod == "getreceivedbylabel"     && n > 1) ConvertTo<boost::int64_t>(params[1]);
1305         if (strMethod == "getallreceived"         && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
1306         if (strMethod == "getallreceived"         && n > 1) ConvertTo<bool>(params[1]);
1307         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
1308         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
1309         if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]);
1310         if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]);
1311
1312         // Execute
1313         Object reply = CallRPC(strMethod, params);
1314
1315         // Parse reply
1316         const Value& result = find_value(reply, "result");
1317         const Value& error  = find_value(reply, "error");
1318         const Value& id     = find_value(reply, "id");
1319
1320         if (error.type() != null_type)
1321         {
1322             // Error
1323             strPrint = "error: " + write_string(error, false);
1324             int code = find_value(error.get_obj(), "code").get_int();
1325             nRet = abs(code);
1326         }
1327         else
1328         {
1329             // Result
1330             if (result.type() == null_type)
1331                 strPrint = "";
1332             else if (result.type() == str_type)
1333                 strPrint = result.get_str();
1334             else
1335                 strPrint = write_string(result, true);
1336         }
1337     }
1338     catch (std::exception& e)
1339     {
1340         strPrint = string("error: ") + e.what();
1341         nRet = 87;
1342     }
1343     catch (...)
1344     {
1345         PrintException(NULL, "CommandLineRPC()");
1346     }
1347
1348     if (strPrint != "")
1349     {
1350 #if defined(__WXMSW__) && defined(GUI)
1351         // Windows GUI apps can't print to command line,
1352         // so settle for a message box yuck
1353         MyMessageBox(strPrint, "Bitcoin", wxOK);
1354 #else
1355         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
1356 #endif
1357     }
1358     return nRet;
1359 }
1360
1361
1362
1363
1364 #ifdef TEST
1365 int main(int argc, char *argv[])
1366 {
1367 #ifdef _MSC_VER
1368     // Turn off microsoft heap dump noise
1369     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1370     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
1371 #endif
1372     setbuf(stdin, NULL);
1373     setbuf(stdout, NULL);
1374     setbuf(stderr, NULL);
1375
1376     try
1377     {
1378         if (argc >= 2 && string(argv[1]) == "-server")
1379         {
1380             printf("server ready\n");
1381             ThreadRPCServer(NULL);
1382         }
1383         else
1384         {
1385             return CommandLineRPC(argc, argv);
1386         }
1387     }
1388     catch (std::exception& e) {
1389         PrintException(&e, "main()");
1390     } catch (...) {
1391         PrintException(NULL, "main()");
1392     }
1393     return 0;
1394 }
1395 #endif