aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qa/rpc-tests/README.md5
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py1
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py1
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py1
-rwxr-xr-xqa/rpc-tests/sendheaders.py1
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py1
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py24
-rw-r--r--src/net.cpp29
-rw-r--r--src/net.h28
-rw-r--r--src/rpcnet.cpp22
10 files changed, 69 insertions, 44 deletions
diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md
index 898931936b..651b01f18a 100644
--- a/qa/rpc-tests/README.md
+++ b/qa/rpc-tests/README.md
@@ -47,10 +47,7 @@ implements the test logic.
* ```NodeConn``` is the class used to connect to a bitcoind. If you implement
a callback class that derives from ```NodeConnCB``` and pass that to the
```NodeConn``` object, your code will receive the appropriate callbacks when
-events of interest arrive. NOTE: be sure to call
-```self.create_callback_map()``` in your derived classes' ```__init__```
-function, so that the correct mappings are set up between p2p messages and your
-callback functions.
+events of interest arrive.
* You can pass the same handler to multiple ```NodeConn```'s if you like, or pass
different ones to each -- whatever makes the most sense for your test.
diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py
index a601147ce8..1a9ae480ab 100755
--- a/qa/rpc-tests/maxblocksinflight.py
+++ b/qa/rpc-tests/maxblocksinflight.py
@@ -34,7 +34,6 @@ class TestManager(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
self.log = logging.getLogger("BlockRelayTest")
- self.create_callback_map()
def add_new_connection(self, connection):
self.connection = connection
diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index e714465db1..249663779c 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -25,7 +25,6 @@ if uploadtarget has been reached.
class TestNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py
index 700deab207..23872d8494 100755
--- a/qa/rpc-tests/p2p-acceptblock.py
+++ b/qa/rpc-tests/p2p-acceptblock.py
@@ -62,7 +62,6 @@ The test:
class TestNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py
index 63e071805a..e6e26dbce3 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/qa/rpc-tests/sendheaders.py
@@ -70,7 +70,6 @@ f. Announce 1 more header that builds on that fork.
class BaseNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.connection = None
self.last_inv = None
self.last_headers = None
diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py
index e0b3ce040d..9444424dcf 100755
--- a/qa/rpc-tests/test_framework/comptool.py
+++ b/qa/rpc-tests/test_framework/comptool.py
@@ -45,7 +45,6 @@ class TestNode(NodeConnCB):
def __init__(self, block_store, tx_store):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.conn = None
self.bestblockhash = None
self.block_store = block_store
diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py
index 64985d58e2..9d0fb713a1 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/qa/rpc-tests/test_framework/mininode.py
@@ -1015,32 +1015,10 @@ class NodeConnCB(object):
return
time.sleep(0.05)
- # Derived classes should call this function once to set the message map
- # which associates the derived classes' functions to incoming messages
- def create_callback_map(self):
- self.cbmap = {
- "version": self.on_version,
- "verack": self.on_verack,
- "addr": self.on_addr,
- "alert": self.on_alert,
- "inv": self.on_inv,
- "getdata": self.on_getdata,
- "getblocks": self.on_getblocks,
- "tx": self.on_tx,
- "block": self.on_block,
- "getaddr": self.on_getaddr,
- "ping": self.on_ping,
- "pong": self.on_pong,
- "headers": self.on_headers,
- "getheaders": self.on_getheaders,
- "reject": self.on_reject,
- "mempool": self.on_mempool
- }
-
def deliver(self, conn, message):
with mininode_lock:
try:
- self.cbmap[message.command](conn, message)
+ getattr(self, 'on_' + message.command)(conn, message)
except:
print "ERROR delivering %s (%s)" % (repr(message),
sys.exc_info()[0])
diff --git a/src/net.cpp b/src/net.cpp
index a8aa97feec..159d44cba1 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -67,6 +67,16 @@ namespace {
};
}
+//immutable thread safe array of allowed commands for logging inbound traffic
+const static std::string logAllowIncomingMsgCmds[] = {
+ "version", "addr", "inv", "getdata", "merkleblock",
+ "getblocks", "getheaders", "tx", "headers", "block",
+ "getaddr", "mempool", "ping", "pong", "alert", "notfound",
+ "filterload", "filteradd", "filterclear", "reject",
+ "sendheaders", "verack"};
+
+const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
+
//
// Global state variables
//
@@ -627,7 +637,9 @@ void CNode::copyStats(CNodeStats &stats)
X(fInbound);
X(nStartingHeight);
X(nSendBytes);
+ X(mapSendBytesPerMsgCmd);
X(nRecvBytes);
+ X(mapRecvBytesPerMsgCmd);
X(fWhitelisted);
// It is common for nodes with good ping times to suddenly become lagged,
@@ -682,6 +694,15 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
nBytes -= handled;
if (msg.complete()) {
+
+ //store received bytes per message command
+ //to prevent a memory DOS, only allow valid commands
+ mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand);
+ if (i == mapRecvBytesPerMsgCmd.end())
+ i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);
+ assert(i != mapRecvBytesPerMsgCmd.end());
+ i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
+
msg.nTime = GetTimeMicros();
messageHandlerCondition.notify_one();
}
@@ -2378,6 +2399,9 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nPingUsecTime = 0;
fPingQueued = false;
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
+ for (unsigned int i = 0; i < sizeof(logAllowIncomingMsgCmds)/sizeof(logAllowIncomingMsgCmds[0]); i++)
+ mapRecvBytesPerMsgCmd[logAllowIncomingMsgCmds[i]] = 0;
+ mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
{
LOCK(cs_nLastNodeId);
@@ -2457,7 +2481,7 @@ void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
LogPrint("net", "(aborted)\n");
}
-void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
+void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend)
{
// The -*messagestest options are intentionally not documented in the help message,
// since they are only used during development to debug the networking code and are
@@ -2480,6 +2504,9 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
+ //log total amount of bytes per command
+ mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE;
+
// Set the checksum
uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
unsigned int nChecksum = 0;
diff --git a/src/net.h b/src/net.h
index 6886d070bf..3ed438605e 100644
--- a/src/net.h
+++ b/src/net.h
@@ -182,6 +182,7 @@ struct LocalServiceInfo {
extern CCriticalSection cs_mapLocalHost;
extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
+typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes
class CNodeStats
{
@@ -199,7 +200,9 @@ public:
bool fInbound;
int nStartingHeight;
uint64_t nSendBytes;
+ mapMsgCmdSize mapSendBytesPerMsgCmd;
uint64_t nRecvBytes;
+ mapMsgCmdSize mapRecvBytesPerMsgCmd;
bool fWhitelisted;
double dPingTime;
double dPingWait;
@@ -373,6 +376,9 @@ protected:
static std::vector<CSubNet> vWhitelistedRange;
static CCriticalSection cs_vWhitelistedRange;
+ mapMsgCmdSize mapSendBytesPerMsgCmd;
+ mapMsgCmdSize mapRecvBytesPerMsgCmd;
+
// Basic fuzz-testing
void Fuzz(int nChance); // modifies ssSend
@@ -525,7 +531,7 @@ public:
void AbortMessage() UNLOCK_FUNCTION(cs_vSend);
// TODO: Document the precondition of this function. Is cs_vSend locked?
- void EndMessage() UNLOCK_FUNCTION(cs_vSend);
+ void EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend);
void PushVersion();
@@ -535,7 +541,7 @@ public:
try
{
BeginMessage(pszCommand);
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -551,7 +557,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -567,7 +573,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -583,7 +589,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -599,7 +605,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -615,7 +621,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -631,7 +637,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -647,7 +653,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -663,7 +669,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -679,7 +685,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 2578848891..0ce108b06e 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -111,6 +111,14 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
" ]\n"
+ " \"bytessent_per_msg\": {\n"
+ " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " ...\n"
+ " }\n"
+ " \"bytesrecv_per_msg\": {\n"
+ " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
+ " ...\n"
+ " }\n"
" }\n"
" ,...\n"
"]\n"
@@ -165,6 +173,20 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
}
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
+ UniValue sendPerMsgCmd(UniValue::VOBJ);
+ BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapSendBytesPerMsgCmd) {
+ if (i.second > 0)
+ sendPerMsgCmd.push_back(Pair(i.first, i.second));
+ }
+ obj.push_back(Pair("bytessent_per_msg", sendPerMsgCmd));
+
+ UniValue recvPerMsgCmd(UniValue::VOBJ);
+ BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapRecvBytesPerMsgCmd) {
+ if (i.second > 0)
+ recvPerMsgCmd.push_back(Pair(i.first, i.second));
+ }
+ obj.push_back(Pair("bytesrecv_per_msg", recvPerMsgCmd));
+
ret.push_back(obj);
}