1 // Copyright (c) 2009-2012 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 "bitcoinrpc.h"
13 using namespace json_spirit;
16 Value getconnectioncount(const Array& params, bool fHelp)
18 if (fHelp || params.size() != 0)
20 "getconnectioncount\n"
21 "Returns the number of connections to other nodes.");
24 return (int)vNodes.size();
27 static void CopyNodeStats(std::vector<CNodeStats>& vstats)
32 vstats.reserve(vNodes.size());
33 BOOST_FOREACH(CNode* pnode, vNodes) {
35 pnode->copyStats(stats);
36 vstats.push_back(stats);
40 struct addrManItemSort {
41 bool operator()(const CAddrInfo &leftItem, const CAddrInfo &rightItem) {
42 int64_t nTime = GetTime();
43 return leftItem.GetChance(nTime) > rightItem.GetChance(nTime);
47 Value getaddrmaninfo(const Array& params, bool fHelp)
49 if (fHelp || params.size() > 1)
51 "getaddrmaninfo [networkType]\n"
52 "Returns a dump of addrman data.");
54 // Get a full list of "online" address items
55 vector<CAddrInfo> vAddr = addrman.GetOnlineAddr();
57 // Sort by the GetChance result backwardly
58 sort(vAddr.begin(), vAddr.end(), addrManItemSort());
60 string strFilterNetType = "";
61 if (params.size() == 1)
62 strFilterNetType = params[0].get_str();
65 BOOST_FOREACH(const CAddrInfo &addr, vAddr) {
66 if (!addr.IsRoutable() || addr.IsLocal())
70 addrManItem.push_back(Pair("address", addr.ToString()));
73 switch(addr.GetNetwork())
79 // strNetType = "i2p";
90 if (strFilterNetType.size() != 0 && strNetType != strFilterNetType)
93 addrManItem.push_back(Pair("chance", addr.GetChance(GetTime())));
94 addrManItem.push_back(Pair("type", strNetType));
95 addrManItem.push_back(Pair("time", (int64_t)addr.nTime));
97 ret.push_back(addrManItem);
103 Value getpeerinfo(const Array& params, bool fHelp)
105 if (fHelp || params.size() != 0)
108 "Returns data about each connected network node.");
110 vector<CNodeStats> vstats;
111 CopyNodeStats(vstats);
115 BOOST_FOREACH(const CNodeStats& stats, vstats) {
118 obj.push_back(Pair("addr", stats.addrName));
119 obj.push_back(Pair("services", strprintf("%08" PRIx64, stats.nServices)));
120 obj.push_back(Pair("lastsend", (int64_t)stats.nLastSend));
121 obj.push_back(Pair("lastrecv", (int64_t)stats.nLastRecv));
122 obj.push_back(Pair("bytessent", (int64_t)stats.nSendBytes));
123 obj.push_back(Pair("bytesrecv", (int64_t)stats.nRecvBytes));
124 obj.push_back(Pair("conntime", (int64_t)stats.nTimeConnected));
125 obj.push_back(Pair("version", stats.nVersion));
126 obj.push_back(Pair("subver", stats.strSubVer));
127 obj.push_back(Pair("inbound", stats.fInbound));
128 obj.push_back(Pair("releasetime", (int64_t)stats.nReleaseTime));
129 obj.push_back(Pair("startingheight", stats.nStartingHeight));
130 obj.push_back(Pair("banscore", stats.nMisbehavior));
132 obj.push_back(Pair("syncnode", true));
139 Value addnode(const Array& params, bool fHelp)
142 if (params.size() == 2)
143 strCommand = params[1].get_str();
144 if (fHelp || params.size() != 2 ||
145 (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
147 "addnode <node> <add|remove|onetry>\n"
148 "Attempts add or remove <node> from the addnode list or try a connection to <node> once.");
150 string strNode = params[0].get_str();
152 if (strCommand == "onetry")
155 OpenNetworkConnection(addr, NULL, strNode.c_str());
159 LOCK(cs_vAddedNodes);
160 vector<string>::iterator it = vAddedNodes.begin();
161 for(; it != vAddedNodes.end(); it++)
165 if (strCommand == "add")
167 if (it != vAddedNodes.end())
168 throw JSONRPCError(-23, "Error: Node already added");
169 vAddedNodes.push_back(strNode);
171 else if(strCommand == "remove")
173 if (it == vAddedNodes.end())
174 throw JSONRPCError(-24, "Error: Node has not been added.");
175 vAddedNodes.erase(it);
181 Value getaddednodeinfo(const Array& params, bool fHelp)
183 if (fHelp || params.size() < 1 || params.size() > 2)
185 "getaddednodeinfo <dns> [node]\n"
186 "Returns information about the given added node, or all added nodes\n"
187 "(note that onetry addnodes are not listed here)\n"
188 "If dns is false, only a list of added nodes will be provided,\n"
189 "otherwise connected information will also be available.");
191 bool fDns = params[0].get_bool();
193 list<string> laddedNodes(0);
194 if (params.size() == 1)
196 LOCK(cs_vAddedNodes);
197 BOOST_FOREACH(string& strAddNode, vAddedNodes)
198 laddedNodes.push_back(strAddNode);
202 string strNode = params[1].get_str();
203 LOCK(cs_vAddedNodes);
204 BOOST_FOREACH(string& strAddNode, vAddedNodes)
205 if (strAddNode == strNode)
207 laddedNodes.push_back(strAddNode);
210 if (laddedNodes.size() == 0)
211 throw JSONRPCError(-24, "Error: Node has not been added.");
217 BOOST_FOREACH(string& strAddNode, laddedNodes)
218 ret.push_back(Pair("addednode", strAddNode));
224 list<pair<string, vector<CService> > > laddedAddreses(0);
225 BOOST_FOREACH(string& strAddNode, laddedNodes)
227 vector<CService> vservNode(0);
228 if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
229 laddedAddreses.push_back(make_pair(strAddNode, vservNode));
233 obj.push_back(Pair("addednode", strAddNode));
234 obj.push_back(Pair("connected", false));
236 obj.push_back(Pair("addresses", addresses));
241 for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
244 obj.push_back(Pair("addednode", it->first));
247 bool fConnected = false;
248 BOOST_FOREACH(CService& addrNode, it->second)
252 node.push_back(Pair("address", addrNode.ToString()));
253 BOOST_FOREACH(CNode* pnode, vNodes)
254 if (pnode->addr == addrNode)
258 node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
262 node.push_back(Pair("connected", "false"));
263 addresses.push_back(node);
265 obj.push_back(Pair("connected", fConnected));
266 obj.push_back(Pair("addresses", addresses));
273 // There is a known deadlock situation with ThreadMessageHandler
274 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
275 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
276 Value sendalert(const Array& params, bool fHelp)
278 if (fHelp || params.size() < 6)
280 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
281 "<message> is the alert text message\n"
282 "<privatekey> is hex string of alert master private key\n"
283 "<minver> is the minimum applicable internal client version\n"
284 "<maxver> is the maximum applicable internal client version\n"
285 "<priority> is integer priority number\n"
286 "<id> is the alert id\n"
287 "[cancelupto] cancels all alert id's up to this number\n"
288 "Returns true or false.");
293 alert.strStatusBar = params[0].get_str();
294 alert.nMinVer = params[2].get_int();
295 alert.nMaxVer = params[3].get_int();
296 alert.nPriority = params[4].get_int();
297 alert.nID = params[5].get_int();
298 if (params.size() > 6)
299 alert.nCancel = params[6].get_int();
300 alert.nVersion = PROTOCOL_VERSION;
301 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
302 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
304 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
305 sMsg << (CUnsignedAlert)alert;
306 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
308 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
309 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
310 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
312 "Unable to sign alert, check private key?\n");
313 if(!alert.ProcessAlert())
315 "Failed to process alert.\n");
319 BOOST_FOREACH(CNode* pnode, vNodes)
320 alert.RelayTo(pnode);
324 result.push_back(Pair("strStatusBar", alert.strStatusBar));
325 result.push_back(Pair("nVersion", alert.nVersion));
326 result.push_back(Pair("nMinVer", alert.nMinVer));
327 result.push_back(Pair("nMaxVer", alert.nMaxVer));
328 result.push_back(Pair("nPriority", alert.nPriority));
329 result.push_back(Pair("nID", alert.nID));
330 if (alert.nCancel > 0)
331 result.push_back(Pair("nCancel", alert.nCancel));
335 Value getnettotals(const Array& params, bool fHelp)
337 if (fHelp || params.size() > 0)
340 "Returns information about network traffic, including bytes in, bytes out,\n"
341 "and current time.");
344 obj.push_back(Pair("totalbytesrecv", static_cast<uint64_t>(CNode::GetTotalBytesRecv())));
345 obj.push_back(Pair("totalbytessent", static_cast<uint64_t>(CNode::GetTotalBytesSent())));
346 obj.push_back(Pair("timemillis", static_cast<int64_t>(GetTimeMillis())));
354 "epoch" : 1442494427,
355 "time" : "2015-09-17 12:53:47 UTC"
358 05:53:56 ntptime time.windows.com
361 "epoch" : 1442494436,
362 "time" : "2015-09-17 12:53:56 UTC"
365 05:54:33 ntptime time-a.nist.gov
368 "epoch" : 1442494473,
369 "time" : "2015-09-17 12:54:33 UTC"
372 Value ntptime(const Array& params, bool fHelp)
374 if (fHelp || params.size() > 1)
376 "ntptime [ntpserver]\n"
377 "Returns current time from specific or random NTP server.");
380 if (params.size() > 0) {
381 string strHostName = params[0].get_str();
382 nTime = NtpGetTime(strHostName);
386 nTime = NtpGetTime(ip);
392 throw runtime_error("Socket initialization error");
394 throw runtime_error("Switching socket mode to non-blocking failed");
396 throw runtime_error("Unable to send data");
398 throw runtime_error("Receive timed out");
400 if (nTime > 0 && nTime != 2085978496) {
401 obj.push_back(Pair("epoch", nTime));
402 obj.push_back(Pair("time", DateTimeStrFormat(nTime)));
404 else throw runtime_error("Unexpected response");