1ce14cd2ed260acfc3ef4887e6758ef729e5362a
[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
12 using namespace json_spirit;
13 using namespace std;
14
15 Value getconnectioncount(const Array& params, bool fHelp)
16 {
17     if (fHelp || params.size() != 0)
18         throw runtime_error(
19             "getconnectioncount\n"
20             "Returns the number of connections to other nodes.");
21
22     LOCK(cs_vNodes);
23     return (int)vNodes.size();
24 }
25
26 static void CopyNodeStats(std::vector<CNodeStats>& vstats)
27 {
28     vstats.clear();
29
30     LOCK(cs_vNodes);
31     vstats.reserve(vNodes.size());
32     BOOST_FOREACH(CNode* pnode, vNodes) {
33         CNodeStats stats;
34         pnode->copyStats(stats);
35         vstats.push_back(stats);
36     }
37 }
38
39 struct addrManItemSort {
40     bool operator()(const CAddrInfo &leftItem, const CAddrInfo &rightItem) {
41         int64_t nTime = GetTime();
42         return leftItem.GetChance(nTime) > rightItem.GetChance(nTime);
43     }
44 };
45
46 Value getaddrmaninfo(const Array& params, bool fHelp)
47 {
48     if (fHelp || params.size() > 1)
49         throw runtime_error(
50             "getaddrmaninfo [networkType]\n"
51             "Returns a dump of addrman data.");
52
53     // Get a full list of "online" address items
54     vector<CAddrInfo> vAddr = addrman.GetOnlineAddr();
55
56     // Sort by the GetChance result backwardly
57     sort(vAddr.begin(), vAddr.end(), addrManItemSort());
58
59     string strFilterNetType = "ipv4";
60     if (params.size() == 1)
61         strFilterNetType = params[0].get_str();
62
63     Array ret;
64     BOOST_FOREACH(const CAddrInfo &addr, vAddr) {
65         if (!addr.IsRoutable() || addr.IsLocal())
66             continue;
67
68         Object addrManItem;
69         addrManItem.push_back(Pair("address", addr.ToString()));
70
71         string strNetType;
72         switch(addr.GetNetwork())
73         {
74 //            case NET_TOR:
75 //                strNetType = "tor";
76 //            break;
77 //            case NET_I2P:
78 //                strNetType = "i2p";
79 //            break;
80             case NET_IPV6:
81                 strNetType = "ipv6";
82             break;
83             default:
84             case NET_IPV4:
85                 strNetType = "ipv4";
86
87         }
88
89         if (strNetType != strFilterNetType)
90             continue;
91
92         addrManItem.push_back(Pair("chance", addr.GetChance(GetTime())));
93         addrManItem.push_back(Pair("type", strNetType));
94         addrManItem.push_back(Pair("time", (int64_t)addr.nTime));
95
96         ret.push_back(addrManItem);
97     }
98
99     return ret;
100 }
101
102 Value getpeerinfo(const Array& params, bool fHelp)
103 {
104     if (fHelp || params.size() != 0)
105         throw runtime_error(
106             "getpeerinfo\n"
107             "Returns data about each connected network node.");
108
109     vector<CNodeStats> vstats;
110     CopyNodeStats(vstats);
111
112     Array ret;
113
114     BOOST_FOREACH(const CNodeStats& stats, vstats) {
115         Object obj;
116
117         obj.push_back(Pair("addr", stats.addrName));
118         obj.push_back(Pair("services", strprintf("%08" PRIx64, stats.nServices)));
119         obj.push_back(Pair("lastsend", (boost::int64_t)stats.nLastSend));
120         obj.push_back(Pair("lastrecv", (boost::int64_t)stats.nLastRecv));
121         obj.push_back(Pair("bytessent", (boost::int64_t)stats.nSendBytes));
122         obj.push_back(Pair("bytesrecv", (boost::int64_t)stats.nRecvBytes));
123         obj.push_back(Pair("conntime", (boost::int64_t)stats.nTimeConnected));
124         obj.push_back(Pair("version", stats.nVersion));
125         obj.push_back(Pair("subver", stats.strSubVer));
126         obj.push_back(Pair("inbound", stats.fInbound));
127         obj.push_back(Pair("releasetime", (boost::int64_t)stats.nReleaseTime));
128         obj.push_back(Pair("startingheight", stats.nStartingHeight));
129         obj.push_back(Pair("banscore", stats.nMisbehavior));
130         if (stats.fSyncNode)
131             obj.push_back(Pair("syncnode", true));
132         ret.push_back(obj);
133     }
134
135     return ret;
136 }
137
138 Value addnode(const Array& params, bool fHelp)
139 {
140     string strCommand;
141     if (params.size() == 2)
142         strCommand = params[1].get_str();
143     if (fHelp || params.size() != 2 ||
144         (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
145         throw runtime_error(
146             "addnode <node> <add|remove|onetry>\n"
147             "Attempts add or remove <node> from the addnode list or try a connection to <node> once.");
148
149     string strNode = params[0].get_str();
150
151     if (strCommand == "onetry")
152     {
153         CAddress addr;
154         OpenNetworkConnection(addr, NULL, strNode.c_str());
155         return Value::null;
156     }
157
158     LOCK(cs_vAddedNodes);
159     vector<string>::iterator it = vAddedNodes.begin();
160     for(; it != vAddedNodes.end(); it++)
161         if (strNode == *it)
162             break;
163
164     if (strCommand == "add")
165     {
166         if (it != vAddedNodes.end())
167             throw JSONRPCError(-23, "Error: Node already added");
168         vAddedNodes.push_back(strNode);
169     }
170     else if(strCommand == "remove")
171     {
172         if (it == vAddedNodes.end())
173             throw JSONRPCError(-24, "Error: Node has not been added.");
174         vAddedNodes.erase(it);
175     }
176
177     return Value::null;
178 }
179
180 Value getaddednodeinfo(const Array& params, bool fHelp)
181 {
182     if (fHelp || params.size() < 1 || params.size() > 2)
183         throw runtime_error(
184             "getaddednodeinfo <dns> [node]\n"
185             "Returns information about the given added node, or all added nodes\n"
186             "(note that onetry addnodes are not listed here)\n"
187             "If dns is false, only a list of added nodes will be provided,\n"
188             "otherwise connected information will also be available.");
189
190     bool fDns = params[0].get_bool();
191
192     list<string> laddedNodes(0);
193     if (params.size() == 1)
194     {
195         LOCK(cs_vAddedNodes);
196         BOOST_FOREACH(string& strAddNode, vAddedNodes)
197             laddedNodes.push_back(strAddNode);
198     }
199     else
200     {
201         string strNode = params[1].get_str();
202         LOCK(cs_vAddedNodes);
203         BOOST_FOREACH(string& strAddNode, vAddedNodes)
204             if (strAddNode == strNode)
205             {
206                 laddedNodes.push_back(strAddNode);
207                 break;
208             }
209         if (laddedNodes.size() == 0)
210             throw JSONRPCError(-24, "Error: Node has not been added.");
211         }
212
213         if (!fDns)
214         {
215             Object ret;
216             BOOST_FOREACH(string& strAddNode, laddedNodes)
217                 ret.push_back(Pair("addednode", strAddNode));
218             return ret;
219         }
220
221         Array ret;
222
223         list<pair<string, vector<CService> > > laddedAddreses(0);
224         BOOST_FOREACH(string& strAddNode, laddedNodes)
225         {
226             vector<CService> vservNode(0);
227             if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
228                 laddedAddreses.push_back(make_pair(strAddNode, vservNode));
229             else
230             {
231                 Object obj;
232                 obj.push_back(Pair("addednode", strAddNode));
233                 obj.push_back(Pair("connected", false));
234                 Array addresses;
235                 obj.push_back(Pair("addresses", addresses));
236             }
237         }
238
239     LOCK(cs_vNodes);
240     for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
241     {
242         Object obj;
243         obj.push_back(Pair("addednode", it->first));
244
245         Array addresses;
246         bool fConnected = false;
247         BOOST_FOREACH(CService& addrNode, it->second)
248         {
249             bool fFound = false;
250             Object node;
251             node.push_back(Pair("address", addrNode.ToString()));
252             BOOST_FOREACH(CNode* pnode, vNodes)
253                 if (pnode->addr == addrNode)
254                 {
255                     fFound = true;
256                     fConnected = true;
257                     node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
258                     break;
259                 }
260             if (!fFound)
261                 node.push_back(Pair("connected", "false"));
262             addresses.push_back(node);
263         }
264         obj.push_back(Pair("connected", fConnected));
265         obj.push_back(Pair("addresses", addresses));
266         ret.push_back(obj);
267     }
268
269     return ret;
270 }
271
272 extern CCriticalSection cs_mapAlerts;
273 extern map<uint256, CAlert> mapAlerts;
274  
275 // ppcoin: send alert.  
276 // There is a known deadlock situation with ThreadMessageHandler
277 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
278 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
279 Value sendalert(const Array& params, bool fHelp)
280 {
281     if (fHelp || params.size() < 6)
282         throw runtime_error(
283             "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
284             "<message> is the alert text message\n"
285             "<privatekey> is hex string of alert master private key\n"
286             "<minver> is the minimum applicable internal client version\n"
287             "<maxver> is the maximum applicable internal client version\n"
288             "<priority> is integer priority number\n"
289             "<id> is the alert id\n"
290             "[cancelupto] cancels all alert id's up to this number\n"
291             "Returns true or false.");
292
293     CAlert alert;
294     CKey key;
295
296     alert.strStatusBar = params[0].get_str();
297     alert.nMinVer = params[2].get_int();
298     alert.nMaxVer = params[3].get_int();
299     alert.nPriority = params[4].get_int();
300     alert.nID = params[5].get_int();
301     if (params.size() > 6)
302         alert.nCancel = params[6].get_int();
303     alert.nVersion = PROTOCOL_VERSION;
304     alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
305     alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
306
307     CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
308     sMsg << (CUnsignedAlert)alert;
309     alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
310
311     vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
312     key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
313     if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
314         throw runtime_error(
315             "Unable to sign alert, check private key?\n");  
316     if(!alert.ProcessAlert()) 
317         throw runtime_error(
318             "Failed to process alert.\n");
319     // Relay alert
320     {
321         LOCK(cs_vNodes);
322         BOOST_FOREACH(CNode* pnode, vNodes)
323             alert.RelayTo(pnode);
324     }
325
326     Object result;
327     result.push_back(Pair("strStatusBar", alert.strStatusBar));
328     result.push_back(Pair("nVersion", alert.nVersion));
329     result.push_back(Pair("nMinVer", alert.nMinVer));
330     result.push_back(Pair("nMaxVer", alert.nMaxVer));
331     result.push_back(Pair("nPriority", alert.nPriority));
332     result.push_back(Pair("nID", alert.nID));
333     if (alert.nCancel > 0)
334         result.push_back(Pair("nCancel", alert.nCancel));
335     return result;
336 }
337
338 Value getnettotals(const Array& params, bool fHelp)
339 {
340     if (fHelp || params.size() > 0)
341         throw runtime_error(
342             "getnettotals\n"
343             "Returns information about network traffic, including bytes in, bytes out,\n"
344             "and current time.");
345
346     Object obj;
347     obj.push_back(Pair("totalbytesrecv", static_cast< boost::uint64_t>(CNode::GetTotalBytesRecv())));
348     obj.push_back(Pair("totalbytessent", static_cast<boost::uint64_t>(CNode::GetTotalBytesSent())));
349     obj.push_back(Pair("timemillis", static_cast<boost::int64_t>(GetTimeMillis())));
350     return obj;
351 }