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