]>
Commit | Line | Data |
---|---|---|
f914f1a7 | 1 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
72fb3d29 | 2 | // Distributed under the MIT software license, see the accompanying |
70ab73a0 | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
b2864d2f | 4 | |
fdbdb7f3 | 5 | #include "rpcserver.h" |
b2864d2f | 6 | |
71697f97 | 7 | #include "clientversion.h" |
b2864d2f | 8 | #include "main.h" |
51ed9ec9 BD |
9 | #include "net.h" |
10 | #include "netbase.h" | |
11 | #include "protocol.h" | |
12 | #include "sync.h" | |
14f888ca | 13 | #include "timedata.h" |
51ed9ec9 | 14 | #include "util.h" |
ff36cbe8 | 15 | #include "version.h" |
51ed9ec9 | 16 | |
51ed9ec9 | 17 | #include <boost/foreach.hpp> |
611116d4 | 18 | |
51ed9ec9 | 19 | #include "json/json_spirit_value.h" |
70ab73a0 JG |
20 | |
21 | using namespace json_spirit; | |
22 | using namespace std; | |
23 | ||
24 | Value getconnectioncount(const Array& params, bool fHelp) | |
25 | { | |
26 | if (fHelp || params.size() != 0) | |
27 | throw runtime_error( | |
28 | "getconnectioncount\n" | |
a6099ef3 | 29 | "\nReturns the number of connections to other nodes.\n" |
30 | "\nbResult:\n" | |
31 | "n (numeric) The connection count\n" | |
32 | "\nExamples:\n" | |
33 | + HelpExampleCli("getconnectioncount", "") | |
34 | + HelpExampleRpc("getconnectioncount", "") | |
35 | ); | |
70ab73a0 | 36 | |
4401b2d7 EL |
37 | LOCK2(cs_main, cs_vNodes); |
38 | ||
70ab73a0 JG |
39 | return (int)vNodes.size(); |
40 | } | |
41 | ||
971bb3e9 JL |
42 | Value ping(const Array& params, bool fHelp) |
43 | { | |
44 | if (fHelp || params.size() != 0) | |
45 | throw runtime_error( | |
46 | "ping\n" | |
a6099ef3 | 47 | "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" |
971bb3e9 | 48 | "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" |
6943cb9b | 49 | "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n" |
a6099ef3 | 50 | "\nExamples:\n" |
51 | + HelpExampleCli("ping", "") | |
52 | + HelpExampleRpc("ping", "") | |
53 | ); | |
4315ec1a | 54 | |
971bb3e9 | 55 | // Request that each node send a ping during next message processing pass |
4401b2d7 EL |
56 | LOCK2(cs_main, cs_vNodes); |
57 | ||
971bb3e9 JL |
58 | BOOST_FOREACH(CNode* pNode, vNodes) { |
59 | pNode->fPingQueued = true; | |
60 | } | |
61 | ||
62 | return Value::null; | |
63 | } | |
64 | ||
1006f070 JG |
65 | static void CopyNodeStats(std::vector<CNodeStats>& vstats) |
66 | { | |
67 | vstats.clear(); | |
68 | ||
69 | LOCK(cs_vNodes); | |
70 | vstats.reserve(vNodes.size()); | |
71 | BOOST_FOREACH(CNode* pnode, vNodes) { | |
72 | CNodeStats stats; | |
73 | pnode->copyStats(stats); | |
74 | vstats.push_back(stats); | |
75 | } | |
76 | } | |
77 | ||
78 | Value getpeerinfo(const Array& params, bool fHelp) | |
79 | { | |
80 | if (fHelp || params.size() != 0) | |
81 | throw runtime_error( | |
82 | "getpeerinfo\n" | |
a6099ef3 | 83 | "\nReturns data about each connected network node as a json array of objects.\n" |
84 | "\nbResult:\n" | |
85 | "[\n" | |
86 | " {\n" | |
c4a321f5 | 87 | " \"id\": n, (numeric) Peer index\n" |
a6099ef3 | 88 | " \"addr\":\"host:port\", (string) The ip address and port of the peer\n" |
89 | " \"addrlocal\":\"ip:port\", (string) local address\n" | |
99ddc6cb | 90 | " \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n" |
a6099ef3 | 91 | " \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n" |
92 | " \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n" | |
93 | " \"bytessent\": n, (numeric) The total bytes sent\n" | |
94 | " \"bytesrecv\": n, (numeric) The total bytes received\n" | |
95 | " \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n" | |
26a6bae7 | 96 | " \"timeoffset\": ttt, (numeric) The time offset in seconds\n" |
a6099ef3 | 97 | " \"pingtime\": n, (numeric) ping time\n" |
98 | " \"pingwait\": n, (numeric) ping wait\n" | |
5bd677f5 S |
99 | " \"version\": v, (numeric) The peer version, such as 170002\n" |
100 | " \"subver\": \"/MagicBean:x.y.z[-v]/\", (string) The string version\n" | |
a6099ef3 | 101 | " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n" |
102 | " \"startingheight\": n, (numeric) The starting height (block) of the peer\n" | |
ee304b6e | 103 | " \"banscore\": n, (numeric) The ban score\n" |
ad6e6017 PW |
104 | " \"synced_headers\": n, (numeric) The last header we have in common with this peer\n" |
105 | " \"synced_blocks\": n, (numeric) The last block we have in common with this peer\n" | |
106 | " \"inflight\": [\n" | |
107 | " n, (numeric) The heights of blocks we're currently asking from this peer\n" | |
108 | " ...\n" | |
109 | " ]\n" | |
a6099ef3 | 110 | " }\n" |
111 | " ,...\n" | |
7de3f1cf | 112 | "]\n" |
a6099ef3 | 113 | "\nExamples:\n" |
114 | + HelpExampleCli("getpeerinfo", "") | |
115 | + HelpExampleRpc("getpeerinfo", "") | |
116 | ); | |
1006f070 | 117 | |
4401b2d7 EL |
118 | LOCK(cs_main); |
119 | ||
1006f070 JG |
120 | vector<CNodeStats> vstats; |
121 | CopyNodeStats(vstats); | |
122 | ||
123 | Array ret; | |
124 | ||
125 | BOOST_FOREACH(const CNodeStats& stats, vstats) { | |
126 | Object obj; | |
b2864d2f PW |
127 | CNodeStateStats statestats; |
128 | bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); | |
c4a321f5 | 129 | obj.push_back(Pair("id", stats.nodeid)); |
1006f070 | 130 | obj.push_back(Pair("addr", stats.addrName)); |
547c61f8 JL |
131 | if (!(stats.addrLocal.empty())) |
132 | obj.push_back(Pair("addrlocal", stats.addrLocal)); | |
99ddc6cb | 133 | obj.push_back(Pair("services", strprintf("%016x", stats.nServices))); |
d56e30ca KD |
134 | obj.push_back(Pair("lastsend", stats.nLastSend)); |
135 | obj.push_back(Pair("lastrecv", stats.nLastRecv)); | |
136 | obj.push_back(Pair("bytessent", stats.nSendBytes)); | |
137 | obj.push_back(Pair("bytesrecv", stats.nRecvBytes)); | |
138 | obj.push_back(Pair("conntime", stats.nTimeConnected)); | |
26a6bae7 | 139 | obj.push_back(Pair("timeoffset", stats.nTimeOffset)); |
971bb3e9 JL |
140 | obj.push_back(Pair("pingtime", stats.dPingTime)); |
141 | if (stats.dPingWait > 0.0) | |
142 | obj.push_back(Pair("pingwait", stats.dPingWait)); | |
1006f070 | 143 | obj.push_back(Pair("version", stats.nVersion)); |
a946aa8d MH |
144 | // Use the sanitized form of subver here, to avoid tricksy remote peers from |
145 | // corrupting or modifiying the JSON output by putting special characters in | |
146 | // their ver message. | |
147 | obj.push_back(Pair("subver", stats.cleanSubVer)); | |
1006f070 | 148 | obj.push_back(Pair("inbound", stats.fInbound)); |
18e8e437 | 149 | obj.push_back(Pair("startingheight", stats.nStartingHeight)); |
b2864d2f PW |
150 | if (fStateStats) { |
151 | obj.push_back(Pair("banscore", statestats.nMisbehavior)); | |
ad6e6017 PW |
152 | obj.push_back(Pair("synced_headers", statestats.nSyncHeight)); |
153 | obj.push_back(Pair("synced_blocks", statestats.nCommonHeight)); | |
154 | Array heights; | |
155 | BOOST_FOREACH(int height, statestats.vHeightInFlight) { | |
156 | heights.push_back(height); | |
157 | } | |
158 | obj.push_back(Pair("inflight", heights)); | |
b2864d2f | 159 | } |
dc942e6f | 160 | obj.push_back(Pair("whitelisted", stats.fWhitelisted)); |
1006f070 JG |
161 | |
162 | ret.push_back(obj); | |
163 | } | |
ea0796bd | 164 | |
1006f070 JG |
165 | return ret; |
166 | } | |
70ab73a0 | 167 | |
72a348fd MC |
168 | Value addnode(const Array& params, bool fHelp) |
169 | { | |
170 | string strCommand; | |
171 | if (params.size() == 2) | |
172 | strCommand = params[1].get_str(); | |
173 | if (fHelp || params.size() != 2 || | |
174 | (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) | |
175 | throw runtime_error( | |
a6099ef3 | 176 | "addnode \"node\" \"add|remove|onetry\"\n" |
177 | "\nAttempts add or remove a node from the addnode list.\n" | |
178 | "Or try a connection to a node once.\n" | |
179 | "\nArguments:\n" | |
180 | "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n" | |
181 | "2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n" | |
182 | "\nExamples:\n" | |
3985a40d JG |
183 | + HelpExampleCli("addnode", "\"192.168.0.6:8233\" \"onetry\"") |
184 | + HelpExampleRpc("addnode", "\"192.168.0.6:8233\", \"onetry\"") | |
a6099ef3 | 185 | ); |
72a348fd MC |
186 | |
187 | string strNode = params[0].get_str(); | |
188 | ||
189 | if (strCommand == "onetry") | |
190 | { | |
191 | CAddress addr; | |
b641c9cd | 192 | OpenNetworkConnection(addr, NULL, strNode.c_str()); |
72a348fd MC |
193 | return Value::null; |
194 | } | |
195 | ||
196 | LOCK(cs_vAddedNodes); | |
197 | vector<string>::iterator it = vAddedNodes.begin(); | |
198 | for(; it != vAddedNodes.end(); it++) | |
199 | if (strNode == *it) | |
200 | break; | |
201 | ||
202 | if (strCommand == "add") | |
203 | { | |
204 | if (it != vAddedNodes.end()) | |
4315ec1a | 205 | throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); |
72a348fd MC |
206 | vAddedNodes.push_back(strNode); |
207 | } | |
208 | else if(strCommand == "remove") | |
209 | { | |
210 | if (it == vAddedNodes.end()) | |
4315ec1a | 211 | throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); |
72a348fd MC |
212 | vAddedNodes.erase(it); |
213 | } | |
214 | ||
215 | return Value::null; | |
216 | } | |
217 | ||
67a11bd6 MC |
218 | Value getaddednodeinfo(const Array& params, bool fHelp) |
219 | { | |
220 | if (fHelp || params.size() < 1 || params.size() > 2) | |
221 | throw runtime_error( | |
a6099ef3 | 222 | "getaddednodeinfo dns ( \"node\" )\n" |
223 | "\nReturns information about the given added node, or all added nodes\n" | |
67a11bd6 MC |
224 | "(note that onetry addnodes are not listed here)\n" |
225 | "If dns is false, only a list of added nodes will be provided,\n" | |
a6099ef3 | 226 | "otherwise connected information will also be available.\n" |
227 | "\nArguments:\n" | |
228 | "1. dns (boolean, required) If false, only a list of added nodes will be provided, otherwise connected information will also be available.\n" | |
229 | "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n" | |
230 | "\nResult:\n" | |
231 | "[\n" | |
232 | " {\n" | |
233 | " \"addednode\" : \"192.168.0.201\", (string) The node ip address\n" | |
234 | " \"connected\" : true|false, (boolean) If connected\n" | |
235 | " \"addresses\" : [\n" | |
236 | " {\n" | |
3985a40d | 237 | " \"address\" : \"192.168.0.201:8233\", (string) The bitcoin server host and port\n" |
a6099ef3 | 238 | " \"connected\" : \"outbound\" (string) connection, inbound or outbound\n" |
239 | " }\n" | |
240 | " ,...\n" | |
241 | " ]\n" | |
242 | " }\n" | |
243 | " ,...\n" | |
244 | "]\n" | |
245 | "\nExamples:\n" | |
246 | + HelpExampleCli("getaddednodeinfo", "true") | |
247 | + HelpExampleCli("getaddednodeinfo", "true \"192.168.0.201\"") | |
248 | + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"") | |
249 | ); | |
67a11bd6 MC |
250 | |
251 | bool fDns = params[0].get_bool(); | |
252 | ||
253 | list<string> laddedNodes(0); | |
254 | if (params.size() == 1) | |
255 | { | |
256 | LOCK(cs_vAddedNodes); | |
257 | BOOST_FOREACH(string& strAddNode, vAddedNodes) | |
258 | laddedNodes.push_back(strAddNode); | |
259 | } | |
260 | else | |
261 | { | |
262 | string strNode = params[1].get_str(); | |
263 | LOCK(cs_vAddedNodes); | |
264 | BOOST_FOREACH(string& strAddNode, vAddedNodes) | |
265 | if (strAddNode == strNode) | |
266 | { | |
267 | laddedNodes.push_back(strAddNode); | |
268 | break; | |
269 | } | |
270 | if (laddedNodes.size() == 0) | |
4315ec1a | 271 | throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); |
67a11bd6 MC |
272 | } |
273 | ||
4412c5a7 | 274 | Array ret; |
67a11bd6 MC |
275 | if (!fDns) |
276 | { | |
67a11bd6 | 277 | BOOST_FOREACH(string& strAddNode, laddedNodes) |
4412c5a7 WL |
278 | { |
279 | Object obj; | |
280 | obj.push_back(Pair("addednode", strAddNode)); | |
281 | ret.push_back(obj); | |
282 | } | |
67a11bd6 MC |
283 | return ret; |
284 | } | |
285 | ||
67a11bd6 MC |
286 | list<pair<string, vector<CService> > > laddedAddreses(0); |
287 | BOOST_FOREACH(string& strAddNode, laddedNodes) | |
288 | { | |
289 | vector<CService> vservNode(0); | |
0e4b3175 | 290 | if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) |
67a11bd6 MC |
291 | laddedAddreses.push_back(make_pair(strAddNode, vservNode)); |
292 | else | |
293 | { | |
294 | Object obj; | |
295 | obj.push_back(Pair("addednode", strAddNode)); | |
296 | obj.push_back(Pair("connected", false)); | |
297 | Array addresses; | |
298 | obj.push_back(Pair("addresses", addresses)); | |
299 | } | |
300 | } | |
301 | ||
302 | LOCK(cs_vNodes); | |
303 | for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) | |
304 | { | |
305 | Object obj; | |
306 | obj.push_back(Pair("addednode", it->first)); | |
307 | ||
308 | Array addresses; | |
309 | bool fConnected = false; | |
310 | BOOST_FOREACH(CService& addrNode, it->second) | |
311 | { | |
312 | bool fFound = false; | |
313 | Object node; | |
314 | node.push_back(Pair("address", addrNode.ToString())); | |
315 | BOOST_FOREACH(CNode* pnode, vNodes) | |
316 | if (pnode->addr == addrNode) | |
317 | { | |
318 | fFound = true; | |
319 | fConnected = true; | |
320 | node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound")); | |
321 | break; | |
322 | } | |
323 | if (!fFound) | |
324 | node.push_back(Pair("connected", "false")); | |
325 | addresses.push_back(node); | |
326 | } | |
327 | obj.push_back(Pair("connected", fConnected)); | |
328 | obj.push_back(Pair("addresses", addresses)); | |
329 | ret.push_back(obj); | |
330 | } | |
331 | ||
332 | return ret; | |
333 | } | |
334 | ||
ce14345a SE |
335 | Value getnettotals(const Array& params, bool fHelp) |
336 | { | |
337 | if (fHelp || params.size() > 0) | |
338 | throw runtime_error( | |
339 | "getnettotals\n" | |
a6099ef3 | 340 | "\nReturns information about network traffic, including bytes in, bytes out,\n" |
341 | "and current time.\n" | |
342 | "\nResult:\n" | |
343 | "{\n" | |
344 | " \"totalbytesrecv\": n, (numeric) Total bytes received\n" | |
38cbeab1 | 345 | " \"totalbytessent\": n, (numeric) Total bytes sent\n" |
a6099ef3 | 346 | " \"timemillis\": t (numeric) Total cpu time\n" |
347 | "}\n" | |
348 | "\nExamples:\n" | |
349 | + HelpExampleCli("getnettotals", "") | |
350 | + HelpExampleRpc("getnettotals", "") | |
351 | ); | |
ce14345a SE |
352 | |
353 | Object obj; | |
d56e30ca KD |
354 | obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); |
355 | obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); | |
356 | obj.push_back(Pair("timemillis", GetTimeMillis())); | |
ce14345a SE |
357 | return obj; |
358 | } | |
d387b8ec | 359 | |
aa827951 WL |
360 | static Array GetNetworksInfo() |
361 | { | |
362 | Array networks; | |
363 | for(int n=0; n<NET_MAX; ++n) | |
364 | { | |
365 | enum Network network = static_cast<enum Network>(n); | |
366 | if(network == NET_UNROUTABLE) | |
367 | continue; | |
368 | proxyType proxy; | |
369 | Object obj; | |
370 | GetProxy(network, proxy); | |
371 | obj.push_back(Pair("name", GetNetworkName(network))); | |
372 | obj.push_back(Pair("limited", IsLimited(network))); | |
373 | obj.push_back(Pair("reachable", IsReachable(network))); | |
67a79493 WL |
374 | obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())); |
375 | obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials)); | |
aa827951 WL |
376 | networks.push_back(obj); |
377 | } | |
378 | return networks; | |
379 | } | |
380 | ||
d387b8ec WL |
381 | Value getnetworkinfo(const Array& params, bool fHelp) |
382 | { | |
383 | if (fHelp || params.size() != 0) | |
384 | throw runtime_error( | |
385 | "getnetworkinfo\n" | |
386 | "Returns an object containing various state info regarding P2P networking.\n" | |
387 | "\nResult:\n" | |
388 | "{\n" | |
b5ec5fe0 | 389 | " \"version\": xxxxx, (numeric) the server version\n" |
5bd677f5 | 390 | " \"subversion\": \"/MagicBean:x.y.z[-v]/\", (string) the server subversion string\n" |
b5ec5fe0 PK |
391 | " \"protocolversion\": xxxxx, (numeric) the protocol version\n" |
392 | " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n" | |
393 | " \"timeoffset\": xxxxx, (numeric) the time offset\n" | |
394 | " \"connections\": xxxxx, (numeric) the number of connections\n" | |
395 | " \"networks\": [ (array) information per network\n" | |
396 | " {\n" | |
397 | " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n" | |
398 | " \"limited\": true|false, (boolean) is the network limited using -onlynet?\n" | |
399 | " \"reachable\": true|false, (boolean) is the network reachable?\n" | |
400 | " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n" | |
401 | " }\n" | |
402 | " ,...\n" | |
aa827951 | 403 | " ],\n" |
b5ec5fe0 PK |
404 | " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n" |
405 | " \"localaddresses\": [ (array) list of local addresses\n" | |
406 | " {\n" | |
407 | " \"address\": \"xxxx\", (string) network address\n" | |
408 | " \"port\": xxx, (numeric) network port\n" | |
409 | " \"score\": xxx (numeric) relative score\n" | |
410 | " }\n" | |
411 | " ,...\n" | |
d387b8ec WL |
412 | " ]\n" |
413 | "}\n" | |
414 | "\nExamples:\n" | |
415 | + HelpExampleCli("getnetworkinfo", "") | |
416 | + HelpExampleRpc("getnetworkinfo", "") | |
417 | ); | |
418 | ||
4401b2d7 EL |
419 | LOCK(cs_main); |
420 | ||
d387b8ec | 421 | Object obj; |
b5ec5fe0 | 422 | obj.push_back(Pair("version", CLIENT_VERSION)); |
ff36cbe8 JG |
423 | obj.push_back(Pair("subversion", |
424 | FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()))); | |
b5ec5fe0 | 425 | obj.push_back(Pair("protocolversion",PROTOCOL_VERSION)); |
99ddc6cb | 426 | obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); |
d56e30ca | 427 | obj.push_back(Pair("timeoffset", GetTimeOffset())); |
d387b8ec | 428 | obj.push_back(Pair("connections", (int)vNodes.size())); |
aa827951 | 429 | obj.push_back(Pair("networks", GetNetworksInfo())); |
13fc83c7 | 430 | obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); |
d387b8ec WL |
431 | Array localAddresses; |
432 | { | |
433 | LOCK(cs_mapLocalHost); | |
434 | BOOST_FOREACH(const PAIRTYPE(CNetAddr, LocalServiceInfo) &item, mapLocalHost) | |
435 | { | |
436 | Object rec; | |
437 | rec.push_back(Pair("address", item.first.ToString())); | |
438 | rec.push_back(Pair("port", item.second.nPort)); | |
439 | rec.push_back(Pair("score", item.second.nScore)); | |
440 | localAddresses.push_back(rec); | |
441 | } | |
442 | } | |
443 | obj.push_back(Pair("localaddresses", localAddresses)); | |
444 | return obj; | |
445 | } |