Mercurial > hg > bitcoin
annotate rpc.cpp @ 244:bf38622eb0b9 draft
blocks-1,
verify block chain on load, so wouldn't have needed to delete blk*.dat, it would have done a reorg automatically
author | Satoshi Nakamoto <satoshin@gmx.com> |
---|---|
date | Mon, 16 Aug 2010 20:53:49 +0000 |
parents | 96105e347f4a |
children | 41628b8a75b9 |
rev | line source |
---|---|
174 | 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 "json/json_spirit_reader_template.h" | |
9 #include "json/json_spirit_writer_template.h" | |
10 #include "json/json_spirit_utils.h" | |
11 #define printf OutputDebugStringF | |
12 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are | |
13 // precompiled in headers.h. The problem might be when the pch file goes over | |
14 // a certain size around 145MB. If we need access to json_spirit outside this | |
15 // file, we could use the compiled json_spirit option. | |
16 | |
17 using boost::asio::ip::tcp; | |
18 using namespace json_spirit; | |
19 | |
20 void ThreadRPCServer2(void* parg); | |
21 typedef Value(*rpcfn_type)(const Array& params, bool fHelp); | |
22 extern map<string, rpcfn_type> mapCallTable; | |
23 | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
24 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
25 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
26 void PrintConsole(const char* format, ...) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
27 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
28 char buffer[50000]; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
29 int limit = sizeof(buffer); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
30 va_list arg_ptr; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
31 va_start(arg_ptr, format); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
32 int ret = _vsnprintf(buffer, limit, format, arg_ptr); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
33 va_end(arg_ptr); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
34 if (ret < 0 || ret >= limit) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
35 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
36 ret = limit - 1; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
37 buffer[limit-1] = 0; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
38 } |
183
5447d5ff8a3c
bitcoind now compiles without wxWidgets or wxBase
Satoshi Nakamoto <satoshin@gmx.com>
parents:
182
diff
changeset
|
39 #if defined(__WXMSW__) && defined(GUI) |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
40 MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
41 #else |
181
99851818e5b7
Gavin Andresen's JSON-RPC HTTP authentication,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
180
diff
changeset
|
42 fprintf(stdout, "%s", buffer); |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
43 #endif |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
44 } |
179
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
45 |
174 | 46 |
47 | |
48 | |
49 | |
50 | |
51 | |
52 /// | |
53 /// Note: This interface may still be subject to change. | |
54 /// | |
55 | |
56 | |
57 Value help(const Array& params, bool fHelp) | |
58 { | |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
59 if (fHelp || params.size() > 1) |
174 | 60 throw runtime_error( |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
61 "help [command]\n" |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
62 "List commands, or get help for a command."); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
63 |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
64 string strCommand; |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
65 if (params.size() > 0) |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
66 strCommand = params[0].get_str(); |
174 | 67 |
68 string strRet; | |
179
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
69 set<rpcfn_type> setDone; |
174 | 70 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi) |
71 { | |
179
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
72 string strMethod = (*mi).first; |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
73 // We already filter duplicates, but these deprecated screw up the sort order |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
74 if (strMethod == "getamountreceived" || |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
75 strMethod == "getallreceived") |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
76 continue; |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
77 if (strCommand != "" && strMethod != strCommand) |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
78 continue; |
174 | 79 try |
80 { | |
81 Array params; | |
179
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
82 rpcfn_type pfn = (*mi).second; |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
83 if (setDone.insert(pfn).second) |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
84 (*pfn)(params, true); |
174 | 85 } |
86 catch (std::exception& e) | |
87 { | |
88 // Help text is returned in an exception | |
89 string strHelp = string(e.what()); | |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
90 if (strCommand == "") |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
91 if (strHelp.find('\n') != -1) |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
92 strHelp = strHelp.substr(0, strHelp.find('\n')); |
174 | 93 strRet += strHelp + "\n"; |
94 } | |
95 } | |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
96 if (strRet == "") |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
97 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str()); |
174 | 98 strRet = strRet.substr(0,strRet.size()-1); |
99 return strRet; | |
100 } | |
101 | |
102 | |
103 Value stop(const Array& params, bool fHelp) | |
104 { | |
105 if (fHelp || params.size() != 0) | |
106 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
107 "stop\n" |
174 | 108 "Stop bitcoin server."); |
109 | |
110 // Shutdown will take long enough that the response should get back | |
111 CreateThread(Shutdown, NULL); | |
112 return "bitcoin server stopping"; | |
113 } | |
114 | |
115 | |
116 Value getblockcount(const Array& params, bool fHelp) | |
117 { | |
118 if (fHelp || params.size() != 0) | |
119 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
120 "getblockcount\n" |
174 | 121 "Returns the number of blocks in the longest block chain."); |
122 | |
244 | 123 return nBestHeight; |
174 | 124 } |
125 | |
126 | |
127 Value getblocknumber(const Array& params, bool fHelp) | |
128 { | |
129 if (fHelp || params.size() != 0) | |
130 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
131 "getblocknumber\n" |
174 | 132 "Returns the block number of the latest block in the longest block chain."); |
133 | |
134 return nBestHeight; | |
135 } | |
136 | |
137 | |
138 Value getconnectioncount(const Array& params, bool fHelp) | |
139 { | |
140 if (fHelp || params.size() != 0) | |
141 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
142 "getconnectioncount\n" |
174 | 143 "Returns the number of connections to other nodes."); |
144 | |
145 return (int)vNodes.size(); | |
146 } | |
147 | |
148 | |
149 double GetDifficulty() | |
150 { | |
151 // Floating point number that is a multiple of the minimum difficulty, | |
152 // minimum difficulty = 1.0. | |
153 if (pindexBest == NULL) | |
154 return 1.0; | |
155 int nShift = 256 - 32 - 31; // to fit in a uint | |
156 double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint(); | |
157 double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint(); | |
158 return dMinimum / dCurrently; | |
159 } | |
160 | |
161 Value getdifficulty(const Array& params, bool fHelp) | |
162 { | |
163 if (fHelp || params.size() != 0) | |
164 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
165 "getdifficulty\n" |
174 | 166 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty."); |
167 | |
168 return GetDifficulty(); | |
169 } | |
170 | |
171 | |
172 Value getbalance(const Array& params, bool fHelp) | |
173 { | |
174 if (fHelp || params.size() != 0) | |
175 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
176 "getbalance\n" |
174 | 177 "Returns the server's available balance."); |
178 | |
179 return ((double)GetBalance() / (double)COIN); | |
180 } | |
181 | |
182 | |
183 Value getgenerate(const Array& params, bool fHelp) | |
184 { | |
185 if (fHelp || params.size() != 0) | |
186 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
187 "getgenerate\n" |
174 | 188 "Returns true or false."); |
189 | |
190 return (bool)fGenerateBitcoins; | |
191 } | |
192 | |
193 | |
194 Value setgenerate(const Array& params, bool fHelp) | |
195 { | |
196 if (fHelp || params.size() < 1 || params.size() > 2) | |
197 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
198 "setgenerate <generate> [genproclimit]\n" |
174 | 199 "<generate> is true or false to turn generation on or off.\n" |
200 "Generation is limited to [genproclimit] processors, -1 is unlimited."); | |
201 | |
202 bool fGenerate = true; | |
203 if (params.size() > 0) | |
204 fGenerate = params[0].get_bool(); | |
205 | |
206 if (params.size() > 1) | |
207 { | |
208 int nGenProcLimit = params[1].get_int(); | |
209 fLimitProcessors = (nGenProcLimit != -1); | |
210 CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors); | |
211 if (nGenProcLimit != -1) | |
212 CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); | |
213 } | |
214 | |
215 GenerateBitcoins(fGenerate); | |
216 return Value::null; | |
217 } | |
218 | |
219 | |
234
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
220 Value gethashespersec(const Array& params, bool fHelp) |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
221 { |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
222 if (fHelp || params.size() != 0) |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
223 throw runtime_error( |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
224 "gethashespersec\n" |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
225 "Returns a recent hashes per second performance measurement while generating."); |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
226 |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
227 if (GetTimeMillis() - nHPSTimerStart > 8000) |
236
df45df86d5c1
fix build, thanks jgarzik
Satoshi Nakamoto <satoshin@gmx.com>
parents:
234
diff
changeset
|
228 return (boost::int64_t)0; |
df45df86d5c1
fix build, thanks jgarzik
Satoshi Nakamoto <satoshin@gmx.com>
parents:
234
diff
changeset
|
229 return (boost::int64_t)dHashesPerSec; |
234
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
230 } |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
231 |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
232 |
174 | 233 Value getinfo(const Array& params, bool fHelp) |
234 { | |
235 if (fHelp || params.size() != 0) | |
236 throw runtime_error( | |
234
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
237 "getinfo\n" |
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
238 "Returns an object containing various state info."); |
174 | 239 |
240 Object obj; | |
234
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
241 obj.push_back(Pair("version", (int)VERSION)); |
174 | 242 obj.push_back(Pair("balance", (double)GetBalance() / (double)COIN)); |
244 | 243 obj.push_back(Pair("blocks", (int)nBestHeight)); |
174 | 244 obj.push_back(Pair("connections", (int)vNodes.size())); |
245 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string()))); | |
246 obj.push_back(Pair("generate", (bool)fGenerateBitcoins)); | |
247 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1))); | |
248 obj.push_back(Pair("difficulty", (double)GetDifficulty())); | |
234
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
249 obj.push_back(Pair("hashespersec", gethashespersec(params, false))); |
174 | 250 return obj; |
251 } | |
252 | |
253 | |
254 Value getnewaddress(const Array& params, bool fHelp) | |
255 { | |
256 if (fHelp || params.size() > 1) | |
257 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
258 "getnewaddress [label]\n" |
174 | 259 "Returns a new bitcoin address for receiving payments. " |
260 "If [label] is specified (recommended), it is added to the address book " | |
261 "so payments received with the address will be labeled."); | |
262 | |
263 // Parse the label first so we don't generate a key if there's an error | |
264 string strLabel; | |
265 if (params.size() > 0) | |
266 strLabel = params[0].get_str(); | |
267 | |
268 // Generate a new key that is added to wallet | |
269 string strAddress = PubKeyToAddress(GenerateNewKey()); | |
270 | |
271 SetAddressBookName(strAddress, strLabel); | |
272 return strAddress; | |
273 } | |
274 | |
275 | |
276 Value setlabel(const Array& params, bool fHelp) | |
277 { | |
278 if (fHelp || params.size() < 1 || params.size() > 2) | |
279 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
280 "setlabel <bitcoinaddress> <label>\n" |
174 | 281 "Sets the label associated with the given address."); |
282 | |
283 string strAddress = params[0].get_str(); | |
284 string strLabel; | |
285 if (params.size() > 1) | |
286 strLabel = params[1].get_str(); | |
287 | |
288 SetAddressBookName(strAddress, strLabel); | |
289 return Value::null; | |
290 } | |
291 | |
292 | |
293 Value getlabel(const Array& params, bool fHelp) | |
294 { | |
295 if (fHelp || params.size() != 1) | |
296 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
297 "getlabel <bitcoinaddress>\n" |
174 | 298 "Returns the label associated with the given address."); |
299 | |
300 string strAddress = params[0].get_str(); | |
301 | |
302 string strLabel; | |
303 CRITICAL_BLOCK(cs_mapAddressBook) | |
304 { | |
305 map<string, string>::iterator mi = mapAddressBook.find(strAddress); | |
306 if (mi != mapAddressBook.end() && !(*mi).second.empty()) | |
307 strLabel = (*mi).second; | |
308 } | |
309 return strLabel; | |
310 } | |
311 | |
312 | |
313 Value getaddressesbylabel(const Array& params, bool fHelp) | |
314 { | |
315 if (fHelp || params.size() != 1) | |
316 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
317 "getaddressesbylabel <label>\n" |
174 | 318 "Returns the list of addresses with the given label."); |
319 | |
320 string strLabel = params[0].get_str(); | |
321 | |
322 // Find all addresses that have the given label | |
323 Array ret; | |
324 CRITICAL_BLOCK(cs_mapAddressBook) | |
325 { | |
326 foreach(const PAIRTYPE(string, string)& item, mapAddressBook) | |
327 { | |
328 const string& strAddress = item.first; | |
329 const string& strName = item.second; | |
330 if (strName == strLabel) | |
331 { | |
332 // We're only adding valid bitcoin addresses and not ip addresses | |
333 CScript scriptPubKey; | |
334 if (scriptPubKey.SetBitcoinAddress(strAddress)) | |
335 ret.push_back(strAddress); | |
336 } | |
337 } | |
338 } | |
339 return ret; | |
340 } | |
341 | |
342 | |
343 Value sendtoaddress(const Array& params, bool fHelp) | |
344 { | |
345 if (fHelp || params.size() < 2 || params.size() > 4) | |
346 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
347 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n" |
174 | 348 "<amount> is a real and is rounded to the nearest 0.01"); |
349 | |
350 string strAddress = params[0].get_str(); | |
351 | |
352 // Amount | |
353 if (params[1].get_real() <= 0.0 || params[1].get_real() > 21000000.0) | |
354 throw runtime_error("Invalid amount"); | |
355 int64 nAmount = roundint64(params[1].get_real() * 100.00) * CENT; | |
356 | |
357 // Wallet comments | |
358 CWalletTx wtx; | |
359 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) | |
360 wtx.mapValue["message"] = params[2].get_str(); | |
361 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) | |
362 wtx.mapValue["to"] = params[3].get_str(); | |
363 | |
364 string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); | |
365 if (strError != "") | |
366 throw runtime_error(strError); | |
367 return "sent"; | |
368 } | |
369 | |
370 | |
371 Value listtransactions(const Array& params, bool fHelp) | |
372 { | |
373 if (fHelp || params.size() > 2) | |
374 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
375 "listtransactions [count=10] [includegenerated=false]\n" |
174 | 376 "Returns up to [count] most recent transactions."); |
377 | |
378 int64 nCount = 10; | |
379 if (params.size() > 0) | |
380 nCount = params[0].get_int64(); | |
381 bool fGenerated = false; | |
382 if (params.size() > 1) | |
383 fGenerated = params[1].get_bool(); | |
384 | |
385 Array ret; | |
386 //// not finished | |
387 ret.push_back("not implemented yet"); | |
388 return ret; | |
389 } | |
390 | |
391 | |
392 Value getreceivedbyaddress(const Array& params, bool fHelp) | |
393 { | |
394 if (fHelp || params.size() < 1 || params.size() > 2) | |
395 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
396 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n" |
174 | 397 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations."); |
398 | |
399 // Bitcoin address | |
400 string strAddress = params[0].get_str(); | |
401 CScript scriptPubKey; | |
402 if (!scriptPubKey.SetBitcoinAddress(strAddress)) | |
403 throw runtime_error("Invalid bitcoin address"); | |
404 if (!IsMine(scriptPubKey)) | |
405 return (double)0.0; | |
406 | |
407 // Minimum confirmations | |
408 int nMinDepth = 1; | |
409 if (params.size() > 1) | |
410 nMinDepth = params[1].get_int(); | |
411 | |
412 // Tally | |
413 int64 nAmount = 0; | |
414 CRITICAL_BLOCK(cs_mapWallet) | |
415 { | |
416 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) | |
417 { | |
418 const CWalletTx& wtx = (*it).second; | |
419 if (wtx.IsCoinBase() || !wtx.IsFinal()) | |
420 continue; | |
421 | |
422 foreach(const CTxOut& txout, wtx.vout) | |
423 if (txout.scriptPubKey == scriptPubKey) | |
424 if (wtx.GetDepthInMainChain() >= nMinDepth) | |
425 nAmount += txout.nValue; | |
426 } | |
427 } | |
428 | |
429 return (double)nAmount / (double)COIN; | |
430 } | |
431 | |
432 | |
433 Value getreceivedbylabel(const Array& params, bool fHelp) | |
434 { | |
435 if (fHelp || params.size() < 1 || params.size() > 2) | |
436 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
437 "getreceivedbylabel <label> [minconf=1]\n" |
174 | 438 "Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations."); |
439 | |
440 // Get the set of pub keys that have the label | |
441 string strLabel = params[0].get_str(); | |
442 set<CScript> setPubKey; | |
443 CRITICAL_BLOCK(cs_mapAddressBook) | |
444 { | |
445 foreach(const PAIRTYPE(string, string)& item, mapAddressBook) | |
446 { | |
447 const string& strAddress = item.first; | |
448 const string& strName = item.second; | |
449 if (strName == strLabel) | |
450 { | |
451 // We're only counting our own valid bitcoin addresses and not ip addresses | |
452 CScript scriptPubKey; | |
453 if (scriptPubKey.SetBitcoinAddress(strAddress)) | |
454 if (IsMine(scriptPubKey)) | |
455 setPubKey.insert(scriptPubKey); | |
456 } | |
457 } | |
458 } | |
459 | |
460 // Minimum confirmations | |
461 int nMinDepth = 1; | |
462 if (params.size() > 1) | |
463 nMinDepth = params[1].get_int(); | |
464 | |
465 // Tally | |
466 int64 nAmount = 0; | |
467 CRITICAL_BLOCK(cs_mapWallet) | |
468 { | |
469 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) | |
470 { | |
471 const CWalletTx& wtx = (*it).second; | |
472 if (wtx.IsCoinBase() || !wtx.IsFinal()) | |
473 continue; | |
474 | |
475 foreach(const CTxOut& txout, wtx.vout) | |
476 if (setPubKey.count(txout.scriptPubKey)) | |
477 if (wtx.GetDepthInMainChain() >= nMinDepth) | |
478 nAmount += txout.nValue; | |
479 } | |
480 } | |
481 | |
482 return (double)nAmount / (double)COIN; | |
483 } | |
484 | |
485 | |
234
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
486 |
174 | 487 struct tallyitem |
488 { | |
489 int64 nAmount; | |
490 int nConf; | |
491 tallyitem() | |
492 { | |
493 nAmount = 0; | |
494 nConf = INT_MAX; | |
495 } | |
496 }; | |
497 | |
498 Value ListReceived(const Array& params, bool fByLabels) | |
499 { | |
500 // Minimum confirmations | |
501 int nMinDepth = 1; | |
502 if (params.size() > 0) | |
503 nMinDepth = params[0].get_int(); | |
504 | |
505 // Whether to include empty accounts | |
506 bool fIncludeEmpty = false; | |
507 if (params.size() > 1) | |
508 fIncludeEmpty = params[1].get_bool(); | |
509 | |
510 // Tally | |
511 map<uint160, tallyitem> mapTally; | |
512 CRITICAL_BLOCK(cs_mapWallet) | |
513 { | |
514 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) | |
515 { | |
516 const CWalletTx& wtx = (*it).second; | |
517 if (wtx.IsCoinBase() || !wtx.IsFinal()) | |
518 continue; | |
519 | |
520 int nDepth = wtx.GetDepthInMainChain(); | |
521 if (nDepth < nMinDepth) | |
522 continue; | |
523 | |
524 foreach(const CTxOut& txout, wtx.vout) | |
525 { | |
526 // Only counting our own bitcoin addresses and not ip addresses | |
527 uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160(); | |
528 if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine | |
529 continue; | |
530 | |
531 tallyitem& item = mapTally[hash160]; | |
532 item.nAmount += txout.nValue; | |
533 item.nConf = min(item.nConf, nDepth); | |
534 } | |
535 } | |
536 } | |
537 | |
538 // Reply | |
539 Array ret; | |
540 map<string, tallyitem> mapLabelTally; | |
541 CRITICAL_BLOCK(cs_mapAddressBook) | |
542 { | |
543 foreach(const PAIRTYPE(string, string)& item, mapAddressBook) | |
544 { | |
545 const string& strAddress = item.first; | |
546 const string& strLabel = item.second; | |
547 uint160 hash160; | |
548 if (!AddressToHash160(strAddress, hash160)) | |
549 continue; | |
550 map<uint160, tallyitem>::iterator it = mapTally.find(hash160); | |
551 if (it == mapTally.end() && !fIncludeEmpty) | |
552 continue; | |
553 | |
554 int64 nAmount = 0; | |
555 int nConf = INT_MAX; | |
556 if (it != mapTally.end()) | |
557 { | |
558 nAmount = (*it).second.nAmount; | |
559 nConf = (*it).second.nConf; | |
560 } | |
561 | |
562 if (fByLabels) | |
563 { | |
564 tallyitem& item = mapLabelTally[strLabel]; | |
565 item.nAmount += nAmount; | |
566 item.nConf = min(item.nConf, nConf); | |
567 } | |
568 else | |
569 { | |
570 Object obj; | |
571 obj.push_back(Pair("address", strAddress)); | |
572 obj.push_back(Pair("label", strLabel)); | |
573 obj.push_back(Pair("amount", (double)nAmount / (double)COIN)); | |
574 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf))); | |
575 ret.push_back(obj); | |
576 } | |
577 } | |
578 } | |
579 | |
580 if (fByLabels) | |
581 { | |
582 for (map<string, tallyitem>::iterator it = mapLabelTally.begin(); it != mapLabelTally.end(); ++it) | |
583 { | |
584 int64 nAmount = (*it).second.nAmount; | |
585 int nConf = (*it).second.nConf; | |
586 Object obj; | |
587 obj.push_back(Pair("label", (*it).first)); | |
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 return ret; | |
595 } | |
596 | |
597 Value listreceivedbyaddress(const Array& params, bool fHelp) | |
598 { | |
599 if (fHelp || params.size() > 2) | |
600 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
601 "listreceivedbyaddress [minconf=1] [includeempty=false]\n" |
174 | 602 "[minconf] is the minimum number of confirmations before payments are included.\n" |
603 "[includeempty] whether to include addresses that haven't received any payments.\n" | |
604 "Returns an array of objects containing:\n" | |
605 " \"address\" : receiving address\n" | |
606 " \"label\" : the label of the receiving address\n" | |
607 " \"amount\" : total amount received by the address\n" | |
608 " \"confirmations\" : number of confirmations of the most recent transaction included"); | |
609 | |
610 return ListReceived(params, false); | |
611 } | |
612 | |
613 Value listreceivedbylabel(const Array& params, bool fHelp) | |
614 { | |
615 if (fHelp || params.size() > 2) | |
616 throw runtime_error( | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
617 "listreceivedbylabel [minconf=1] [includeempty=false]\n" |
174 | 618 "[minconf] is the minimum number of confirmations before payments are included.\n" |
619 "[includeempty] whether to include labels that haven't received any payments.\n" | |
620 "Returns an array of objects containing:\n" | |
621 " \"label\" : the label of the receiving addresses\n" | |
622 " \"amount\" : total amount received by addresses with this label\n" | |
623 " \"confirmations\" : number of confirmations of the most recent transaction included"); | |
624 | |
625 return ListReceived(params, true); | |
626 } | |
627 | |
628 | |
629 | |
630 | |
631 | |
632 | |
633 | |
634 | |
635 | |
636 | |
637 | |
638 | |
639 | |
640 // | |
641 // Call Table | |
642 // | |
643 | |
644 pair<string, rpcfn_type> pCallTable[] = | |
645 { | |
646 make_pair("help", &help), | |
647 make_pair("stop", &stop), | |
648 make_pair("getblockcount", &getblockcount), | |
649 make_pair("getblocknumber", &getblocknumber), | |
650 make_pair("getconnectioncount", &getconnectioncount), | |
651 make_pair("getdifficulty", &getdifficulty), | |
652 make_pair("getbalance", &getbalance), | |
653 make_pair("getgenerate", &getgenerate), | |
654 make_pair("setgenerate", &setgenerate), | |
234
99f46c62ba59
gethashespersec and added version and hashespersec to getinfo
Satoshi Nakamoto <satoshin@gmx.com>
parents:
233
diff
changeset
|
655 make_pair("gethashespersec", &gethashespersec), |
174 | 656 make_pair("getinfo", &getinfo), |
657 make_pair("getnewaddress", &getnewaddress), | |
658 make_pair("setlabel", &setlabel), | |
659 make_pair("getlabel", &getlabel), | |
660 make_pair("getaddressesbylabel", &getaddressesbylabel), | |
661 make_pair("sendtoaddress", &sendtoaddress), | |
662 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress | |
663 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress | |
664 make_pair("getreceivedbyaddress", &getreceivedbyaddress), | |
665 make_pair("getreceivedbylabel", &getreceivedbylabel), | |
666 make_pair("listreceivedbyaddress", &listreceivedbyaddress), | |
667 make_pair("listreceivedbylabel", &listreceivedbylabel), | |
668 }; | |
669 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); | |
670 | |
671 | |
672 | |
673 | |
674 // | |
675 // HTTP protocol | |
676 // | |
677 // This ain't Apache. We're just using HTTP header for the length field | |
678 // and to be compatible with other JSON-RPC implementations. | |
679 // | |
680 | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
681 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders) |
174 | 682 { |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
683 ostringstream s; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
684 s << "POST / HTTP/1.1\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
685 << "User-Agent: json-rpc/1.0\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
686 << "Host: 127.0.0.1\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
687 << "Content-Type: application/json\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
688 << "Content-Length: " << strMsg.size() << "\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
689 << "Accept: application/json\r\n"; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
690 for (map<string,string>::const_iterator it = mapRequestHeaders.begin(); it != mapRequestHeaders.end(); ++it) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
691 s << it->first << ": " << it->second << "\r\n"; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
692 s << "\r\n" << strMsg; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
693 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
694 return s.str(); |
174 | 695 } |
696 | |
697 string HTTPReply(const string& strMsg, int nStatus=200) | |
698 { | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
699 if (nStatus == 401) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
700 return "HTTP/1.0 401 Authorization Required\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
701 "Server: HTTPd/1.0\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
702 "Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
703 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
704 "Content-Type: text/html\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
705 "Content-Length: 311\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
706 "\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
707 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
708 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
709 "<HTML>\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
710 "<HEAD>\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
711 "<TITLE>Error</TITLE>\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
712 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
713 "</HEAD>\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
714 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
715 "</HTML>\r\n"; |
174 | 716 string strStatus; |
717 if (nStatus == 200) strStatus = "OK"; | |
718 if (nStatus == 500) strStatus = "Internal Server Error"; | |
719 return strprintf( | |
720 "HTTP/1.1 %d %s\r\n" | |
721 "Connection: close\r\n" | |
722 "Content-Length: %d\r\n" | |
723 "Content-Type: application/json\r\n" | |
724 "Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n" | |
725 "Server: json-rpc/1.0\r\n" | |
726 "\r\n" | |
727 "%s", | |
728 nStatus, | |
729 strStatus.c_str(), | |
730 strMsg.size(), | |
731 strMsg.c_str()); | |
732 } | |
733 | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
734 int ReadHTTPStatus(tcp::iostream& stream) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
735 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
736 string str; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
737 getline(stream, str); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
738 vector<string> vWords; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
739 boost::split(vWords, str, boost::is_any_of(" ")); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
740 int nStatus = atoi(vWords[1].c_str()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
741 return nStatus; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
742 } |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
743 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
744 int ReadHTTPHeader(tcp::iostream& stream, map<string, string>& mapHeadersRet) |
174 | 745 { |
746 int nLen = 0; | |
747 loop | |
748 { | |
749 string str; | |
750 std::getline(stream, str); | |
751 if (str.empty() || str == "\r") | |
752 break; | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
753 string::size_type nColon = str.find(":"); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
754 if (nColon != string::npos) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
755 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
756 string strHeader = str.substr(0, nColon); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
757 boost::trim(strHeader); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
758 string strValue = str.substr(nColon+1); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
759 boost::trim(strValue); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
760 mapHeadersRet[strHeader] = strValue; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
761 if (strHeader == "Content-Length") |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
762 nLen = atoi(strValue.c_str()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
763 } |
174 | 764 } |
765 return nLen; | |
766 } | |
767 | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
768 int ReadHTTP(tcp::iostream& stream, map<string, string>& mapHeadersRet, string& strMessageRet) |
174 | 769 { |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
770 mapHeadersRet.clear(); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
771 strMessageRet = ""; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
772 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
773 // Read status |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
774 int nStatus = ReadHTTPStatus(stream); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
775 |
174 | 776 // Read header |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
777 int nLen = ReadHTTPHeader(stream, mapHeadersRet); |
174 | 778 if (nLen <= 0) |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
779 return 500; |
174 | 780 |
781 // Read message | |
782 vector<char> vch(nLen); | |
783 stream.read(&vch[0], nLen); | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
784 strMessageRet = string(vch.begin(), vch.end()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
785 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
786 return nStatus; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
787 } |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
788 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
789 string EncodeBase64(string s) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
790 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
791 BIO *b64, *bmem; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
792 BUF_MEM *bptr; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
793 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
794 b64 = BIO_new(BIO_f_base64()); |
182
27f90a2a8198
Gavin: BIO_FLAGS_BASE64_NO_NL
Gavin Andresen <gavinandresen@gmail.com>
parents:
181
diff
changeset
|
795 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
796 bmem = BIO_new(BIO_s_mem()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
797 b64 = BIO_push(b64, bmem); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
798 BIO_write(b64, s.c_str(), s.size()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
799 BIO_flush(b64); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
800 BIO_get_mem_ptr(b64, &bptr); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
801 |
182
27f90a2a8198
Gavin: BIO_FLAGS_BASE64_NO_NL
Gavin Andresen <gavinandresen@gmail.com>
parents:
181
diff
changeset
|
802 string result(bptr->data, bptr->length); |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
803 BIO_free_all(b64); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
804 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
805 return result; |
174 | 806 } |
807 | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
808 string DecodeBase64(string s) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
809 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
810 BIO *b64, *bmem; |
174 | 811 |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
812 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char))); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
813 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
814 b64 = BIO_new(BIO_f_base64()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
815 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
816 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
817 bmem = BIO_push(b64, bmem); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
818 BIO_read(bmem, buffer, s.size()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
819 BIO_free_all(bmem); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
820 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
821 string result(buffer); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
822 free(buffer); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
823 return result; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
824 } |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
825 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
826 bool HTTPAuthorized(map<string, string>& mapHeaders) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
827 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
828 string strAuth = mapHeaders["Authorization"]; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
829 if (strAuth.substr(0,6) != "Basic ") |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
830 return false; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
831 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
832 string strUserPass = DecodeBase64(strUserPass64); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
833 string::size_type nColon = strUserPass.find(":"); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
834 if (nColon == string::npos) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
835 return false; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
836 string strUser = strUserPass.substr(0, nColon); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
837 string strPassword = strUserPass.substr(nColon+1); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
838 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
839 } |
174 | 840 |
841 // | |
842 // JSON-RPC protocol | |
843 // | |
844 // http://json-rpc.org/wiki/specification | |
845 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx | |
846 // | |
847 | |
848 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id) | |
849 { | |
850 Object request; | |
851 request.push_back(Pair("method", strMethod)); | |
852 request.push_back(Pair("params", params)); | |
853 request.push_back(Pair("id", id)); | |
854 return write_string(Value(request), false) + "\n"; | |
855 } | |
856 | |
857 string JSONRPCReply(const Value& result, const Value& error, const Value& id) | |
858 { | |
859 Object reply; | |
860 if (error.type() != null_type) | |
861 reply.push_back(Pair("result", Value::null)); | |
862 else | |
863 reply.push_back(Pair("result", result)); | |
864 reply.push_back(Pair("error", error)); | |
865 reply.push_back(Pair("id", id)); | |
866 return write_string(Value(reply), false) + "\n"; | |
867 } | |
868 | |
869 | |
870 | |
871 | |
872 void ThreadRPCServer(void* parg) | |
873 { | |
874 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg)); | |
875 try | |
876 { | |
877 vnThreadsRunning[4]++; | |
878 ThreadRPCServer2(parg); | |
879 vnThreadsRunning[4]--; | |
880 } | |
881 catch (std::exception& e) { | |
882 vnThreadsRunning[4]--; | |
883 PrintException(&e, "ThreadRPCServer()"); | |
884 } catch (...) { | |
885 vnThreadsRunning[4]--; | |
886 PrintException(NULL, "ThreadRPCServer()"); | |
887 } | |
888 printf("ThreadRPCServer exiting\n"); | |
889 } | |
890 | |
891 void ThreadRPCServer2(void* parg) | |
892 { | |
893 printf("ThreadRPCServer started\n"); | |
894 | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
895 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") |
179
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
896 { |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
897 string strWhatAmI = "To use bitcoind"; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
898 if (mapArgs.count("-server")) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
899 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\""); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
900 else if (mapArgs.count("-daemon")) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
901 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\""); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
902 PrintConsole( |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
903 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
904 "If the file does not exist, create it with owner-readable-only file permissions.\n"), |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
905 strWhatAmI.c_str(), |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
906 GetConfigFile().c_str()); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
907 CreateThread(Shutdown, NULL); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
908 return; |
179
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
909 } |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
910 |
174 | 911 // Bind to loopback 127.0.0.1 so the socket can only be accessed locally |
912 boost::asio::io_service io_service; | |
913 tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 8332); | |
914 tcp::acceptor acceptor(io_service, endpoint); | |
915 | |
916 loop | |
917 { | |
918 // Accept connection | |
919 tcp::iostream stream; | |
920 tcp::endpoint peer; | |
921 vnThreadsRunning[4]--; | |
922 acceptor.accept(*stream.rdbuf(), peer); | |
923 vnThreadsRunning[4]++; | |
924 if (fShutdown) | |
925 return; | |
926 | |
927 // Shouldn't be possible for anyone else to connect, but just in case | |
928 if (peer.address().to_string() != "127.0.0.1") | |
929 continue; | |
930 | |
931 // Receive request | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
932 map<string, string> mapHeaders; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
933 string strRequest; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
934 ReadHTTP(stream, mapHeaders, strRequest); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
935 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
936 // Check authorization |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
937 if (mapHeaders.count("Authorization") == 0) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
938 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
939 stream << HTTPReply("", 401) << std::flush; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
940 continue; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
941 } |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
942 if (!HTTPAuthorized(mapHeaders)) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
943 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
944 // Deter brute-forcing short passwords |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
945 if (mapArgs["-rpcpassword"].size() < 15) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
946 Sleep(50); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
947 |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
948 stream << HTTPReply("", 401) << std::flush; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
949 printf("ThreadRPCServer incorrect password attempt\n"); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
950 continue; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
951 } |
174 | 952 |
953 // Handle multiple invocations per request | |
954 string::iterator begin = strRequest.begin(); | |
955 while (skipspaces(begin), begin != strRequest.end()) | |
956 { | |
957 string::iterator prev = begin; | |
958 Value id; | |
959 try | |
960 { | |
961 // Parse request | |
962 Value valRequest; | |
963 if (!read_range(begin, strRequest.end(), valRequest)) | |
964 throw runtime_error("Parse error."); | |
965 const Object& request = valRequest.get_obj(); | |
966 if (find_value(request, "method").type() != str_type || | |
967 find_value(request, "params").type() != array_type) | |
968 throw runtime_error("Invalid request."); | |
969 | |
970 string strMethod = find_value(request, "method").get_str(); | |
971 const Array& params = find_value(request, "params").get_array(); | |
972 id = find_value(request, "id"); | |
973 | |
179
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
974 printf("ThreadRPCServer method=%s\n", strMethod.c_str()); |
b9ee0808d2cf
json-rpc password, minor UI tweaks, removed some outdated txt files
Gavin Andresen <gavinandresen@gmail.com>
parents:
174
diff
changeset
|
975 |
193
83513e9c3f0c
new safety feature displays a warning message and locks down RPC if it detects a problem that may require an upgrade
Satoshi Nakamoto <satoshin@gmx.com>
parents:
183
diff
changeset
|
976 // Observe lockdown |
237
96105e347f4a
fix -datadir=./subdir relative path,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
236
diff
changeset
|
977 if (IsLockdown() && !mapArgs.count("-overridesafety") && strMethod != "help" && strMethod != "stop" && strMethod != "getgenerate" && strMethod != "setgenerate") |
96105e347f4a
fix -datadir=./subdir relative path,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
236
diff
changeset
|
978 throw runtime_error("WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade."); |
193
83513e9c3f0c
new safety feature displays a warning message and locks down RPC if it detects a problem that may require an upgrade
Satoshi Nakamoto <satoshin@gmx.com>
parents:
183
diff
changeset
|
979 |
174 | 980 // Execute |
981 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod); | |
982 if (mi == mapCallTable.end()) | |
983 throw runtime_error("Method not found."); | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
984 Value result = (*(*mi).second)(params, false); |
174 | 985 |
986 // Send reply | |
987 string strReply = JSONRPCReply(result, Value::null, id); | |
988 stream << HTTPReply(strReply, 200) << std::flush; | |
989 } | |
990 catch (std::exception& e) | |
991 { | |
992 // Send error reply | |
993 string strReply = JSONRPCReply(Value::null, e.what(), id); | |
994 stream << HTTPReply(strReply, 500) << std::flush; | |
995 } | |
996 if (begin == prev) | |
997 break; | |
998 } | |
999 } | |
1000 } | |
1001 | |
1002 | |
1003 | |
1004 | |
1005 Value CallRPC(const string& strMethod, const Array& params) | |
1006 { | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1007 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1008 throw runtime_error(strprintf( |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1009 _("You must set rpcpassword=<password> in the configuration file:\n%s\n" |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1010 "If the file does not exist, create it with owner-readable-only file permissions."), |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1011 GetConfigFile().c_str())); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1012 |
174 | 1013 // Connect to localhost |
1014 tcp::iostream stream("127.0.0.1", "8332"); | |
1015 if (stream.fail()) | |
1016 throw runtime_error("couldn't connect to server"); | |
1017 | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1018 // HTTP basic authentication |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1019 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1020 map<string, string> mapRequestHeaders; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1021 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1022 |
174 | 1023 // Send request |
1024 string strRequest = JSONRPCRequest(strMethod, params, 1); | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1025 string strPost = HTTPPost(strRequest, mapRequestHeaders); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1026 stream << strPost << std::flush; |
174 | 1027 |
1028 // Receive reply | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1029 map<string, string> mapHeaders; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1030 string strReply; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1031 int nStatus = ReadHTTP(stream, mapHeaders, strReply); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1032 if (nStatus == 401) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1033 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1034 else if (nStatus >= 400 && nStatus != 500) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1035 throw runtime_error(strprintf("server returned HTTP error %d", nStatus)); |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1036 else if (strReply.empty()) |
174 | 1037 throw runtime_error("no response from server"); |
1038 | |
1039 // Parse reply | |
1040 Value valReply; | |
1041 if (!read_string(strReply, valReply)) | |
1042 throw runtime_error("couldn't parse reply from server"); | |
1043 const Object& reply = valReply.get_obj(); | |
1044 if (reply.empty()) | |
1045 throw runtime_error("expected reply to have result, error and id properties"); | |
1046 | |
1047 const Value& result = find_value(reply, "result"); | |
1048 const Value& error = find_value(reply, "error"); | |
1049 const Value& id = find_value(reply, "id"); | |
1050 | |
1051 if (error.type() == str_type) | |
1052 throw runtime_error(error.get_str()); | |
1053 else if (error.type() != null_type) | |
1054 throw runtime_error(write_string(error, false)); | |
1055 return result; | |
1056 } | |
1057 | |
1058 | |
1059 | |
1060 | |
1061 template<typename T> | |
1062 void ConvertTo(Value& value) | |
1063 { | |
1064 if (value.type() == str_type) | |
1065 { | |
1066 // reinterpret string as unquoted json value | |
1067 Value value2; | |
1068 if (!read_string(value.get_str(), value2)) | |
1069 throw runtime_error("type mismatch"); | |
1070 value = value2.get_value<T>(); | |
1071 } | |
1072 else | |
1073 { | |
1074 value = value.get_value<T>(); | |
1075 } | |
1076 } | |
1077 | |
1078 int CommandLineRPC(int argc, char *argv[]) | |
1079 { | |
1080 try | |
1081 { | |
180
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1082 // Skip switches |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1083 while (argc > 1 && IsSwitchChar(argv[1][0])) |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1084 { |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1085 argc--; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1086 argv++; |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1087 } |
386494d57fb2
Configuration file, HTTP Basic authentication
Gavin Andresen <gavinandresen@gmail.com>
parents:
179
diff
changeset
|
1088 |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1089 // Method |
174 | 1090 if (argc < 2) |
1091 throw runtime_error("too few parameters"); | |
1092 string strMethod = argv[1]; | |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1093 |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1094 // Parameters default to strings |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1095 Array params; |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1096 for (int i = 2; i < argc; i++) |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1097 params.push_back(argv[i]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1098 int n = params.size(); |
174 | 1099 |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1100 // |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1101 // Special case non-string parameter types |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1102 // |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1103 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1104 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1105 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1106 if (strMethod == "listtransactions" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1107 if (strMethod == "listtransactions" && n > 1) ConvertTo<bool>(params[1]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1108 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1109 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1110 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1111 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1112 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1113 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1114 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1115 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1116 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); |
174 | 1117 |
233
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1118 // Execute |
e6e5741f4aca
json-spirit print reals with 8 decimal places,
Satoshi Nakamoto <satoshin@gmx.com>
parents:
193
diff
changeset
|
1119 Value result = CallRPC(strMethod, params); |
174 | 1120 |
1121 // Print result | |
1122 string strResult = (result.type() == str_type ? result.get_str() : write_string(result, true)); | |
1123 if (result.type() != null_type) | |
1124 { | |
183
5447d5ff8a3c
bitcoind now compiles without wxWidgets or wxBase
Satoshi Nakamoto <satoshin@gmx.com>
parents:
182
diff
changeset
|
1125 #if defined(__WXMSW__) && defined(GUI) |
174 | 1126 // Windows GUI apps can't print to command line, |
1127 // so settle for a message box yuck | |
1128 MyMessageBox(strResult.c_str(), "Bitcoin", wxOK); | |
1129 #else | |
1130 fprintf(stdout, "%s\n", strResult.c_str()); | |
1131 #endif | |
1132 } | |
1133 return 0; | |
1134 } | |
1135 catch (std::exception& e) { | |
183
5447d5ff8a3c
bitcoind now compiles without wxWidgets or wxBase
Satoshi Nakamoto <satoshin@gmx.com>
parents:
182
diff
changeset
|
1136 #if defined(__WXMSW__) && defined(GUI) |
174 | 1137 MyMessageBox(strprintf("error: %s\n", e.what()).c_str(), "Bitcoin", wxOK); |
1138 #else | |
1139 fprintf(stderr, "error: %s\n", e.what()); | |
1140 #endif | |
1141 } catch (...) { | |
1142 PrintException(NULL, "CommandLineRPC()"); | |
1143 } | |
1144 return 1; | |
1145 } | |
1146 | |
1147 | |
1148 | |
1149 | |
1150 #ifdef TEST | |
1151 int main(int argc, char *argv[]) | |
1152 { | |
1153 #ifdef _MSC_VER | |
1154 // Turn off microsoft heap dump noise | |
1155 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); | |
1156 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); | |
1157 #endif | |
1158 setbuf(stdin, NULL); | |
1159 setbuf(stdout, NULL); | |
1160 setbuf(stderr, NULL); | |
1161 | |
1162 try | |
1163 { | |
1164 if (argc >= 2 && string(argv[1]) == "-server") | |
1165 { | |
1166 printf("server ready\n"); | |
1167 ThreadRPCServer(NULL); | |
1168 } | |
1169 else | |
1170 { | |
1171 return CommandLineRPC(argc, argv); | |
1172 } | |
1173 } | |
1174 catch (std::exception& e) { | |
1175 PrintException(&e, "main()"); | |
1176 } catch (...) { | |
1177 PrintException(NULL, "main()"); | |
1178 } | |
1179 return 0; | |
1180 } | |
1181 #endif |