Merge branch 'master' of github.com:novacoin-project/novacoin
[novacoin.git] / src / rpcnet.cpp
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.
4
5 #include "bitcoinrpc.h"
6 #include "alert.h"
7 #include "wallet.h"
8 #include "db.h"
9 #include "walletdb.h"
10 #include "net.h"
11 #include "ntp.h"
12
13 using namespace json_spirit;
14 using namespace std;
15
16 Value getconnectioncount(const Array& params, bool fHelp)
17 {
18     if (fHelp || params.size() != 0)
19         throw runtime_error(
20             "getconnectioncount\n"
21             "Returns the number of connections to other nodes.");
22
23     LOCK(cs_vNodes);
24     return (int)vNodes.size();
25 }
26
27 static void CopyNodeStats(std::vector<CNodeStats>& vstats)
28 {
29     vstats.clear();
30
31     LOCK(cs_vNodes);
32     vstats.reserve(vNodes.size());
33     BOOST_FOREACH(CNode* pnode, vNodes) {
34         CNodeStats stats;
35         pnode->copyStats(stats);
36         vstats.push_back(stats);
37     }
38 }
39
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);
44     }
45 };
46
47 Value getaddrmaninfo(const Array& params, bool fHelp)
48 {
49     if (fHelp || params.size() > 1)
50         throw runtime_error(
51             "getaddrmaninfo [networkType]\n"
52             "Returns a dump of addrman data.");
53
54     // Get a full list of "online" address items
55     vector<CAddrInfo> vAddr = addrman.GetOnlineAddr();
56
57     // Sort by the GetChance result backwardly
58     sort(vAddr.begin(), vAddr.end(), addrManItemSort());
59
60     string strFilterNetType = "";
61     if (params.size() == 1)
62         strFilterNetType = params[0].get_str();
63
64     Array ret;
65     BOOST_FOREACH(const CAddrInfo &addr, vAddr) {
66         if (!addr.IsRoutable() || addr.IsLocal())
67             continue;
68
69         Object addrManItem;
70         addrManItem.push_back(Pair("address", addr.ToString()));
71
72         string strNetType;
73         switch(addr.GetNetwork())
74         {
75             case NET_TOR:
76                 strNetType = "tor";
77             break;
78 //            case NET_I2P:
79 //                strNetType = "i2p";
80 //            break;
81             case NET_IPV6:
82                 strNetType = "ipv6";
83             break;
84             default:
85             case NET_IPV4:
86                 strNetType = "ipv4";
87
88         }
89
90         if (strFilterNetType.size() != 0 && strNetType != strFilterNetType)
91             continue;
92
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));
96
97         ret.push_back(addrManItem);
98     }
99
100     return ret;
101 }
102
103 Value getpeerinfo(const Array& params, bool fHelp)
104 {
105     if (fHelp || params.size() != 0)
106         throw runtime_error(
107             "getpeerinfo\n"
108             "Returns data about each connected network node.");
109
110     vector<CNodeStats> vstats;
111     CopyNodeStats(vstats);
112
113     Array ret;
114
115     BOOST_FOREACH(const CNodeStats& stats, vstats) {
116         Object obj;
117
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));
131         if (stats.fSyncNode)
132             obj.push_back(Pair("syncnode", true));
133         ret.push_back(obj);
134     }
135
136     return ret;
137 }
138
139 Value addnode(const Array& params, bool fHelp)
140 {
141     string strCommand;
142     if (params.size() == 2)
143         strCommand = params[1].get_str();
144     if (fHelp || params.size() != 2 ||
145         (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
146         throw runtime_error(
147             "addnode <node> <add|remove|onetry>\n"
148             "Attempts add or remove <node> from the addnode list or try a connection to <node> once.");
149
150     string strNode = params[0].get_str();
151
152     if (strCommand == "onetry")
153     {
154         CAddress addr;
155         OpenNetworkConnection(addr, NULL, strNode.c_str());
156         return Value::null;
157     }
158
159     LOCK(cs_vAddedNodes);
160     vector<string>::iterator it = vAddedNodes.begin();
161     for(; it != vAddedNodes.end(); it++)
162         if (strNode == *it)
163             break;
164
165     if (strCommand == "add")
166     {
167         if (it != vAddedNodes.end())
168             throw JSONRPCError(-23, "Error: Node already added");
169         vAddedNodes.push_back(strNode);
170     }
171     else if(strCommand == "remove")
172     {
173         if (it == vAddedNodes.end())
174             throw JSONRPCError(-24, "Error: Node has not been added.");
175         vAddedNodes.erase(it);
176     }
177
178     return Value::null;
179 }
180
181 Value getaddednodeinfo(const Array& params, bool fHelp)
182 {
183     if (fHelp || params.size() < 1 || params.size() > 2)
184         throw runtime_error(
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.");
190
191     bool fDns = params[0].get_bool();
192
193     list<string> laddedNodes(0);
194     if (params.size() == 1)
195     {
196         LOCK(cs_vAddedNodes);
197         BOOST_FOREACH(string& strAddNode, vAddedNodes)
198             laddedNodes.push_back(strAddNode);
199     }
200     else
201     {
202         string strNode = params[1].get_str();
203         LOCK(cs_vAddedNodes);
204         BOOST_FOREACH(string& strAddNode, vAddedNodes)
205             if (strAddNode == strNode)
206             {
207                 laddedNodes.push_back(strAddNode);
208                 break;
209             }
210         if (laddedNodes.size() == 0)
211             throw JSONRPCError(-24, "Error: Node has not been added.");
212         }
213
214         if (!fDns)
215         {
216             Object ret;
217             BOOST_FOREACH(string& strAddNode, laddedNodes)
218                 ret.push_back(Pair("addednode", strAddNode));
219             return ret;
220         }
221
222         Array ret;
223
224         list<pair<string, vector<CService> > > laddedAddreses(0);
225         BOOST_FOREACH(string& strAddNode, laddedNodes)
226         {
227             vector<CService> vservNode(0);
228             if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
229                 laddedAddreses.push_back(make_pair(strAddNode, vservNode));
230             else
231             {
232                 Object obj;
233                 obj.push_back(Pair("addednode", strAddNode));
234                 obj.push_back(Pair("connected", false));
235                 Array addresses;
236                 obj.push_back(Pair("addresses", addresses));
237             }
238         }
239
240     LOCK(cs_vNodes);
241     for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
242     {
243         Object obj;
244         obj.push_back(Pair("addednode", it->first));
245
246         Array addresses;
247         bool fConnected = false;
248         BOOST_FOREACH(CService& addrNode, it->second)
249         {
250             bool fFound = false;
251             Object node;
252             node.push_back(Pair("address", addrNode.ToString()));
253             BOOST_FOREACH(CNode* pnode, vNodes)
254                 if (pnode->addr == addrNode)
255                 {
256                     fFound = true;
257                     fConnected = true;
258                     node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
259                     break;
260                 }
261             if (!fFound)
262                 node.push_back(Pair("connected", "false"));
263             addresses.push_back(node);
264         }
265         obj.push_back(Pair("connected", fConnected));
266         obj.push_back(Pair("addresses", addresses));
267         ret.push_back(obj);
268     }
269
270     return ret;
271 }
272
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)
277 {
278     if (fHelp || params.size() < 6)
279         throw runtime_error(
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.");
289
290     CAlert alert;
291     CKey key;
292
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;
303
304     CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
305     sMsg << (CUnsignedAlert)alert;
306     alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
307
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))
311         throw runtime_error(
312             "Unable to sign alert, check private key?\n");  
313     if(!alert.ProcessAlert()) 
314         throw runtime_error(
315             "Failed to process alert.\n");
316     // Relay alert
317     {
318         LOCK(cs_vNodes);
319         BOOST_FOREACH(CNode* pnode, vNodes)
320             alert.RelayTo(pnode);
321     }
322
323     Object result;
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));
332     return result;
333 }
334
335 Value getnettotals(const Array& params, bool fHelp)
336 {
337     if (fHelp || params.size() > 0)
338         throw runtime_error(
339             "getnettotals\n"
340             "Returns information about network traffic, including bytes in, bytes out,\n"
341             "and current time.");
342
343     Object obj;
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())));
347     return obj;
348 }
349
350 /*
351 05:53:45 ntptime
352 05:53:48
353 {
354 "epoch" : 1442494427,
355 "time" : "2015-09-17 12:53:47 UTC"
356 }
357
358 05:53:56 ntptime time.windows.com
359 05:53:57
360 {
361 "epoch" : 1442494436,
362 "time" : "2015-09-17 12:53:56 UTC"
363 }
364
365 05:54:33 ntptime time-a.nist.gov
366 05:54:34
367 {
368 "epoch" : 1442494473,
369 "time" : "2015-09-17 12:54:33 UTC"
370 }*/
371
372 Value ntptime(const Array& params, bool fHelp)
373 {
374     if (fHelp || params.size() > 1)
375         throw runtime_error(
376             "ntptime [ntpserver]\n"
377             "Returns current time from specific or random NTP server.");
378
379     int64_t nTime;
380     if (params.size() > 0) {
381         string strHostName = params[0].get_str();
382         nTime = NtpGetTime(strHostName);
383     }
384     else {
385         CNetAddr ip;
386         nTime = NtpGetTime(ip);
387     }
388
389     Object obj;
390     switch (nTime) {
391     case -1:
392         throw runtime_error("Socket initialization error");
393     case -2:
394         throw runtime_error("Switching socket mode to non-blocking failed");
395     case -3:
396         throw runtime_error("Unable to send data");
397     case -4:
398         throw runtime_error("Receive timed out");
399     default:
400         if (nTime > 0 && nTime != 2085978496) {
401             obj.push_back(Pair("epoch", nTime));
402             obj.push_back(Pair("time", DateTimeStrFormat(nTime)));
403         }
404         else throw runtime_error("Unexpected response");
405     }
406
407     return obj;
408 }