bitcoin-tx: Accept input via stdin. Add input handling to tests.
[bitcoinplatinum.git] / src / rpcnet.cpp
blob2baa481c4e4da5a320d89ce9c473d98cf3487a2f
1 // Copyright (c) 2009-2014 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include "rpcserver.h"
7 #include "main.h"
8 #include "net.h"
9 #include "netbase.h"
10 #include "protocol.h"
11 #include "sync.h"
12 #include "timedata.h"
13 #include "util.h"
15 #include <boost/foreach.hpp>
16 #include "json/json_spirit_value.h"
18 using namespace json_spirit;
19 using namespace std;
21 Value getconnectioncount(const Array& params, bool fHelp)
23 if (fHelp || params.size() != 0)
24 throw runtime_error(
25 "getconnectioncount\n"
26 "\nReturns the number of connections to other nodes.\n"
27 "\nbResult:\n"
28 "n (numeric) The connection count\n"
29 "\nExamples:\n"
30 + HelpExampleCli("getconnectioncount", "")
31 + HelpExampleRpc("getconnectioncount", "")
34 LOCK(cs_vNodes);
35 return (int)vNodes.size();
38 Value ping(const Array& params, bool fHelp)
40 if (fHelp || params.size() != 0)
41 throw runtime_error(
42 "ping\n"
43 "\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
44 "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
45 "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n"
46 "\nExamples:\n"
47 + HelpExampleCli("ping", "")
48 + HelpExampleRpc("ping", "")
51 // Request that each node send a ping during next message processing pass
52 LOCK(cs_vNodes);
53 BOOST_FOREACH(CNode* pNode, vNodes) {
54 pNode->fPingQueued = true;
57 return Value::null;
60 static void CopyNodeStats(std::vector<CNodeStats>& vstats)
62 vstats.clear();
64 LOCK(cs_vNodes);
65 vstats.reserve(vNodes.size());
66 BOOST_FOREACH(CNode* pnode, vNodes) {
67 CNodeStats stats;
68 pnode->copyStats(stats);
69 vstats.push_back(stats);
73 Value getpeerinfo(const Array& params, bool fHelp)
75 if (fHelp || params.size() != 0)
76 throw runtime_error(
77 "getpeerinfo\n"
78 "\nReturns data about each connected network node as a json array of objects.\n"
79 "\nbResult:\n"
80 "[\n"
81 " {\n"
82 " \"id\": n, (numeric) Peer index\n"
83 " \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
84 " \"addrlocal\":\"ip:port\", (string) local address\n"
85 " \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
86 " \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
87 " \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
88 " \"bytessent\": n, (numeric) The total bytes sent\n"
89 " \"bytesrecv\": n, (numeric) The total bytes received\n"
90 " \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n"
91 " \"pingtime\": n, (numeric) ping time\n"
92 " \"pingwait\": n, (numeric) ping wait\n"
93 " \"version\": v, (numeric) The peer version, such as 7001\n"
94 " \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n"
95 " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
96 " \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
97 " \"banscore\": n, (numeric) The ban score (stats.nMisbehavior)\n"
98 " \"syncnode\" : true|false (booleamn) if sync node\n"
99 " }\n"
100 " ,...\n"
101 "]\n"
102 "\nExamples:\n"
103 + HelpExampleCli("getpeerinfo", "")
104 + HelpExampleRpc("getpeerinfo", "")
107 vector<CNodeStats> vstats;
108 CopyNodeStats(vstats);
110 Array ret;
112 BOOST_FOREACH(const CNodeStats& stats, vstats) {
113 Object obj;
114 CNodeStateStats statestats;
115 bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
116 obj.push_back(Pair("id", stats.nodeid));
117 obj.push_back(Pair("addr", stats.addrName));
118 if (!(stats.addrLocal.empty()))
119 obj.push_back(Pair("addrlocal", stats.addrLocal));
120 obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
121 obj.push_back(Pair("lastsend", stats.nLastSend));
122 obj.push_back(Pair("lastrecv", stats.nLastRecv));
123 obj.push_back(Pair("bytessent", stats.nSendBytes));
124 obj.push_back(Pair("bytesrecv", stats.nRecvBytes));
125 obj.push_back(Pair("conntime", stats.nTimeConnected));
126 obj.push_back(Pair("pingtime", stats.dPingTime));
127 if (stats.dPingWait > 0.0)
128 obj.push_back(Pair("pingwait", stats.dPingWait));
129 obj.push_back(Pair("version", stats.nVersion));
130 // Use the sanitized form of subver here, to avoid tricksy remote peers from
131 // corrupting or modifiying the JSON output by putting special characters in
132 // their ver message.
133 obj.push_back(Pair("subver", stats.cleanSubVer));
134 obj.push_back(Pair("inbound", stats.fInbound));
135 obj.push_back(Pair("startingheight", stats.nStartingHeight));
136 if (fStateStats) {
137 obj.push_back(Pair("banscore", statestats.nMisbehavior));
138 obj.push_back(Pair("syncheight", statestats.nSyncHeight));
140 obj.push_back(Pair("syncnode", stats.fSyncNode));
141 obj.push_back(Pair("whitelisted", stats.fWhitelisted));
143 ret.push_back(obj);
146 return ret;
149 Value addnode(const Array& params, bool fHelp)
151 string strCommand;
152 if (params.size() == 2)
153 strCommand = params[1].get_str();
154 if (fHelp || params.size() != 2 ||
155 (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
156 throw runtime_error(
157 "addnode \"node\" \"add|remove|onetry\"\n"
158 "\nAttempts add or remove a node from the addnode list.\n"
159 "Or try a connection to a node once.\n"
160 "\nArguments:\n"
161 "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
162 "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"
163 "\nExamples:\n"
164 + HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"")
165 + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
168 string strNode = params[0].get_str();
170 if (strCommand == "onetry")
172 CAddress addr;
173 OpenNetworkConnection(addr, NULL, strNode.c_str());
174 return Value::null;
177 LOCK(cs_vAddedNodes);
178 vector<string>::iterator it = vAddedNodes.begin();
179 for(; it != vAddedNodes.end(); it++)
180 if (strNode == *it)
181 break;
183 if (strCommand == "add")
185 if (it != vAddedNodes.end())
186 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
187 vAddedNodes.push_back(strNode);
189 else if(strCommand == "remove")
191 if (it == vAddedNodes.end())
192 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
193 vAddedNodes.erase(it);
196 return Value::null;
199 Value getaddednodeinfo(const Array& params, bool fHelp)
201 if (fHelp || params.size() < 1 || params.size() > 2)
202 throw runtime_error(
203 "getaddednodeinfo dns ( \"node\" )\n"
204 "\nReturns information about the given added node, or all added nodes\n"
205 "(note that onetry addnodes are not listed here)\n"
206 "If dns is false, only a list of added nodes will be provided,\n"
207 "otherwise connected information will also be available.\n"
208 "\nArguments:\n"
209 "1. dns (boolean, required) If false, only a list of added nodes will be provided, otherwise connected information will also be available.\n"
210 "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
211 "\nResult:\n"
212 "[\n"
213 " {\n"
214 " \"addednode\" : \"192.168.0.201\", (string) The node ip address\n"
215 " \"connected\" : true|false, (boolean) If connected\n"
216 " \"addresses\" : [\n"
217 " {\n"
218 " \"address\" : \"192.168.0.201:8333\", (string) The bitcoin server host and port\n"
219 " \"connected\" : \"outbound\" (string) connection, inbound or outbound\n"
220 " }\n"
221 " ,...\n"
222 " ]\n"
223 " }\n"
224 " ,...\n"
225 "]\n"
226 "\nExamples:\n"
227 + HelpExampleCli("getaddednodeinfo", "true")
228 + HelpExampleCli("getaddednodeinfo", "true \"192.168.0.201\"")
229 + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
232 bool fDns = params[0].get_bool();
234 list<string> laddedNodes(0);
235 if (params.size() == 1)
237 LOCK(cs_vAddedNodes);
238 BOOST_FOREACH(string& strAddNode, vAddedNodes)
239 laddedNodes.push_back(strAddNode);
241 else
243 string strNode = params[1].get_str();
244 LOCK(cs_vAddedNodes);
245 BOOST_FOREACH(string& strAddNode, vAddedNodes)
246 if (strAddNode == strNode)
248 laddedNodes.push_back(strAddNode);
249 break;
251 if (laddedNodes.size() == 0)
252 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
255 Array ret;
256 if (!fDns)
258 BOOST_FOREACH(string& strAddNode, laddedNodes)
260 Object obj;
261 obj.push_back(Pair("addednode", strAddNode));
262 ret.push_back(obj);
264 return ret;
267 list<pair<string, vector<CService> > > laddedAddreses(0);
268 BOOST_FOREACH(string& strAddNode, laddedNodes)
270 vector<CService> vservNode(0);
271 if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
272 laddedAddreses.push_back(make_pair(strAddNode, vservNode));
273 else
275 Object obj;
276 obj.push_back(Pair("addednode", strAddNode));
277 obj.push_back(Pair("connected", false));
278 Array addresses;
279 obj.push_back(Pair("addresses", addresses));
283 LOCK(cs_vNodes);
284 for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
286 Object obj;
287 obj.push_back(Pair("addednode", it->first));
289 Array addresses;
290 bool fConnected = false;
291 BOOST_FOREACH(CService& addrNode, it->second)
293 bool fFound = false;
294 Object node;
295 node.push_back(Pair("address", addrNode.ToString()));
296 BOOST_FOREACH(CNode* pnode, vNodes)
297 if (pnode->addr == addrNode)
299 fFound = true;
300 fConnected = true;
301 node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
302 break;
304 if (!fFound)
305 node.push_back(Pair("connected", "false"));
306 addresses.push_back(node);
308 obj.push_back(Pair("connected", fConnected));
309 obj.push_back(Pair("addresses", addresses));
310 ret.push_back(obj);
313 return ret;
316 Value getnettotals(const Array& params, bool fHelp)
318 if (fHelp || params.size() > 0)
319 throw runtime_error(
320 "getnettotals\n"
321 "\nReturns information about network traffic, including bytes in, bytes out,\n"
322 "and current time.\n"
323 "\nResult:\n"
324 "{\n"
325 " \"totalbytesrecv\": n, (numeric) Total bytes received\n"
326 " \"totalbytessent\": n, (numeric) Total bytes sent\n"
327 " \"timemillis\": t (numeric) Total cpu time\n"
328 "}\n"
329 "\nExamples:\n"
330 + HelpExampleCli("getnettotals", "")
331 + HelpExampleRpc("getnettotals", "")
334 Object obj;
335 obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
336 obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
337 obj.push_back(Pair("timemillis", GetTimeMillis()));
338 return obj;
341 static Array GetNetworksInfo()
343 Array networks;
344 for(int n=0; n<NET_MAX; ++n)
346 enum Network network = static_cast<enum Network>(n);
347 if(network == NET_UNROUTABLE)
348 continue;
349 proxyType proxy;
350 Object obj;
351 GetProxy(network, proxy);
352 obj.push_back(Pair("name", GetNetworkName(network)));
353 obj.push_back(Pair("limited", IsLimited(network)));
354 obj.push_back(Pair("reachable", IsReachable(network)));
355 obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.ToStringIPPort() : string()));
356 networks.push_back(obj);
358 return networks;
361 Value getnetworkinfo(const Array& params, bool fHelp)
363 if (fHelp || params.size() != 0)
364 throw runtime_error(
365 "getnetworkinfo\n"
366 "Returns an object containing various state info regarding P2P networking.\n"
367 "\nResult:\n"
368 "{\n"
369 " \"version\": xxxxx, (numeric) the server version\n"
370 " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
371 " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
372 " \"timeoffset\": xxxxx, (numeric) the time offset\n"
373 " \"connections\": xxxxx, (numeric) the number of connections\n"
374 " \"networks\": [ (array) information per network\n"
375 " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
376 " \"limited\": xxx, (boolean) is the network limited using -onlynet?\n"
377 " \"reachable\": xxx, (boolean) is the network reachable?\n"
378 " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
379 " },\n"
380 " ],\n"
381 " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
382 " \"localaddresses\": [, (array) list of local addresses\n"
383 " \"address\": \"xxxx\", (string) network address\n"
384 " \"port\": xxx, (numeric) network port\n"
385 " \"score\": xxx (numeric) relative score\n"
386 " ]\n"
387 "}\n"
388 "\nExamples:\n"
389 + HelpExampleCli("getnetworkinfo", "")
390 + HelpExampleRpc("getnetworkinfo", "")
393 Object obj;
394 obj.push_back(Pair("version", (int)CLIENT_VERSION));
395 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
396 obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
397 obj.push_back(Pair("timeoffset", GetTimeOffset()));
398 obj.push_back(Pair("connections", (int)vNodes.size()));
399 obj.push_back(Pair("networks", GetNetworksInfo()));
400 obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
401 Array localAddresses;
403 LOCK(cs_mapLocalHost);
404 BOOST_FOREACH(const PAIRTYPE(CNetAddr, LocalServiceInfo) &item, mapLocalHost)
406 Object rec;
407 rec.push_back(Pair("address", item.first.ToString()));
408 rec.push_back(Pair("port", item.second.nPort));
409 rec.push_back(Pair("score", item.second.nScore));
410 localAddresses.push_back(rec);
413 obj.push_back(Pair("localaddresses", localAddresses));
414 return obj;