// Copyright (c) 2009-2012 Bitcoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "rpcserver.h" #include "alert.h" #include "main.h" #include "net.h" #include "netbase.h" #include "protocol.h" #include "sync.h" #include "timedata.h" #include "util.h" #include #include "json/json_spirit_value.h" using namespace json_spirit; using namespace std; Value getconnectioncount(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getconnectioncount\n" "Returns the number of connections to other nodes."); LOCK(cs_vNodes); return (int)vNodes.size(); } Value ping(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "ping\n" "Requests that a ping be sent to all other nodes, to measure ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping."); // Request that each node send a ping during next message processing pass LOCK(cs_vNodes); BOOST_FOREACH(CNode* pNode, vNodes) { pNode->fPingQueued = true; } return Value::null; } static void CopyNodeStats(std::vector& vstats) { vstats.clear(); LOCK(cs_vNodes); vstats.reserve(vNodes.size()); BOOST_FOREACH(CNode* pnode, vNodes) { CNodeStats stats; pnode->copyStats(stats); vstats.push_back(stats); } } Value getpeerinfo(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getpeerinfo\n" "Returns data about each connected network node."); vector vstats; CopyNodeStats(vstats); Array ret; BOOST_FOREACH(const CNodeStats& stats, vstats) { Object obj; obj.push_back(Pair("addr", stats.addrName)); if (!(stats.addrLocal.empty())) obj.push_back(Pair("addrlocal", stats.addrLocal)); obj.push_back(Pair("services", strprintf("%08x", stats.nServices))); obj.push_back(Pair("lastsend", (int64_t)stats.nLastSend)); obj.push_back(Pair("lastrecv", (int64_t)stats.nLastRecv)); obj.push_back(Pair("bytessent", (int64_t)stats.nSendBytes)); obj.push_back(Pair("bytesrecv", (int64_t)stats.nRecvBytes)); obj.push_back(Pair("conntime", (int64_t)stats.nTimeConnected)); obj.push_back(Pair("timeoffset", stats.nTimeOffset)); obj.push_back(Pair("pingtime", stats.dPingTime)); if (stats.dPingWait > 0.0) obj.push_back(Pair("pingwait", stats.dPingWait)); obj.push_back(Pair("version", stats.nVersion)); obj.push_back(Pair("subver", stats.strSubVer)); obj.push_back(Pair("inbound", stats.fInbound)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); obj.push_back(Pair("banscore", stats.nMisbehavior)); obj.push_back(Pair("syncnode", stats.fSyncNode)); ret.push_back(obj); } return ret; } Value addnode(const Array& params, bool fHelp) { string strCommand; if (params.size() == 2) strCommand = params[1].get_str(); if (fHelp || params.size() != 2 || (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) throw runtime_error( "addnode \n" "Attempts add or remove from the addnode list or try a connection to once."); string strNode = params[0].get_str(); if (strCommand == "onetry") { CAddress addr; ConnectNode(addr, strNode.c_str()); return Value::null; } LOCK(cs_vAddedNodes); vector::iterator it = vAddedNodes.begin(); for(; it != vAddedNodes.end(); it++) if (strNode == *it) break; if (strCommand == "add") { if (it != vAddedNodes.end()) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); vAddedNodes.push_back(strNode); } else if(strCommand == "remove") { if (it == vAddedNodes.end()) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); vAddedNodes.erase(it); } return Value::null; } Value getaddednodeinfo(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getaddednodeinfo [node]\n" "Returns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n" "If dns is false, only a list of added nodes will be provided,\n" "otherwise connected information will also be available."); bool fDns = params[0].get_bool(); list laddedNodes(0); if (params.size() == 1) { LOCK(cs_vAddedNodes); BOOST_FOREACH(string& strAddNode, vAddedNodes) laddedNodes.push_back(strAddNode); } else { string strNode = params[1].get_str(); LOCK(cs_vAddedNodes); BOOST_FOREACH(string& strAddNode, vAddedNodes) if (strAddNode == strNode) { laddedNodes.push_back(strAddNode); break; } if (laddedNodes.size() == 0) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } if (!fDns) { Object ret; BOOST_FOREACH(string& strAddNode, laddedNodes) ret.push_back(Pair("addednode", strAddNode)); return ret; } Array ret; list > > laddedAddreses(0); BOOST_FOREACH(string& strAddNode, laddedNodes) { vector vservNode(0); if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) laddedAddreses.push_back(make_pair(strAddNode, vservNode)); else { Object obj; obj.push_back(Pair("addednode", strAddNode)); obj.push_back(Pair("connected", false)); Array addresses; obj.push_back(Pair("addresses", addresses)); } } LOCK(cs_vNodes); for (list > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) { Object obj; obj.push_back(Pair("addednode", it->first)); Array addresses; bool fConnected = false; BOOST_FOREACH(CService& addrNode, it->second) { bool fFound = false; Object node; node.push_back(Pair("address", addrNode.ToString())); BOOST_FOREACH(CNode* pnode, vNodes) if (pnode->addr == addrNode) { fFound = true; fConnected = true; node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound")); break; } if (!fFound) node.push_back(Pair("connected", "false")); addresses.push_back(node); } obj.push_back(Pair("connected", fConnected)); obj.push_back(Pair("addresses", addresses)); ret.push_back(obj); } return ret; } // ppcoin: send alert. // There is a known deadlock situation with ThreadMessageHandler // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages() // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage() Value sendalert(const Array& params, bool fHelp) { if (fHelp || params.size() < 6) throw runtime_error( "sendalert [cancelupto]\n" " is the alert text message\n" " is hex string of alert master private key\n" " is the minimum applicable internal client version\n" " is the maximum applicable internal client version\n" " is integer priority number\n" " is the alert id\n" "[cancelupto] cancels all alert id's up to this number\n" "Returns true or false."); CAlert alert; CKey key; alert.strStatusBar = params[0].get_str(); alert.nMinVer = params[2].get_int(); alert.nMaxVer = params[3].get_int(); alert.nPriority = params[4].get_int(); alert.nID = params[5].get_int(); if (params.size() > 6) alert.nCancel = params[6].get_int(); alert.nVersion = PROTOCOL_VERSION; alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60; alert.nExpiration = GetAdjustedTime() + 365*24*60*60; CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); sMsg << (CUnsignedAlert)alert; alert.vchMsg = vector(sMsg.begin(), sMsg.end()); vector vchPrivKey = ParseHex(params[1].get_str()); key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end()), false); // if key is not correct openssl may crash if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig)) throw runtime_error( "Unable to sign alert, check private key?\n"); if(!alert.ProcessAlert()) throw runtime_error( "Failed to process alert.\n"); // Relay alert { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) alert.RelayTo(pnode); } Object result; result.push_back(Pair("strStatusBar", alert.strStatusBar)); result.push_back(Pair("nVersion", alert.nVersion)); result.push_back(Pair("nMinVer", alert.nMinVer)); result.push_back(Pair("nMaxVer", alert.nMaxVer)); result.push_back(Pair("nPriority", alert.nPriority)); result.push_back(Pair("nID", alert.nID)); if (alert.nCancel > 0) result.push_back(Pair("nCancel", alert.nCancel)); return result; } Value getnettotals(const Array& params, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( "getnettotals\n" "Returns information about network traffic, including bytes in, bytes out,\n" "and current time."); Object obj; obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); return obj; }