From 531214fb100c14e62921085cd68cabe2b20ee0eb Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 19 Aug 2016 15:38:04 -0400 Subject: [PATCH 01/33] gui: add NodeID to the peer table --- src/qt/guiutil.cpp | 8 ++++---- src/qt/guiutil.h | 2 +- src/qt/peertablemodel.cpp | 6 +++++- src/qt/peertablemodel.h | 7 ++++--- src/qt/rpcconsole.cpp | 6 +++--- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index c00f5e859..444e35de8 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -291,17 +291,17 @@ void copyEntryData(QAbstractItemView *view, int column, int role) } } -QString getEntryData(QAbstractItemView *view, int column, int role) +QVariant getEntryData(QAbstractItemView *view, int column, int role) { if(!view || !view->selectionModel()) - return QString(); + return QVariant(); QModelIndexList selection = view->selectionModel()->selectedRows(column); if(!selection.isEmpty()) { // Return first item - return (selection.at(0).data(role).toString()); + return (selection.at(0).data(role)); } - return QString(); + return QVariant(); } QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 9267e0a6c..d5a658e7c 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -70,7 +70,7 @@ namespace GUIUtil @param[in] role Data role to extract from the model @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress */ - QString getEntryData(QAbstractItemView *view, int column, int role); + QVariant getEntryData(QAbstractItemView *view, int column, int role); void setClipboard(const QString& str); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 84ad0052f..0eb28f4ae 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -24,6 +24,8 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine switch(column) { + case PeerTableModel::NetNodeId: + return pLeft->nodeid < pRight->nodeid; case PeerTableModel::Address: return pLeft->addrName.compare(pRight->addrName) < 0; case PeerTableModel::Subversion: @@ -114,7 +116,7 @@ PeerTableModel::PeerTableModel(ClientModel *parent) : clientModel(parent), timer(0) { - columns << tr("Node/Service") << tr("User Agent") << tr("Ping Time"); + columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping Time"); priv = new PeerTablePriv(); // default to unsorted priv->sortColumn = -1; @@ -160,6 +162,8 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const if (role == Qt::DisplayRole) { switch(index.column()) { + case NetNodeId: + return rec->nodeStats.nodeid; case Address: return QString::fromStdString(rec->nodeStats.addrName); case Subversion: diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index a2aaaa5d2..a4f7bbdb3 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -52,9 +52,10 @@ public: void stopAutoRefresh(); enum ColumnIndex { - Address = 0, - Subversion = 1, - Ping = 2 + NetNodeId = 0, + Address = 1, + Subversion = 2, + Ping = 3 }; /** @name Methods overridden from QAbstractTableModel diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index bcaa9164c..e5720dd70 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -877,7 +877,7 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point) void RPCConsole::disconnectSelectedNode() { // Get currently selected peer address - QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address); + QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString(); // Find the node, disconnect it and clear the selected node if (CNode *bannedNode = FindNode(strNode.toStdString())) { bannedNode->fDisconnect = true; @@ -891,7 +891,7 @@ void RPCConsole::banSelectedNode(int bantime) return; // Get currently selected peer address - QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address); + QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString(); // Find possible nodes, ban it and clear the selected node if (FindNode(strNode.toStdString())) { std::string nStr = strNode.toStdString(); @@ -915,7 +915,7 @@ void RPCConsole::unbanSelectedNode() return; // Get currently selected ban address - QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address); + QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address).toString(); CSubNet possibleSubnet; LookupSubNet(strNode.toStdString().c_str(), possibleSubnet); From d93b14dc5ddfb937b0cc18be425b9d048cefb66b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 00:13:15 -0400 Subject: [PATCH 02/33] net: move CBanDB and CAddrDB out of net.h/cpp This will eventually solve a circular dependency --- src/Makefile.am | 2 + src/addrdb.cpp | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ src/addrdb.h | 102 ++++++++++++++++++++++ src/net.cpp | 209 ---------------------------------------------- src/net.h | 84 +------------------ 5 files changed, 323 insertions(+), 292 deletions(-) create mode 100644 src/addrdb.cpp create mode 100644 src/addrdb.h diff --git a/src/Makefile.am b/src/Makefile.am index 03fac5bf9..ebdddc87f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,6 +71,7 @@ endif .PHONY: FORCE check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ + addrdb.h \ addrman.h \ base58.h \ bloom.h \ @@ -164,6 +165,7 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ + addrdb.cpp \ bloom.cpp \ blockencodings.cpp \ chain.cpp \ diff --git a/src/addrdb.cpp b/src/addrdb.cpp new file mode 100644 index 000000000..ddf41f92d --- /dev/null +++ b/src/addrdb.cpp @@ -0,0 +1,218 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "addrdb.h" + +#include "addrman.h" +#include "chainparams.h" +#include "clientversion.h" +#include "hash.h" +#include "random.h" +#include "streams.h" +#include "tinyformat.h" +#include "util.h" + +#include + +CBanDB::CBanDB() +{ + pathBanlist = GetDataDir() / "banlist.dat"; +} + +bool CBanDB::Write(const banmap_t& banSet) +{ + // Generate random temporary filename + unsigned short randv = 0; + GetRandBytes((unsigned char*)&randv, sizeof(randv)); + std::string tmpfn = strprintf("banlist.dat.%04x", randv); + + // serialize banlist, checksum data up to that point, then append csum + CDataStream ssBanlist(SER_DISK, CLIENT_VERSION); + ssBanlist << FLATDATA(Params().MessageStart()); + ssBanlist << banSet; + uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end()); + ssBanlist << hash; + + // open temp output file, and associate with CAutoFile + boost::filesystem::path pathTmp = GetDataDir() / tmpfn; + FILE *file = fopen(pathTmp.string().c_str(), "wb"); + CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: Failed to open file %s", __func__, pathTmp.string()); + + // Write and commit header, data + try { + fileout << ssBanlist; + } + catch (const std::exception& e) { + return error("%s: Serialize or I/O error - %s", __func__, e.what()); + } + FileCommit(fileout.Get()); + fileout.fclose(); + + // replace existing banlist.dat, if any, with new banlist.dat.XXXX + if (!RenameOver(pathTmp, pathBanlist)) + return error("%s: Rename-into-place failed", __func__); + + return true; +} + +bool CBanDB::Read(banmap_t& banSet) +{ + // open input file, and associate with CAutoFile + FILE *file = fopen(pathBanlist.string().c_str(), "rb"); + CAutoFile filein(file, SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: Failed to open file %s", __func__, pathBanlist.string()); + + // use file size to size memory buffer + uint64_t fileSize = boost::filesystem::file_size(pathBanlist); + uint64_t dataSize = 0; + // Don't try to resize to a negative number if file is small + if (fileSize >= sizeof(uint256)) + dataSize = fileSize - sizeof(uint256); + std::vector vchData; + vchData.resize(dataSize); + uint256 hashIn; + + // read data and checksum from file + try { + filein.read((char *)&vchData[0], dataSize); + filein >> hashIn; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + filein.fclose(); + + CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION); + + // verify stored checksum matches input data + uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end()); + if (hashIn != hashTmp) + return error("%s: Checksum mismatch, data corrupted", __func__); + + unsigned char pchMsgTmp[4]; + try { + // de-serialize file header (network specific magic number) and .. + ssBanlist >> FLATDATA(pchMsgTmp); + + // ... verify the network matches ours + if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) + return error("%s: Invalid network magic number", __func__); + + // de-serialize address data into one CAddrMan object + ssBanlist >> banSet; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + + return true; +} + +CAddrDB::CAddrDB() +{ + pathAddr = GetDataDir() / "peers.dat"; +} + +bool CAddrDB::Write(const CAddrMan& addr) +{ + // Generate random temporary filename + unsigned short randv = 0; + GetRandBytes((unsigned char*)&randv, sizeof(randv)); + std::string tmpfn = strprintf("peers.dat.%04x", randv); + + // serialize addresses, checksum data up to that point, then append csum + CDataStream ssPeers(SER_DISK, CLIENT_VERSION); + ssPeers << FLATDATA(Params().MessageStart()); + ssPeers << addr; + uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); + ssPeers << hash; + + // open temp output file, and associate with CAutoFile + boost::filesystem::path pathTmp = GetDataDir() / tmpfn; + FILE *file = fopen(pathTmp.string().c_str(), "wb"); + CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: Failed to open file %s", __func__, pathTmp.string()); + + // Write and commit header, data + try { + fileout << ssPeers; + } + catch (const std::exception& e) { + return error("%s: Serialize or I/O error - %s", __func__, e.what()); + } + FileCommit(fileout.Get()); + fileout.fclose(); + + // replace existing peers.dat, if any, with new peers.dat.XXXX + if (!RenameOver(pathTmp, pathAddr)) + return error("%s: Rename-into-place failed", __func__); + + return true; +} + +bool CAddrDB::Read(CAddrMan& addr) +{ + // open input file, and associate with CAutoFile + FILE *file = fopen(pathAddr.string().c_str(), "rb"); + CAutoFile filein(file, SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: Failed to open file %s", __func__, pathAddr.string()); + + // use file size to size memory buffer + uint64_t fileSize = boost::filesystem::file_size(pathAddr); + uint64_t dataSize = 0; + // Don't try to resize to a negative number if file is small + if (fileSize >= sizeof(uint256)) + dataSize = fileSize - sizeof(uint256); + std::vector vchData; + vchData.resize(dataSize); + uint256 hashIn; + + // read data and checksum from file + try { + filein.read((char *)&vchData[0], dataSize); + filein >> hashIn; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + filein.fclose(); + + CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION); + + // verify stored checksum matches input data + uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); + if (hashIn != hashTmp) + return error("%s: Checksum mismatch, data corrupted", __func__); + + return Read(addr, ssPeers); +} + +bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) +{ + unsigned char pchMsgTmp[4]; + try { + // de-serialize file header (network specific magic number) and .. + ssPeers >> FLATDATA(pchMsgTmp); + + // ... verify the network matches ours + if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) + return error("%s: Invalid network magic number", __func__); + + // de-serialize address data into one CAddrMan object + ssPeers >> addr; + } + catch (const std::exception& e) { + // de-serialization has failed, ensure addrman is left in a clean state + addr.Clear(); + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + + return true; +} diff --git a/src/addrdb.h b/src/addrdb.h new file mode 100644 index 000000000..3ffcfe3e1 --- /dev/null +++ b/src/addrdb.h @@ -0,0 +1,102 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_ADDRDB_H +#define BITCOIN_ADDRDB_H + +#include "serialize.h" + +#include +#include +#include + +class CSubNet; +class CAddrMan; + +typedef enum BanReason +{ + BanReasonUnknown = 0, + BanReasonNodeMisbehaving = 1, + BanReasonManuallyAdded = 2 +} BanReason; + +class CBanEntry +{ +public: + static const int CURRENT_VERSION=1; + int nVersion; + int64_t nCreateTime; + int64_t nBanUntil; + uint8_t banReason; + + CBanEntry() + { + SetNull(); + } + + CBanEntry(int64_t nCreateTimeIn) + { + SetNull(); + nCreateTime = nCreateTimeIn; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(nCreateTime); + READWRITE(nBanUntil); + READWRITE(banReason); + } + + void SetNull() + { + nVersion = CBanEntry::CURRENT_VERSION; + nCreateTime = 0; + nBanUntil = 0; + banReason = BanReasonUnknown; + } + + std::string banReasonToString() + { + switch (banReason) { + case BanReasonNodeMisbehaving: + return "node misbehaving"; + case BanReasonManuallyAdded: + return "manually added"; + default: + return "unknown"; + } + } +}; + +typedef std::map banmap_t; + +/** Access to the (IP) address database (peers.dat) */ +class CAddrDB +{ +private: + boost::filesystem::path pathAddr; +public: + CAddrDB(); + bool Write(const CAddrMan& addr); + bool Read(CAddrMan& addr); + bool Read(CAddrMan& addr, CDataStream& ssPeers); +}; + +/** Access to the banlist database (banlist.dat) */ +class CBanDB +{ +private: + boost::filesystem::path pathBanlist; +public: + CBanDB(); + bool Write(const banmap_t& banSet); + bool Read(banmap_t& banSet); +}; + +#endif // BITCOIN_ADDRDB_H diff --git a/src/net.cpp b/src/net.cpp index c5b080f79..cee149ee7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2356,114 +2356,6 @@ void CNode::Fuzz(int nChance) Fuzz(2); } -// -// CAddrDB -// - -CAddrDB::CAddrDB() -{ - pathAddr = GetDataDir() / "peers.dat"; -} - -bool CAddrDB::Write(const CAddrMan& addr) -{ - // Generate random temporary filename - unsigned short randv = 0; - GetRandBytes((unsigned char*)&randv, sizeof(randv)); - std::string tmpfn = strprintf("peers.dat.%04x", randv); - - // serialize addresses, checksum data up to that point, then append csum - CDataStream ssPeers(SER_DISK, CLIENT_VERSION); - ssPeers << FLATDATA(Params().MessageStart()); - ssPeers << addr; - uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); - ssPeers << hash; - - // open temp output file, and associate with CAutoFile - boost::filesystem::path pathTmp = GetDataDir() / tmpfn; - FILE *file = fopen(pathTmp.string().c_str(), "wb"); - CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("%s: Failed to open file %s", __func__, pathTmp.string()); - - // Write and commit header, data - try { - fileout << ssPeers; - } - catch (const std::exception& e) { - return error("%s: Serialize or I/O error - %s", __func__, e.what()); - } - FileCommit(fileout.Get()); - fileout.fclose(); - - // replace existing peers.dat, if any, with new peers.dat.XXXX - if (!RenameOver(pathTmp, pathAddr)) - return error("%s: Rename-into-place failed", __func__); - - return true; -} - -bool CAddrDB::Read(CAddrMan& addr) -{ - // open input file, and associate with CAutoFile - FILE *file = fopen(pathAddr.string().c_str(), "rb"); - CAutoFile filein(file, SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("%s: Failed to open file %s", __func__, pathAddr.string()); - - // use file size to size memory buffer - uint64_t fileSize = boost::filesystem::file_size(pathAddr); - uint64_t dataSize = 0; - // Don't try to resize to a negative number if file is small - if (fileSize >= sizeof(uint256)) - dataSize = fileSize - sizeof(uint256); - std::vector vchData; - vchData.resize(dataSize); - uint256 hashIn; - - // read data and checksum from file - try { - filein.read((char *)&vchData[0], dataSize); - filein >> hashIn; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - filein.fclose(); - - CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION); - - // verify stored checksum matches input data - uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); - if (hashIn != hashTmp) - return error("%s: Checksum mismatch, data corrupted", __func__); - - return Read(addr, ssPeers); -} - -bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) -{ - unsigned char pchMsgTmp[4]; - try { - // de-serialize file header (network specific magic number) and .. - ssPeers >> FLATDATA(pchMsgTmp); - - // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) - return error("%s: Invalid network magic number", __func__); - - // de-serialize address data into one CAddrMan object - ssPeers >> addr; - } - catch (const std::exception& e) { - // de-serialization has failed, ensure addrman is left in a clean state - addr.Clear(); - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - - return true; -} - unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } @@ -2649,107 +2541,6 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) LEAVE_CRITICAL_SECTION(cs_vSend); } -// -// CBanDB -// - -CBanDB::CBanDB() -{ - pathBanlist = GetDataDir() / "banlist.dat"; -} - -bool CBanDB::Write(const banmap_t& banSet) -{ - // Generate random temporary filename - unsigned short randv = 0; - GetRandBytes((unsigned char*)&randv, sizeof(randv)); - std::string tmpfn = strprintf("banlist.dat.%04x", randv); - - // serialize banlist, checksum data up to that point, then append csum - CDataStream ssBanlist(SER_DISK, CLIENT_VERSION); - ssBanlist << FLATDATA(Params().MessageStart()); - ssBanlist << banSet; - uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end()); - ssBanlist << hash; - - // open temp output file, and associate with CAutoFile - boost::filesystem::path pathTmp = GetDataDir() / tmpfn; - FILE *file = fopen(pathTmp.string().c_str(), "wb"); - CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("%s: Failed to open file %s", __func__, pathTmp.string()); - - // Write and commit header, data - try { - fileout << ssBanlist; - } - catch (const std::exception& e) { - return error("%s: Serialize or I/O error - %s", __func__, e.what()); - } - FileCommit(fileout.Get()); - fileout.fclose(); - - // replace existing banlist.dat, if any, with new banlist.dat.XXXX - if (!RenameOver(pathTmp, pathBanlist)) - return error("%s: Rename-into-place failed", __func__); - - return true; -} - -bool CBanDB::Read(banmap_t& banSet) -{ - // open input file, and associate with CAutoFile - FILE *file = fopen(pathBanlist.string().c_str(), "rb"); - CAutoFile filein(file, SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("%s: Failed to open file %s", __func__, pathBanlist.string()); - - // use file size to size memory buffer - uint64_t fileSize = boost::filesystem::file_size(pathBanlist); - uint64_t dataSize = 0; - // Don't try to resize to a negative number if file is small - if (fileSize >= sizeof(uint256)) - dataSize = fileSize - sizeof(uint256); - std::vector vchData; - vchData.resize(dataSize); - uint256 hashIn; - - // read data and checksum from file - try { - filein.read((char *)&vchData[0], dataSize); - filein >> hashIn; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - filein.fclose(); - - CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION); - - // verify stored checksum matches input data - uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end()); - if (hashIn != hashTmp) - return error("%s: Checksum mismatch, data corrupted", __func__); - - unsigned char pchMsgTmp[4]; - try { - // de-serialize file header (network specific magic number) and .. - ssBanlist >> FLATDATA(pchMsgTmp); - - // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) - return error("%s: Invalid network magic number", __func__); - - // de-serialize address data into one CAddrMan object - ssBanlist >> banSet; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - - return true; -} - int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } diff --git a/src/net.h b/src/net.h index b9cc81e4e..0d1c62e42 100644 --- a/src/net.h +++ b/src/net.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_NET_H #define BITCOIN_NET_H +#include "addrdb.h" #include "amount.h" #include "bloom.h" #include "compat.h" @@ -256,67 +257,6 @@ public: }; -typedef enum BanReason -{ - BanReasonUnknown = 0, - BanReasonNodeMisbehaving = 1, - BanReasonManuallyAdded = 2 -} BanReason; - -class CBanEntry -{ -public: - static const int CURRENT_VERSION=1; - int nVersion; - int64_t nCreateTime; - int64_t nBanUntil; - uint8_t banReason; - - CBanEntry() - { - SetNull(); - } - - CBanEntry(int64_t nCreateTimeIn) - { - SetNull(); - nCreateTime = nCreateTimeIn; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(nCreateTime); - READWRITE(nBanUntil); - READWRITE(banReason); - } - - void SetNull() - { - nVersion = CBanEntry::CURRENT_VERSION; - nCreateTime = 0; - nBanUntil = 0; - banReason = BanReasonUnknown; - } - - std::string banReasonToString() - { - switch (banReason) { - case BanReasonNodeMisbehaving: - return "node misbehaving"; - case BanReasonManuallyAdded: - return "manually added"; - default: - return "unknown"; - } - } -}; - -typedef std::map banmap_t; - /** Information about a peer */ class CNode { @@ -819,28 +759,6 @@ public: class CTransaction; void RelayTransaction(const CTransaction& tx); -/** Access to the (IP) address database (peers.dat) */ -class CAddrDB -{ -private: - boost::filesystem::path pathAddr; -public: - CAddrDB(); - bool Write(const CAddrMan& addr); - bool Read(CAddrMan& addr); - bool Read(CAddrMan& addr, CDataStream& ssPeers); -}; - -/** Access to the banlist database (banlist.dat) */ -class CBanDB -{ -private: - boost::filesystem::path pathBanlist; -public: - CBanDB(); - bool Write(const banmap_t& banSet); - bool Read(banmap_t& banSet); -}; /** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds); From cd16f48028f54327d4afba9c1f91f25d0b072aa5 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 14:47:18 -0400 Subject: [PATCH 03/33] net: Create CConnman to encapsulate p2p connections --- src/addrdb.h | 1 + src/init.cpp | 14 ++++- src/net.cpp | 113 +++++++++++++++++++++----------------- src/net.h | 30 +++++++++- src/test/test_bitcoin.cpp | 6 ++ src/test/test_bitcoin.h | 2 + 6 files changed, 112 insertions(+), 54 deletions(-) diff --git a/src/addrdb.h b/src/addrdb.h index 3ffcfe3e1..d8c66d872 100644 --- a/src/addrdb.h +++ b/src/addrdb.h @@ -14,6 +14,7 @@ class CSubNet; class CAddrMan; +class CDataStream; typedef enum BanReason { diff --git a/src/init.cpp b/src/init.cpp index 27843fa88..6aaa7bfc5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -42,6 +42,7 @@ #endif #include #include +#include #ifndef WIN32 #include @@ -70,6 +71,7 @@ static const bool DEFAULT_REST_ENABLE = false; static const bool DEFAULT_DISABLE_SAFEMODE = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; +std::unique_ptr g_connman; #if ENABLE_ZMQ static CZMQNotificationInterface* pzmqNotificationInterface = NULL; @@ -197,7 +199,9 @@ void Shutdown() if (pwalletMain) pwalletMain->Flush(false); #endif - StopNode(); + StopNode(*g_connman); + g_connman.reset(); + StopTorControl(); UnregisterNodeSignals(GetNodeSignals()); @@ -1101,6 +1105,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif // ENABLE_WALLET // ********************************************************* Step 6: network initialization + assert(!g_connman); + g_connman = std::unique_ptr(new CConnman()); + CConnman& connman = *g_connman; + RegisterNodeSignals(GetNodeSignals()); // sanitize comments per BIP-0014, format user agent and check total size @@ -1497,7 +1505,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); - StartNode(threadGroup, scheduler); + std::string strNodeError; + if(!StartNode(connman, threadGroup, scheduler, strNodeError)) + return InitError(strNodeError); // ********************************************************* Step 12: finished diff --git a/src/net.cpp b/src/net.cpp index cee149ee7..6177dc04f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -65,13 +65,6 @@ namespace { const int MAX_OUTBOUND_CONNECTIONS = 8; const int MAX_FEELER_CONNECTIONS = 1; - - struct ListenSocket { - SOCKET socket; - bool whitelisted; - - ListenSocket(SOCKET _socket, bool _whitelisted) : socket(_socket), whitelisted(_whitelisted) {} - }; } const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; @@ -1015,7 +1008,7 @@ static bool AttemptToEvictConnection() { return false; } -static void AcceptConnection(const ListenSocket& hListenSocket) { +void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); @@ -1089,7 +1082,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { } } -void ThreadSocketHandler() +void CConnman::ThreadSocketHandler() { unsigned int nPrevNodeCount = 0; while (true) @@ -1497,7 +1490,7 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe } -void ThreadDNSAddressSeed() +void CConnman::ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute if ((addrman.size() > 0) && @@ -1577,7 +1570,7 @@ void DumpData() DumpBanlist(); } -void static ProcessOneShot() +void CConnman::ProcessOneShot() { std::string strDest; { @@ -1595,7 +1588,7 @@ void static ProcessOneShot() } } -void ThreadOpenConnections() +void CConnman::ThreadOpenConnections() { // Connect to specific addresses if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) @@ -1791,7 +1784,7 @@ std::vector GetAddedNodeInfo() return ret; } -void ThreadOpenAddedConnections() +void CConnman::ThreadOpenAddedConnections() { { LOCK(cs_vAddedNodes); @@ -1848,7 +1841,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem } -void ThreadMessageHandler() +void CConnman::ThreadMessageHandler() { boost::mutex condition_mutex; boost::unique_lock lock(condition_mutex); @@ -2064,7 +2057,11 @@ void static Discover(boost::thread_group& threadGroup) #endif } -void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) +CConnman::CConnman() +{ +} + +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) { uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat @@ -2102,6 +2099,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) fAddressesInitialized = true; + Discover(threadGroup); + + bool ret = connman.Start(threadGroup, strNodeError); + + // Dump network addresses + scheduler.scheduleEvery(DumpData, DUMP_ADDRESSES_INTERVAL); + return ret; +} + +bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError) +{ if (semOutbound == NULL) { // initialize semaphore int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); @@ -2114,8 +2122,6 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); } - Discover(threadGroup); - // // Start threads // @@ -2123,34 +2129,30 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (!GetBoolArg("-dnsseed", true)) LogPrintf("DNS seeding disabled\n"); else - threadGroup.create_thread(boost::bind(&TraceThread, "dnsseed", &ThreadDNSAddressSeed)); + threadGroup.create_thread(boost::bind(&TraceThread >, "dnsseed", boost::function(boost::bind(&CConnman::ThreadDNSAddressSeed, this)))); // Map ports with UPnP MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); // Send and receive from sockets, accept connections - threadGroup.create_thread(boost::bind(&TraceThread, "net", &ThreadSocketHandler)); + threadGroup.create_thread(boost::bind(&TraceThread >, "net", boost::function(boost::bind(&CConnman::ThreadSocketHandler, this)))); // Initiate outbound connections from -addnode - threadGroup.create_thread(boost::bind(&TraceThread, "addcon", &ThreadOpenAddedConnections)); + threadGroup.create_thread(boost::bind(&TraceThread >, "addcon", boost::function(boost::bind(&CConnman::ThreadOpenAddedConnections, this)))); // Initiate outbound connections - threadGroup.create_thread(boost::bind(&TraceThread, "opencon", &ThreadOpenConnections)); + threadGroup.create_thread(boost::bind(&TraceThread >, "opencon", boost::function(boost::bind(&CConnman::ThreadOpenConnections, this)))); // Process messages - threadGroup.create_thread(boost::bind(&TraceThread, "msghand", &ThreadMessageHandler)); + threadGroup.create_thread(boost::bind(&TraceThread >, "msghand", boost::function(boost::bind(&CConnman::ThreadMessageHandler, this)))); - // Dump network addresses - scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL); + return true; } -bool StopNode() +bool StopNode(CConnman& connman) { LogPrintf("StopNode()\n"); MapPort(false); - if (semOutbound) - for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) - semOutbound->post(); if (fAddressesInitialized) { @@ -2158,6 +2160,7 @@ bool StopNode() fAddressesInitialized = false; } + connman.Stop(); return true; } @@ -2168,28 +2171,6 @@ public: ~CNetCleanup() { - // Close sockets - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->hSocket != INVALID_SOCKET) - CloseSocket(pnode->hSocket); - BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket) - if (hListenSocket.socket != INVALID_SOCKET) - if (!CloseSocket(hListenSocket.socket)) - LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); - - // clean up some globals (to help leak detection) - BOOST_FOREACH(CNode *pnode, vNodes) - delete pnode; - BOOST_FOREACH(CNode *pnode, vNodesDisconnected) - delete pnode; - vNodes.clear(); - vNodesDisconnected.clear(); - vhListenSocket.clear(); - delete semOutbound; - semOutbound = NULL; - delete pnodeLocalHost; - pnodeLocalHost = NULL; - #ifdef WIN32 // Shutdown Windows Sockets WSACleanup(); @@ -2198,6 +2179,38 @@ public: } instance_of_cnetcleanup; +void CConnman::Stop() +{ + if (semOutbound) + for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) + semOutbound->post(); + + // Close sockets + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->hSocket != INVALID_SOCKET) + CloseSocket(pnode->hSocket); + BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket) + if (hListenSocket.socket != INVALID_SOCKET) + if (!CloseSocket(hListenSocket.socket)) + LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); + + // clean up some globals (to help leak detection) + BOOST_FOREACH(CNode *pnode, vNodes) + delete pnode; + BOOST_FOREACH(CNode *pnode, vNodesDisconnected) + delete pnode; + vNodes.clear(); + vNodesDisconnected.clear(); + vhListenSocket.clear(); + delete semOutbound; + semOutbound = NULL; + delete pnodeLocalHost; + pnodeLocalHost = NULL; +} + +CConnman::~CConnman() +{ +} void RelayTransaction(const CTransaction& tx) { diff --git a/src/net.h b/src/net.h index 0d1c62e42..7f212f233 100644 --- a/src/net.h +++ b/src/net.h @@ -21,6 +21,7 @@ #include #include #include +#include #ifndef WIN32 #include @@ -93,11 +94,36 @@ CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); CNode* FindNode(const NodeId id); //TODO: Remove this bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); + +struct ListenSocket { + SOCKET socket; + bool whitelisted; + + ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {} +}; + +class CConnman +{ +public: + CConnman(); + ~CConnman(); + bool Start(boost::thread_group& threadGroup, std::string& strNodeError); + void Stop(); +private: + void ThreadOpenAddedConnections(); + void ProcessOneShot(); + void ThreadOpenConnections(); + void ThreadMessageHandler(); + void AcceptConnection(const ListenSocket& hListenSocket); + void ThreadSocketHandler(); + void ThreadDNSAddressSeed(); +}; +extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); -void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler); -bool StopNode(); +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError); +bool StopNode(CConnman& connman); void SocketSendData(CNode *pnode); struct CombinerAll diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 056f2982c..ed74418e3 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -26,6 +26,8 @@ #include #include +std::unique_ptr g_connman; + extern bool fPrintToConsole; extern void noui_connect(); @@ -43,6 +45,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); + g_connman.reset(); } TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) @@ -50,6 +53,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha const CChainParams& chainparams = Params(); // Ideally we'd move all the RPC tests to the functional testing framework // instead of unit tests, but for now we need these here. + RegisterAllCoreRPCCommands(tableRPC); ClearDatadirCache(); pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); @@ -68,6 +72,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); + g_connman = std::unique_ptr(new CConnman()); + connman = g_connman.get(); RegisterNodeSignals(GetNodeSignals()); } diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index bc0d2fe31..9819a7097 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -27,10 +27,12 @@ struct BasicTestingSetup { /** Testing setup that configures a complete environment. * Included are data directory, coins database, script check threads setup. */ +class CConnman; struct TestingSetup: public BasicTestingSetup { CCoinsViewDB *pcoinsdbview; boost::filesystem::path pathTemp; boost::thread_group threadGroup; + CConnman* connman; TestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~TestingSetup(); From d7349ca50d000573d60064d4b295be308357d58e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 26 May 2016 13:10:55 -0400 Subject: [PATCH 04/33] net: Add rpc error for missing/disabled p2p functionality --- src/rpc/protocol.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 988e0fc5f..1d2ef0e41 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -63,6 +63,7 @@ enum RPCErrorCode RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet + RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found //! Wallet errors RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.) From 8d58c4d81f18e9a51d11ee354434cf55d03a4add Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 26 May 2016 14:26:01 -0400 Subject: [PATCH 05/33] net: Pass CConnman around as needed --- src/main.cpp | 22 +++++++++++----------- src/main.h | 10 ++++++---- src/net.cpp | 4 ++-- src/net.h | 4 ++-- src/rpc/blockchain.cpp | 4 ++-- src/rpc/mining.cpp | 4 ++-- src/test/DoS_tests.cpp | 14 +++++++------- src/test/miner_tests.cpp | 2 +- src/test/test_bitcoin.cpp | 2 +- 9 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4b42afb56..32859ebc2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3016,7 +3016,7 @@ static void NotifyHeaderTip() { * or an activated best chain. pblock is either NULL or a pointer to a block * that is already loaded (to avoid loading it again from disk). */ -bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { +bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock, CConnman* connman) { CBlockIndex *pindexMostWork = NULL; CBlockIndex *pindexNewTip = NULL; do { @@ -3731,7 +3731,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha return true; } -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman) { { LOCK(cs_main); @@ -3753,7 +3753,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C NotifyHeaderTip(); - if (!ActivateBestChain(state, chainparams, pblock)) + if (!ActivateBestChain(state, chainparams, pblock, connman)) return error("%s: ActivateBestChain failed", __func__); return true; @@ -4891,7 +4891,7 @@ uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params return nFetchFlags; } -bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams) +bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman) { LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) @@ -5680,7 +5680,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, txn.blockhash = cmpctblock.header.GetHash(); CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION); blockTxnMsg << txn; - return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams); + return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman); } else { req.blockhash = pindex->GetBlockHash(); pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req); @@ -5701,7 +5701,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, headers.push_back(cmpctblock.header); CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION); vHeadersMsg << headers; - return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams); + return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman); } } @@ -5737,7 +5737,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->PushMessage(NetMsgType::GETDATA, invs); } else { CValidationState state; - ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL); + ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, &connman); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes @@ -5913,7 +5913,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, &connman); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes @@ -6163,7 +6163,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // requires LOCK(cs_vRecvMsg) -bool ProcessMessages(CNode* pfrom) +bool ProcessMessages(CNode* pfrom, CConnman& connman) { const CChainParams& chainparams = Params(); //if (fDebug) @@ -6240,7 +6240,7 @@ bool ProcessMessages(CNode* pfrom) bool fRet = false; try { - fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams); + fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman); boost::this_thread::interruption_point(); } catch (const std::ios_base::failure& e) @@ -6305,7 +6305,7 @@ public: } }; -bool SendMessages(CNode* pto) +bool SendMessages(CNode* pto, CConnman& connman) { const Consensus::Params& consensusParams = Params().GetConsensus(); { diff --git a/src/main.h b/src/main.h index 18d674612..2646d8f86 100644 --- a/src/main.h +++ b/src/main.h @@ -34,6 +34,7 @@ class CBlockTreeDB; class CBloomFilter; class CChainParams; class CInv; +class CConnman; class CScriptCheck; class CTxMemPool; class CValidationInterface; @@ -222,7 +223,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -240,13 +241,14 @@ bool LoadBlockIndex(); /** Unload database information */ void UnloadBlockIndex(); /** Process protocol messages received from a given node */ -bool ProcessMessages(CNode* pfrom); +bool ProcessMessages(CNode* pfrom, CConnman& connman); /** * Send queued protocol messages to be sent to a give node. * * @param[in] pto The node which we are sending messages to. + * @param[in] connman The connection manager for that node. */ -bool SendMessages(CNode* pto); +bool SendMessages(CNode* pto, CConnman& connman); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ @@ -262,7 +264,7 @@ std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); +bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL, CConnman* connman = NULL); CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); /** diff --git a/src/net.cpp b/src/net.cpp index 6177dc04f..b99989b28 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1869,7 +1869,7 @@ void CConnman::ThreadMessageHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - if (!GetNodeSignals().ProcessMessages(pnode)) + if (!GetNodeSignals().ProcessMessages(pnode, *this)) pnode->CloseSocketDisconnect(); if (pnode->nSendSize < SendBufferSize()) @@ -1887,7 +1887,7 @@ void CConnman::ThreadMessageHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - GetNodeSignals().SendMessages(pnode); + GetNodeSignals().SendMessages(pnode, *this); } boost::this_thread::interruption_point(); } diff --git a/src/net.h b/src/net.h index 7f212f233..d2a38e7dc 100644 --- a/src/net.h +++ b/src/net.h @@ -145,8 +145,8 @@ struct CombinerAll struct CNodeSignals { boost::signals2::signal GetHeight; - boost::signals2::signal ProcessMessages; - boost::signals2::signal SendMessages; + boost::signals2::signal ProcessMessages; + boost::signals2::signal SendMessages; boost::signals2::signal InitializeNode; boost::signals2::signal FinalizeNode; }; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index b90410017..d600383c4 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1133,7 +1133,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) } if (state.IsValid()) { - ActivateBestChain(state, Params()); + ActivateBestChain(state, Params(), NULL, g_connman.get()); } if (!state.IsValid()) { @@ -1171,7 +1171,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) } CValidationState state; - ActivateBestChain(state, Params()); + ActivateBestChain(state, Params(), NULL, g_connman.get()); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 14183c8e8..63ecf49ec 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr coinbaseScript, int nG continue; } CValidationState state; - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, g_connman.get())) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -754,7 +754,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, g_connman.get()); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index a8c5f95ac..10529cda9 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CNode dummyNode1(INVALID_SOCKET, addr1, "", true); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned - SendMessages(&dummyNode1); + SendMessages(&dummyNode1, *connman); BOOST_CHECK(CNode::IsBanned(addr1)); BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned @@ -57,11 +57,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CNode dummyNode2(INVALID_SOCKET, addr2, "", true); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2); + SendMessages(&dummyNode2, *connman); BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be Misbehaving(dummyNode2.GetId(), 50); - SendMessages(&dummyNode2); + SendMessages(&dummyNode2, *connman); BOOST_CHECK(CNode::IsBanned(addr2)); } @@ -73,13 +73,13 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) CNode dummyNode1(INVALID_SOCKET, addr1, "", true); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); - SendMessages(&dummyNode1); + SendMessages(&dummyNode1, *connman); BOOST_CHECK(!CNode::IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10); - SendMessages(&dummyNode1); + SendMessages(&dummyNode1, *connman); BOOST_CHECK(!CNode::IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1); - SendMessages(&dummyNode1); + SendMessages(&dummyNode1, *connman); BOOST_CHECK(CNode::IsBanned(addr1)); mapArgs.erase("-banscore"); } @@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) dummyNode.nVersion = 1; Misbehaving(dummyNode.GetId(), 100); - SendMessages(&dummyNode); + SendMessages(&dummyNode, *connman); BOOST_CHECK(CNode::IsBanned(addr)); SetMockTime(nStartTime+60*60); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 15fceb963..d3aa2364d 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, connman)); BOOST_CHECK(state.IsValid()); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index ed74418e3..b1ceef4f6 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -124,7 +124,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; CValidationState state; - ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, connman); CBlock result = block; delete pblocktemplate; From 5b446dd5b11d4f403554bc2dd5a7a94c7d20422a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 24 May 2016 20:56:17 -0400 Subject: [PATCH 06/33] net: Pass CConnection to wallet rather than using the global --- src/main.cpp | 2 +- src/qt/walletmodel.cpp | 2 +- src/validationinterface.cpp | 4 ++-- src/validationinterface.h | 5 +++-- src/wallet/rpcwallet.cpp | 15 ++++++++++++--- src/wallet/wallet.cpp | 14 +++++++------- src/wallet/wallet.h | 8 ++++---- 7 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 32859ebc2..4dc9d71ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6431,7 +6431,7 @@ bool SendMessages(CNode* pto, CConnman& connman) // transactions become unconfirmed and spams other nodes. if (!fReindex && !fImporting && !IsInitialBlockDownload()) { - GetMainSignals().Broadcast(nTimeBestReceived); + GetMainSignals().Broadcast(nTimeBestReceived, &connman); } // diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ae7efc7a0..73851e97f 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -328,7 +328,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran } CReserveKey *keyChange = transaction.getPossibleKeyChange(); - if(!wallet->CommitTransaction(*newTx, *keyChange)) + if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get())) return TransactionCommitFailed; CTransaction* t = (CTransaction*)newTx; diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index cf1d6ca08..6ddf37658 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -18,7 +18,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); - g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); + g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2)); g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); @@ -28,7 +28,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); - g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); + g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); diff --git a/src/validationinterface.h b/src/validationinterface.h index 094b1cfe2..0c91ec830 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -13,6 +13,7 @@ class CBlock; class CBlockIndex; struct CBlockLocator; class CBlockIndex; +class CConnman; class CReserveScript; class CTransaction; class CValidationInterface; @@ -37,7 +38,7 @@ protected: virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} - virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} + virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} virtual void GetScriptForMining(boost::shared_ptr&) {}; virtual void ResetRequestCount(const uint256 &hash) {}; @@ -58,7 +59,7 @@ struct CMainSignals { /** Notifies listeners about an inventory item being seen on the network. */ boost::signals2::signal Inventory; /** Tells listeners to broadcast their data. */ - boost::signals2::signal Broadcast; + boost::signals2::signal Broadcast; /** Notifies listeners of a block validation result */ boost::signals2::signal BlockChecked; /** Notifies listeners that a key for mining is required (coinbase) */ diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0ba6706ba..a399f8ad9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -346,6 +346,9 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr if (nValue > curBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); + if (pwalletMain->GetBroadcastTransactions() && !g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + // Parse Bitcoin address CScript scriptPubKey = GetScriptForDestination(address); @@ -362,7 +365,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } - if (!pwalletMain->CommitTransaction(wtxNew, reservekey)) + if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here."); } @@ -891,6 +894,9 @@ UniValue sendmany(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + if (pwalletMain->GetBroadcastTransactions() && !g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + string strAccount = AccountFromValue(params[0]); UniValue sendTo = params[1].get_obj(); int nMinDepth = 1; @@ -953,7 +959,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); - if (!pwalletMain->CommitTransaction(wtx, keyChange)) + if (!pwalletMain->CommitTransaction(wtx, keyChange, g_connman.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); return wtx.GetHash().GetHex(); @@ -2308,9 +2314,12 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp) "Returns array of transaction ids that were re-broadcast.\n" ); + if (!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + LOCK2(cs_main, pwalletMain->cs_wallet); - std::vector txids = pwalletMain->ResendWalletTransactionsBefore(GetTime()); + std::vector txids = pwalletMain->ResendWalletTransactionsBefore(GetTime(), g_connman.get()); UniValue result(UniValue::VARR); BOOST_FOREACH(const uint256& txid, txids) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 10aca2e49..4396c2a2b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1453,7 +1453,7 @@ void CWallet::ReacceptWalletTransactions() } } -bool CWalletTx::RelayWalletTransaction() +bool CWalletTx::RelayWalletTransaction(CConnman* connman) { assert(pwallet->GetBroadcastTransactions()); if (!IsCoinBase()) @@ -1688,7 +1688,7 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const return CTransaction(tx1) == CTransaction(tx2); } -std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime) +std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman) { std::vector result; @@ -1706,13 +1706,13 @@ std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime) BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) { CWalletTx& wtx = *item.second; - if (wtx.RelayWalletTransaction()) + if (wtx.RelayWalletTransaction(connman)) result.push_back(wtx.GetHash()); } return result; } -void CWallet::ResendWalletTransactions(int64_t nBestBlockTime) +void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) { // Do this infrequently and randomly to avoid giving away // that these are our transactions. @@ -1730,7 +1730,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime) // Rebroadcast unconfirmed txes older than 5 minutes before the last // block was found: - std::vector relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60); + std::vector relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman); if (!relayed.empty()) LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size()); } @@ -2447,7 +2447,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt /** * Call after CreateTransaction unless you want to abort */ -bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) +bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman) { { LOCK2(cs_main, cs_wallet); @@ -2481,7 +2481,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); return false; } - wtxNew.RelayWalletTransaction(); + wtxNew.RelayWalletTransaction(connman); } } return true; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index c06513650..7a771350c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -401,7 +401,7 @@ public: int64_t GetTxTime() const; int GetRequestCount() const; - bool RelayWalletTransaction(); + bool RelayWalletTransaction(CConnman* connman); std::set GetConflicts() const; }; @@ -748,8 +748,8 @@ public: bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); - void ResendWalletTransactions(int64_t nBestBlockTime); - std::vector ResendWalletTransactionsBefore(int64_t nTime); + void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman); + std::vector ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman); CAmount GetBalance() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; @@ -770,7 +770,7 @@ public: */ bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true); - bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); + bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman); bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); From 02137f11e2ea5d153f433493639730587836a1e3 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 15:46:00 -0400 Subject: [PATCH 07/33] net: Move socket binding into CConnman --- src/init.cpp | 12 ++++++------ src/net.cpp | 3 +-- src/net.h | 18 +++++++++++------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 6aaa7bfc5..b0ffb7a40 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -273,11 +273,11 @@ void HandleSIGHUP(int) fReopenDebugLog = true; } -bool static Bind(const CService &addr, unsigned int flags) { +bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) { if (!(flags & BF_EXPLICIT) && IsLimited(addr)) return false; std::string strError; - if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) { + if (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) { if (flags & BF_REPORT_ERROR) return InitError(strError); return false; @@ -1198,7 +1198,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(ResolveErrMsg("bind", strBind)); - fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); + fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) { CService addrBind; @@ -1206,14 +1206,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(ResolveErrMsg("whitebind", strBind)); if (addrBind.GetPort() == 0) return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind)); - fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); + fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); } } else { struct in_addr inaddr_any; inaddr_any.s_addr = INADDR_ANY; - fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE); - fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE); + fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE); + fBound |= Bind(connman, CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE); } if (!fBound) return InitError(_("Failed to listen on any port. Use -listen=0 if you want this.")); diff --git a/src/net.cpp b/src/net.cpp index b99989b28..006982000 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -84,7 +84,6 @@ std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; -static std::vector vhListenSocket; CAddrMan addrman; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; bool fAddressesInitialized = false; @@ -1908,7 +1907,7 @@ void CConnman::ThreadMessageHandler() -bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted) +bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted) { strError = ""; int nOne = 1; diff --git a/src/net.h b/src/net.h index d2a38e7dc..4d87408e3 100644 --- a/src/net.h +++ b/src/net.h @@ -95,13 +95,6 @@ CNode* FindNode(const CService& ip); CNode* FindNode(const NodeId id); //TODO: Remove this bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); -struct ListenSocket { - SOCKET socket; - bool whitelisted; - - ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {} -}; - class CConnman { public: @@ -109,7 +102,16 @@ public: ~CConnman(); bool Start(boost::thread_group& threadGroup, std::string& strNodeError); void Stop(); + bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); + private: + struct ListenSocket { + SOCKET socket; + bool whitelisted; + + ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {} + }; + void ThreadOpenAddedConnections(); void ProcessOneShot(); void ThreadOpenConnections(); @@ -117,6 +119,8 @@ private: void AcceptConnection(const ListenSocket& hListenSocket); void ThreadSocketHandler(); void ThreadDNSAddressSeed(); + + std::vector vhListenSocket; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); From b1a5f4320878e34eb998737dce333270dd83e436 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 15:59:10 -0400 Subject: [PATCH 08/33] net: move OpenNetworkConnection into CConnman --- src/net.cpp | 4 ++-- src/net.h | 4 +++- src/rpc/net.cpp | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 006982000..83a96205a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -375,7 +375,7 @@ CNode* FindNode(const NodeId nodeid) return NULL; } -CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) +CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { if (IsLocal(addrConnect)) @@ -1809,7 +1809,7 @@ void CConnman::ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler) +bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler) { // // Initiate outbound network connection diff --git a/src/net.h b/src/net.h index 4d87408e3..e0c317ae4 100644 --- a/src/net.h +++ b/src/net.h @@ -93,7 +93,6 @@ CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); CNode* FindNode(const NodeId id); //TODO: Remove this -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); class CConnman { @@ -103,6 +102,7 @@ public: bool Start(boost::thread_group& threadGroup, std::string& strNodeError); void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); + bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); private: struct ListenSocket { @@ -120,6 +120,8 @@ private: void ThreadSocketHandler(); void ThreadDNSAddressSeed(); + CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure); + std::vector vhListenSocket; }; extern std::unique_ptr g_connman; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 840bfd5a2..edf33c70b 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -214,12 +214,15 @@ UniValue addnode(const UniValue& params, bool fHelp) + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + string strNode = params[0].get_str(); if (strCommand == "onetry") { CAddress addr; - OpenNetworkConnection(addr, false, NULL, strNode.c_str()); + g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str()); return NullUniValue; } From aaf018e3b79417ecfd39291a8c100df77969d77a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 24 May 2016 18:59:16 -0400 Subject: [PATCH 09/33] net: handle nodesignals in CConnman --- src/main.cpp | 5 +++-- src/net.cpp | 38 ++++++++++++++++++++++---------------- src/net.h | 3 ++- src/test/DoS_tests.cpp | 4 ++++ 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4dc9d71ee..bd85fa8f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -348,7 +348,8 @@ void InitializeNode(NodeId nodeid, const CNode *pnode) { state.address = pnode->addr; } -void FinalizeNode(NodeId nodeid) { +void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { + fUpdateConnectionTime = false; LOCK(cs_main); CNodeState *state = State(nodeid); @@ -356,7 +357,7 @@ void FinalizeNode(NodeId nodeid) { nSyncStarted--; if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { - AddressCurrentlyConnected(state->address); + fUpdateConnectionTime = true; } BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) { diff --git a/src/net.cpp b/src/net.cpp index 83a96205a..26bf477e9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -313,12 +313,6 @@ bool IsReachable(const CNetAddr& addr) return IsReachable(net); } -void AddressCurrentlyConnected(const CService& addr) -{ - addrman.Connected(addr); -} - - uint64_t CNode::nTotalBytesRecv = 0; uint64_t CNode::nTotalBytesSent = 0; CCriticalSection CNode::cs_totalBytesRecv; @@ -431,6 +425,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo // Add node CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); + GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); { @@ -1070,6 +1065,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } CNode* pnode = new CNode(hSocket, addr, "", true); + GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -1139,7 +1135,7 @@ void CConnman::ThreadSocketHandler() if (fDelete) { vNodesDisconnected.remove(pnode); - delete pnode; + DeleteNode(pnode); } } } @@ -2119,6 +2115,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError CNetAddr local; LookupHost("127.0.0.1", local, false); pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } // @@ -2194,19 +2191,32 @@ void CConnman::Stop() LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); // clean up some globals (to help leak detection) - BOOST_FOREACH(CNode *pnode, vNodes) - delete pnode; - BOOST_FOREACH(CNode *pnode, vNodesDisconnected) - delete pnode; + BOOST_FOREACH(CNode *pnode, vNodes) { + DeleteNode(pnode); + } + BOOST_FOREACH(CNode *pnode, vNodesDisconnected) { + DeleteNode(pnode); + } vNodes.clear(); vNodesDisconnected.clear(); vhListenSocket.clear(); delete semOutbound; semOutbound = NULL; - delete pnodeLocalHost; + if(pnodeLocalHost) + DeleteNode(pnodeLocalHost); pnodeLocalHost = NULL; } +void CConnman::DeleteNode(CNode* pnode) +{ + assert(pnode); + bool fUpdateConnectionTime = false; + GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime); + if(fUpdateConnectionTime) + addrman.Connected(pnode->addr); + delete pnode; +} + CConnman::~CConnman() { } @@ -2442,8 +2452,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa // Be shy and don't send version until we hear if (hSocket != INVALID_SOCKET && !fInbound) PushVersion(); - - GetNodeSignals().InitializeNode(GetId(), this); } CNode::~CNode() @@ -2452,8 +2460,6 @@ CNode::~CNode() if (pfilter) delete pfilter; - - GetNodeSignals().FinalizeNode(GetId()); } void CNode::AskFor(const CInv& inv) diff --git a/src/net.h b/src/net.h index e0c317ae4..b9dfaa0f4 100644 --- a/src/net.h +++ b/src/net.h @@ -121,6 +121,7 @@ private: void ThreadDNSAddressSeed(); CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure); + void DeleteNode(CNode* pnode); std::vector vhListenSocket; }; @@ -154,7 +155,7 @@ struct CNodeSignals boost::signals2::signal ProcessMessages; boost::signals2::signal SendMessages; boost::signals2::signal InitializeNode; - boost::signals2::signal FinalizeNode; + boost::signals2::signal FinalizeNode; }; diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 10529cda9..007ea79f9 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -47,6 +47,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CNode::ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned SendMessages(&dummyNode1, *connman); @@ -55,6 +56,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); SendMessages(&dummyNode2, *connman); @@ -71,6 +73,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); SendMessages(&dummyNode1, *connman); @@ -92,6 +95,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) CAddress addr(ip(0xa0b0c001), NODE_NONE); CNode dummyNode(INVALID_SOCKET, addr, "", true); + GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); dummyNode.nVersion = 1; Misbehaving(dummyNode.GetId(), 100); From a0f3d3cdad630103d919a4ec802c413b87fa1f1a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 17:43:11 -0400 Subject: [PATCH 10/33] net: move ban and addrman functions into CConnman --- src/main.cpp | 14 ++--- src/net.cpp | 126 ++++++++++++++++++++++++--------------- src/net.h | 89 ++++++++++++++------------- src/qt/bantablemodel.cpp | 3 +- src/qt/rpcconsole.cpp | 29 ++++----- src/rpc/net.cpp | 17 ++++-- src/test/DoS_tests.cpp | 28 ++++----- 7 files changed, 174 insertions(+), 132 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bd85fa8f0..f3babb71d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4944,7 +4944,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->nServices = ServiceFlags(nServiceInt); if (!pfrom->fInbound) { - addrman.SetServices(pfrom->addr, pfrom->nServices); + connman.SetServices(pfrom->addr, pfrom->nServices); } if (pfrom->nServicesExpected & ~pfrom->nServices) { @@ -5038,12 +5038,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Get recent addresses - if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) + if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000) { pfrom->PushMessage(NetMsgType::GETADDR); pfrom->fGetAddr = true; } - addrman.Good(pfrom->addr); + connman.MarkAddressGood(pfrom->addr); } pfrom->fSuccessfullyConnected = true; @@ -5108,7 +5108,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> vAddr; // Don't want addr from older versions unless seeding - if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) + if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000) return true; if (vAddr.size() > 1000) { @@ -5160,7 +5160,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (fReachable) vAddrOk.push_back(addr); } - addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60); + connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60); if (vAddr.size() < 1000) pfrom->fGetAddr = false; if (pfrom->fOneShot) @@ -5950,7 +5950,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->fSentAddr = true; pfrom->vAddrToSend.clear(); - vector vAddr = addrman.GetAddr(); + vector vAddr = connman.GetAddresses(); BOOST_FOREACH(const CAddress &addr, vAddr) pfrom->PushAddress(addr); } @@ -6393,7 +6393,7 @@ bool SendMessages(CNode* pto, CConnman& connman) LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); else { - CNode::Ban(pto->addr, BanReasonNodeMisbehaving); + connman.Ban(pto->addr, BanReasonNodeMisbehaving); } } state.fShouldBan = false; diff --git a/src/net.cpp b/src/net.cpp index 26bf477e9..eeb84fca7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -84,9 +84,7 @@ std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; -CAddrMan addrman; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; -bool fAddressesInitialized = false; std::string strSubVersion; std::vector vNodes; @@ -446,21 +444,21 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo return NULL; } -static void DumpBanlist() +void CConnman::DumpBanlist() { - CNode::SweepBanned(); // clean unused entries (if bantime has expired) + SweepBanned(); // clean unused entries (if bantime has expired) - if (!CNode::BannedSetIsDirty()) + if (!BannedSetIsDirty()) return; int64_t nStart = GetTimeMillis(); CBanDB bandb; banmap_t banmap; - CNode::SetBannedSetDirty(false); - CNode::GetBanned(banmap); + SetBannedSetDirty(false); + GetBanned(banmap); if (!bandb.Write(banmap)) - CNode::SetBannedSetDirty(true); + SetBannedSetDirty(true); LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); @@ -501,11 +499,7 @@ void CNode::PushVersion() -banmap_t CNode::setBanned; -CCriticalSection CNode::cs_setBanned; -bool CNode::setBannedIsDirty; - -void CNode::ClearBanned() +void CConnman::ClearBanned() { { LOCK(cs_setBanned); @@ -516,7 +510,7 @@ void CNode::ClearBanned() uiInterface.BannedListChanged(); } -bool CNode::IsBanned(CNetAddr ip) +bool CConnman::IsBanned(CNetAddr ip) { bool fResult = false; { @@ -533,7 +527,7 @@ bool CNode::IsBanned(CNetAddr ip) return fResult; } -bool CNode::IsBanned(CSubNet subnet) +bool CConnman::IsBanned(CSubNet subnet) { bool fResult = false; { @@ -549,12 +543,12 @@ bool CNode::IsBanned(CSubNet subnet) return fResult; } -void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { +void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { CSubNet subNet(addr); Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); } -void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { +void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { CBanEntry banEntry(GetTime()); banEntry.banReason = banReason; if (bantimeoffset <= 0) @@ -585,12 +579,12 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti DumpBanlist(); //store banlist to disk immediately if user requested ban } -bool CNode::Unban(const CNetAddr &addr) { +bool CConnman::Unban(const CNetAddr &addr) { CSubNet subNet(addr); return Unban(subNet); } -bool CNode::Unban(const CSubNet &subNet) { +bool CConnman::Unban(const CSubNet &subNet) { { LOCK(cs_setBanned); if (!setBanned.erase(subNet)) @@ -602,20 +596,20 @@ bool CNode::Unban(const CSubNet &subNet) { return true; } -void CNode::GetBanned(banmap_t &banMap) +void CConnman::GetBanned(banmap_t &banMap) { LOCK(cs_setBanned); banMap = setBanned; //create a thread safe copy } -void CNode::SetBanned(const banmap_t &banMap) +void CConnman::SetBanned(const banmap_t &banMap) { LOCK(cs_setBanned); setBanned = banMap; setBannedIsDirty = true; } -void CNode::SweepBanned() +void CConnman::SweepBanned() { int64_t now = GetTime(); @@ -636,13 +630,13 @@ void CNode::SweepBanned() } } -bool CNode::BannedSetIsDirty() +bool CConnman::BannedSetIsDirty() { LOCK(cs_setBanned); return setBannedIsDirty; } -void CNode::SetBannedSetDirty(bool dirty) +void CConnman::SetBannedSetDirty(bool dirty) { LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag setBannedIsDirty = dirty; @@ -1047,7 +1041,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); #endif - if (CNode::IsBanned(addr) && !whitelisted) + if (IsBanned(addr) && !whitelisted) { LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); CloseSocket(hSocket); @@ -1548,7 +1542,7 @@ void CConnman::ThreadDNSAddressSeed() -void DumpAddresses() +void CConnman::DumpAddresses() { int64_t nStart = GetTimeMillis(); @@ -1559,7 +1553,7 @@ void DumpAddresses() addrman.size(), GetTimeMillis() - nStart); } -void DumpData() +void CConnman::DumpData() { DumpAddresses(); DumpBanlist(); @@ -1813,7 +1807,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai boost::this_thread::interruption_point(); if (!pszDest) { if (IsLocal(addrConnect) || - FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || + FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort())) return false; } else if (FindNode(std::string(pszDest))) @@ -2054,10 +2048,22 @@ void static Discover(boost::thread_group& threadGroup) CConnman::CConnman() { + setBannedIsDirty = false; + fAddressesInitialized = false; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) { + Discover(threadGroup); + + bool ret = connman.Start(threadGroup, scheduler, strNodeError); + + return ret; +} + +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +{ + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2078,15 +2084,15 @@ bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& CBanDB bandb; banmap_t banmap; if (bandb.Read(banmap)) { - CNode::SetBanned(banmap); // thread save setter - CNode::SetBannedSetDirty(false); // no need to write down, just read data - CNode::SweepBanned(); // sweep out unused entries + SetBanned(banmap); // thread save setter + SetBannedSetDirty(false); // no need to write down, just read data + SweepBanned(); // sweep out unused entries LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); } else { LogPrintf("Invalid or missing banlist.dat; recreating\n"); - CNode::SetBannedSetDirty(true); // force write + SetBannedSetDirty(true); // force write DumpBanlist(); } @@ -2094,17 +2100,6 @@ bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& fAddressesInitialized = true; - Discover(threadGroup); - - bool ret = connman.Start(threadGroup, strNodeError); - - // Dump network addresses - scheduler.scheduleEvery(DumpData, DUMP_ADDRESSES_INTERVAL); - return ret; -} - -bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError) -{ if (semOutbound == NULL) { // initialize semaphore int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); @@ -2142,6 +2137,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError // Process messages threadGroup.create_thread(boost::bind(&TraceThread >, "msghand", boost::function(boost::bind(&CConnman::ThreadMessageHandler, this)))); + // Dump network addresses + scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL); + return true; } @@ -2150,12 +2148,6 @@ bool StopNode(CConnman& connman) LogPrintf("StopNode()\n"); MapPort(false); - if (fAddressesInitialized) - { - DumpData(); - fAddressesInitialized = false; - } - connman.Stop(); return true; } @@ -2181,6 +2173,12 @@ void CConnman::Stop() for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) semOutbound->post(); + if (fAddressesInitialized) + { + DumpData(); + fAddressesInitialized = false; + } + // Close sockets BOOST_FOREACH(CNode* pnode, vNodes) if (pnode->hSocket != INVALID_SOCKET) @@ -2221,6 +2219,36 @@ CConnman::~CConnman() { } +size_t CConnman::GetAddressCount() const +{ + return addrman.size(); +} + +void CConnman::SetServices(const CService &addr, ServiceFlags nServices) +{ + addrman.SetServices(addr, nServices); +} + +void CConnman::MarkAddressGood(const CAddress& addr) +{ + addrman.Good(addr); +} + +void CConnman::AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty) +{ + addrman.Add(addr, addrFrom, nTimePenalty); +} + +void CConnman::AddNewAddresses(const std::vector& vAddr, const CAddress& addrFrom, int64_t nTimePenalty) +{ + addrman.Add(vAddr, addrFrom, nTimePenalty); +} + +std::vector CConnman::GetAddresses() +{ + return addrman.GetAddr(); +} + void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); diff --git a/src/net.h b/src/net.h index b9dfaa0f4..65dafb4fd 100644 --- a/src/net.h +++ b/src/net.h @@ -7,6 +7,7 @@ #define BITCOIN_NET_H #include "addrdb.h" +#include "addrman.h" #include "amount.h" #include "bloom.h" #include "compat.h" @@ -87,7 +88,6 @@ unsigned int SendBufferSize(); typedef int NodeId; void AddOneShot(const std::string& strDest); -void AddressCurrentlyConnected(const CService& addr); CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); @@ -99,11 +99,44 @@ class CConnman public: CConnman(); ~CConnman(); - bool Start(boost::thread_group& threadGroup, std::string& strNodeError); + bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError); void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); + // Addrman functions + size_t GetAddressCount() const; + void SetServices(const CService &addr, ServiceFlags nServices); + void MarkAddressGood(const CAddress& addr); + void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0); + void AddNewAddresses(const std::vector& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0); + std::vector GetAddresses(); + void AddressCurrentlyConnected(const CService& addr); + + // Denial-of-service detection/prevention + // The idea is to detect peers that are behaving + // badly and disconnect/ban them, but do it in a + // one-coding-mistake-won't-shatter-the-entire-network + // way. + // IMPORTANT: There should be nothing I can give a + // node that it will forward on that will make that + // node's peers drop it. If there is, an attacker + // can isolate a node and/or try to split the network. + // Dropping a node for sending stuff that is invalid + // now but might be valid in a later version is also + // dangerous, because it can cause a network split + // between nodes running old code and nodes running + // new code. + void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + void ClearBanned(); // needed for unit testing + bool IsBanned(CNetAddr ip); + bool IsBanned(CSubNet subnet); + bool Unban(const CNetAddr &ip); + bool Unban(const CSubNet &ip); + void GetBanned(banmap_t &banmap); + void SetBanned(const banmap_t &banmap); + private: struct ListenSocket { SOCKET socket; @@ -122,8 +155,22 @@ private: CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure); void DeleteNode(CNode* pnode); + //!check is the banlist has unwritten changes + bool BannedSetIsDirty(); + //!set the "dirty" flag for the banlist + void SetBannedSetDirty(bool dirty=true); + //!clean unused entries (if bantime has expired) + void SweepBanned(); + void DumpAddresses(); + void DumpData(); + void DumpBanlist(); std::vector vhListenSocket; + banmap_t setBanned; + CCriticalSection cs_setBanned; + bool setBannedIsDirty; + bool fAddressesInitialized; + CAddrMan addrman; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); @@ -195,7 +242,6 @@ extern ServiceFlags nLocalServices; extern ServiceFlags nRelevantServices; extern bool fRelayTxes; extern uint64_t nLocalHostNonce; -extern CAddrMan addrman; /** Maximum number of connections to simultaneously allow (aka connection slots) */ extern int nMaxConnections; @@ -347,12 +393,6 @@ public: const uint64_t nKeyedNetGroup; protected: - // Denial-of-service detection/prevention - // Key is IP address, value is banned-until-time - static banmap_t setBanned; - static CCriticalSection cs_setBanned; - static bool setBannedIsDirty; - // Whitelisted ranges. Any node connecting from these is automatically // whitelisted (as well as those connecting to whitelisted binds). static std::vector vWhitelistedRange; @@ -722,37 +762,6 @@ public: void CloseSocketDisconnect(); - // Denial-of-service detection/prevention - // The idea is to detect peers that are behaving - // badly and disconnect/ban them, but do it in a - // one-coding-mistake-won't-shatter-the-entire-network - // way. - // IMPORTANT: There should be nothing I can give a - // node that it will forward on that will make that - // node's peers drop it. If there is, an attacker - // can isolate a node and/or try to split the network. - // Dropping a node for sending stuff that is invalid - // now but might be valid in a later version is also - // dangerous, because it can cause a network split - // between nodes running old code and nodes running - // new code. - static void ClearBanned(); // needed for unit testing - static bool IsBanned(CNetAddr ip); - static bool IsBanned(CSubNet subnet); - static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); - static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); - static bool Unban(const CNetAddr &ip); - static bool Unban(const CSubNet &ip); - static void GetBanned(banmap_t &banmap); - static void SetBanned(const banmap_t &banmap); - - //!check is the banlist has unwritten changes - static bool BannedSetIsDirty(); - //!set the "dirty" flag for the banlist - static void SetBannedSetDirty(bool dirty=true); - //!clean unused entries (if bantime has expired) - static void SweepBanned(); - void copyStats(CNodeStats &stats); static bool IsWhitelistedRange(const CNetAddr &ip); diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index d95106b5a..6e11e2390 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -48,7 +48,8 @@ public: void refreshBanlist() { banmap_t banMap; - CNode::GetBanned(banMap); + if(g_connman) + g_connman->GetBanned(banMap); cachedBanlist.clear(); #if QT_VERSION >= 0x040700 diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index e5720dd70..708be6b64 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -887,26 +887,23 @@ void RPCConsole::disconnectSelectedNode() void RPCConsole::banSelectedNode(int bantime) { - if (!clientModel) + if (!clientModel || !g_connman) return; // Get currently selected peer address QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString(); // Find possible nodes, ban it and clear the selected node - if (FindNode(strNode.toStdString())) { - std::string nStr = strNode.toStdString(); - std::string addr; - int port = 0; - SplitHostPort(nStr, port, addr); - - CNetAddr resolved; - if(!LookupHost(addr.c_str(), resolved, false)) - return; - CNode::Ban(resolved, BanReasonManuallyAdded, bantime); + std::string nStr = strNode.toStdString(); + std::string addr; + int port = 0; + SplitHostPort(nStr, port, addr); - clearSelectedNode(); - clientModel->getBanTableModel()->refresh(); - } + CNetAddr resolved; + if(!LookupHost(addr.c_str(), resolved, false)) + return; + g_connman->Ban(resolved, BanReasonManuallyAdded, bantime); + clearSelectedNode(); + clientModel->getBanTableModel()->refresh(); } void RPCConsole::unbanSelectedNode() @@ -919,9 +916,9 @@ void RPCConsole::unbanSelectedNode() CSubNet possibleSubnet; LookupSubNet(strNode.toStdString().c_str(), possibleSubnet); - if (possibleSubnet.IsValid()) + if (possibleSubnet.IsValid() && g_connman) { - CNode::Unban(possibleSubnet); + g_connman->Unban(possibleSubnet); clientModel->getBanTableModel()->refresh(); } } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index edf33c70b..0244da9fe 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -488,6 +488,8 @@ UniValue setban(const UniValue& params, bool fHelp) + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); CSubNet subNet; CNetAddr netAddr; @@ -509,7 +511,7 @@ UniValue setban(const UniValue& params, bool fHelp) if (strCommand == "add") { - if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr)) + if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr)) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); int64_t banTime = 0; //use standard bantime if not specified @@ -520,11 +522,11 @@ UniValue setban(const UniValue& params, bool fHelp) if (params.size() == 4 && params[3].isTrue()) absolute = true; - isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); + isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); } else if(strCommand == "remove") { - if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) )) + if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) )) throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); } return NullUniValue; @@ -541,8 +543,11 @@ UniValue listbanned(const UniValue& params, bool fHelp) + HelpExampleRpc("listbanned", "") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + banmap_t banMap; - CNode::GetBanned(banMap); + g_connman->GetBanned(banMap); UniValue bannedAddresses(UniValue::VARR); for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++) @@ -570,8 +575,10 @@ UniValue clearbanned(const UniValue& params, bool fHelp) + HelpExampleCli("clearbanned", "") + HelpExampleRpc("clearbanned", "") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - CNode::ClearBanned(); + g_connman->ClearBanned(); return NullUniValue; } diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 007ea79f9..412f94f40 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -44,15 +44,15 @@ BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) BOOST_AUTO_TEST_CASE(DoS_banning) { - CNode::ClearBanned(); + connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(INVALID_SOCKET, addr1, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned SendMessages(&dummyNode1, *connman); - BOOST_CHECK(CNode::IsBanned(addr1)); - BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned + BOOST_CHECK(connman->IsBanned(addr1)); + BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(INVALID_SOCKET, addr2, "", true); @@ -60,16 +60,16 @@ BOOST_AUTO_TEST_CASE(DoS_banning) dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); SendMessages(&dummyNode2, *connman); - BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... - BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be + BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet... + BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be Misbehaving(dummyNode2.GetId(), 50); SendMessages(&dummyNode2, *connman); - BOOST_CHECK(CNode::IsBanned(addr2)); + BOOST_CHECK(connman->IsBanned(addr2)); } BOOST_AUTO_TEST_CASE(DoS_banscore) { - CNode::ClearBanned(); + connman->ClearBanned(); mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(INVALID_SOCKET, addr1, "", true); @@ -77,19 +77,19 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); SendMessages(&dummyNode1, *connman); - BOOST_CHECK(!CNode::IsBanned(addr1)); + BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10); SendMessages(&dummyNode1, *connman); - BOOST_CHECK(!CNode::IsBanned(addr1)); + BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1); SendMessages(&dummyNode1, *connman); - BOOST_CHECK(CNode::IsBanned(addr1)); + BOOST_CHECK(connman->IsBanned(addr1)); mapArgs.erase("-banscore"); } BOOST_AUTO_TEST_CASE(DoS_bantime) { - CNode::ClearBanned(); + connman->ClearBanned(); int64_t nStartTime = GetTime(); SetMockTime(nStartTime); // Overrides future calls to GetTime() @@ -100,13 +100,13 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) Misbehaving(dummyNode.GetId(), 100); SendMessages(&dummyNode, *connman); - BOOST_CHECK(CNode::IsBanned(addr)); + BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime+60*60); - BOOST_CHECK(CNode::IsBanned(addr)); + BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime+60*60*24+1); - BOOST_CHECK(!CNode::IsBanned(addr)); + BOOST_CHECK(!connman->IsBanned(addr)); } CTransaction RandomOrphan() From 502dd3a8a0bc0d12744e75f84a22cc12074c5683 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 17:51:01 -0400 Subject: [PATCH 11/33] net: Add oneshot functions to CConnman --- src/init.cpp | 2 +- src/net.cpp | 5 +---- src/net.h | 4 +++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index b0ffb7a40..719b648c0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1230,7 +1230,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"]) - AddOneShot(strDest); + connman.AddOneShot(strDest); #if ENABLE_ZMQ pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs); diff --git a/src/net.cpp b/src/net.cpp index eeb84fca7..045939c2e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -91,9 +91,6 @@ std::vector vNodes; CCriticalSection cs_vNodes; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -static std::deque vOneShots; -CCriticalSection cs_vOneShots; - std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; @@ -107,7 +104,7 @@ boost::condition_variable messageHandlerCondition; static CNodeSignals g_signals; CNodeSignals& GetNodeSignals() { return g_signals; } -void AddOneShot(const std::string& strDest) +void CConnman::AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); vOneShots.push_back(strDest); diff --git a/src/net.h b/src/net.h index 65dafb4fd..81de7f5a9 100644 --- a/src/net.h +++ b/src/net.h @@ -87,7 +87,6 @@ unsigned int SendBufferSize(); typedef int NodeId; -void AddOneShot(const std::string& strDest); CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); @@ -137,6 +136,7 @@ public: void GetBanned(banmap_t &banmap); void SetBanned(const banmap_t &banmap); + void AddOneShot(const std::string& strDest); private: struct ListenSocket { SOCKET socket; @@ -171,6 +171,8 @@ private: bool setBannedIsDirty; bool fAddressesInitialized; CAddrMan addrman; + std::deque vOneShots; + CCriticalSection cs_vOneShots; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); From 8ae2dac1c65349e4620422a43b7fa9d49af52c11 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 18:12:58 -0400 Subject: [PATCH 12/33] net: move added node functions to CConnman --- src/net.cpp | 29 +++++++++++++++++++++++++---- src/net.h | 28 +++++++++++++++------------- src/rpc/net.cpp | 17 ++++++----------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 045939c2e..8ca6df0f9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -91,9 +91,6 @@ std::vector vNodes; CCriticalSection cs_vNodes; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -std::vector vAddedNodes; -CCriticalSection cs_vAddedNodes; - NodeId nLastNodeId = 0; CCriticalSection cs_nLastNodeId; @@ -1718,7 +1715,7 @@ void CConnman::ThreadOpenConnections() } } -std::vector GetAddedNodeInfo() +std::vector CConnman::GetAddedNodeInfo() { std::vector ret; @@ -2246,6 +2243,30 @@ std::vector CConnman::GetAddresses() return addrman.GetAddr(); } +bool CConnman::AddNode(const std::string& strNode) +{ + LOCK(cs_vAddedNodes); + for(std::vector::const_iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) { + if (strNode == *it) + return false; + } + + vAddedNodes.push_back(strNode); + return true; +} + +bool CConnman::RemoveAddedNode(const std::string& strNode) +{ + LOCK(cs_vAddedNodes); + for(std::vector::iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) { + if (strNode == *it) { + vAddedNodes.erase(it); + return true; + } + } + return false; +} + void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); diff --git a/src/net.h b/src/net.h index 81de7f5a9..f343646cb 100644 --- a/src/net.h +++ b/src/net.h @@ -87,6 +87,14 @@ unsigned int SendBufferSize(); typedef int NodeId; +struct AddedNodeInfo +{ + std::string strAddedNode; + CService resolvedAddress; + bool fConnected; + bool fInbound; +}; + CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); @@ -137,6 +145,11 @@ public: void SetBanned(const banmap_t &banmap); void AddOneShot(const std::string& strDest); + + bool AddNode(const std::string& node); + bool RemoveAddedNode(const std::string& node); + std::vector GetAddedNodeInfo(); + private: struct ListenSocket { SOCKET socket; @@ -173,6 +186,8 @@ private: CAddrMan addrman; std::deque vOneShots; CCriticalSection cs_vOneShots; + std::vector vAddedNodes; + CCriticalSection cs_vAddedNodes; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); @@ -252,9 +267,6 @@ extern std::vector vNodes; extern CCriticalSection cs_vNodes; extern limitedmap mapAlreadyAskedFor; -extern std::vector vAddedNodes; -extern CCriticalSection cs_vAddedNodes; - extern NodeId nLastNodeId; extern CCriticalSection cs_nLastNodeId; @@ -807,14 +819,4 @@ void RelayTransaction(const CTransaction& tx); /** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds); -struct AddedNodeInfo -{ - std::string strAddedNode; - CService resolvedAddress; - bool fConnected; - bool fInbound; -}; - -std::vector GetAddedNodeInfo(); - #endif // BITCOIN_NET_H diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 0244da9fe..ab475f712 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -226,23 +226,15 @@ UniValue addnode(const UniValue& params, bool fHelp) return NullUniValue; } - LOCK(cs_vAddedNodes); - vector::iterator it = vAddedNodes.begin(); - for(; it != vAddedNodes.end(); it++) - if (strNode == *it) - break; - if (strCommand == "add") { - if (it != vAddedNodes.end()) + if(!g_connman->AddNode(strNode)) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); - vAddedNodes.push_back(strNode); } else if(strCommand == "remove") { - if (it == vAddedNodes.end()) + if(!g_connman->RemoveAddedNode(strNode)) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); - vAddedNodes.erase(it); } return NullUniValue; @@ -299,7 +291,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"") ); - std::vector vInfo = GetAddedNodeInfo(); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + + std::vector vInfo = g_connman->GetAddedNodeInfo(); if (params.size() == 1) { bool found = false; From c0569c7fa1e25599b3f1d6a16b15ec23052021da Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 18:30:03 -0400 Subject: [PATCH 13/33] net: Add most functions needed for vNodes to CConnman --- src/net.cpp | 66 +++++++++++++++++++++++++++++++++++++++ src/net.h | 16 ++++++++++ src/qt/clientmodel.cpp | 22 +++++++------ src/qt/peertablemodel.cpp | 15 ++++----- src/qt/rpcconsole.cpp | 8 ++--- src/rpc/mining.cpp | 5 ++- src/rpc/misc.cpp | 3 +- src/rpc/net.cpp | 36 ++++++++------------- 8 files changed, 123 insertions(+), 48 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 8ca6df0f9..e1cfc565d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2267,6 +2267,72 @@ bool CConnman::RemoveAddedNode(const std::string& strNode) return false; } +size_t CConnman::GetNodeCount(NumConnections flags) +{ + LOCK(cs_vNodes); + if (flags == CConnman::CONNECTIONS_ALL) // Shortcut if we want total + return vNodes.size(); + + int nNum = 0; + for(std::vector::const_iterator it = vNodes.begin(); it != vNodes.end(); ++it) + if (flags & ((*it)->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) + nNum++; + + return nNum; +} + +void CConnman::GetNodeStats(std::vector& vstats) +{ + vstats.clear(); + LOCK(cs_vNodes); + vstats.reserve(vNodes.size()); + for(std::vector::iterator it = vNodes.begin(); it != vNodes.end(); ++it) { + CNode* pnode = *it; + CNodeStats stats; + pnode->copyStats(stats); + vstats.push_back(stats); + } +} + +bool CConnman::DisconnectAddress(const CNetAddr& netAddr) +{ + if (CNode* pnode = FindNode(netAddr)) { + pnode->fDisconnect = true; + return true; + } + return false; +} + +bool CConnman::DisconnectSubnet(const CSubNet& subNet) +{ + if (CNode* pnode = FindNode(subNet)) { + pnode->fDisconnect = true; + return true; + } + return false; +} + +bool CConnman::DisconnectNode(const std::string& strNode) +{ + if (CNode* pnode = FindNode(strNode)) { + pnode->fDisconnect = true; + return true; + } + return false; +} + +bool CConnman::DisconnectNode(NodeId id) +{ + LOCK(cs_vNodes); + for(CNode* pnode : vNodes) { + if (id == pnode->id) { + pnode->fDisconnect = true; + return true; + } + } + return false; +} + void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); diff --git a/src/net.h b/src/net.h index f343646cb..9e2408cd7 100644 --- a/src/net.h +++ b/src/net.h @@ -101,9 +101,18 @@ CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); CNode* FindNode(const NodeId id); //TODO: Remove this +class CNodeStats; class CConnman { public: + + enum NumConnections { + CONNECTIONS_NONE = 0, + CONNECTIONS_IN = (1U << 0), + CONNECTIONS_OUT = (1U << 1), + CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT), + }; + CConnman(); ~CConnman(); bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError); @@ -150,6 +159,13 @@ public: bool RemoveAddedNode(const std::string& node); std::vector GetAddedNodeInfo(); + size_t GetNodeCount(NumConnections num); + void GetNodeStats(std::vector& vstats); + bool DisconnectAddress(const CNetAddr& addr); + bool DisconnectNode(const std::string& node); + bool DisconnectNode(NodeId id); + bool DisconnectSubnet(const CSubNet& subnet); + private: struct ListenSocket { SOCKET socket; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 14661b857..f72bbfe6b 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -50,16 +50,18 @@ ClientModel::~ClientModel() int ClientModel::getNumConnections(unsigned int flags) const { - LOCK(cs_vNodes); - if (flags == CONNECTIONS_ALL) // Shortcut if we want total - return vNodes.size(); - - int nNum = 0; - BOOST_FOREACH(const CNode* pnode, vNodes) - if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) - nNum++; - - return nNum; + CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE; + + if(flags == CONNECTIONS_IN) + connections = CConnman::CONNECTIONS_IN; + else if (flags == CONNECTIONS_OUT) + connections = CConnman::CONNECTIONS_OUT; + else if (flags == CONNECTIONS_ALL) + connections = CConnman::CONNECTIONS_ALL; + + if(g_connman) + return g_connman->GetNodeCount(connections); + return 0; } int ClientModel::getNumBlocks() const diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 0eb28f4ae..a820bd791 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -54,24 +54,21 @@ public: void refreshPeers() { { - TRY_LOCK(cs_vNodes, lockNodes); - if (!lockNodes) - { - // skip the refresh if we can't immediately get the lock - return; - } cachedNodeStats.clear(); + std::vector vstats; + if(g_connman) + g_connman->GetNodeStats(vstats); #if QT_VERSION >= 0x040700 - cachedNodeStats.reserve(vNodes.size()); + cachedNodeStats.reserve(vstats.size()); #endif - Q_FOREACH (CNode* pnode, vNodes) + Q_FOREACH (const CNodeStats& nodestats, vstats) { CNodeCombinedStats stats; stats.nodeStateStats.nMisbehavior = 0; stats.nodeStateStats.nSyncHeight = -1; stats.nodeStateStats.nCommonHeight = -1; stats.fNodeStateStatsAvailable = false; - pnode->copyStats(stats.nodeStats); + stats.nodeStats = nodestats; cachedNodeStats.append(stats); } } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 708be6b64..f35f401d0 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -876,13 +876,13 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point) void RPCConsole::disconnectSelectedNode() { + if(!g_connman) + return; // Get currently selected peer address - QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString(); + NodeId id = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::NetNodeId).toInt(); // Find the node, disconnect it and clear the selected node - if (CNode *bannedNode = FindNode(strNode.toStdString())) { - bannedNode->fDisconnect = true; + if(g_connman->DisconnectNode(id)) clearSelectedNode(); - } } void RPCConsole::banSelectedNode(int bantime) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 63ecf49ec..7794ac619 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -457,7 +457,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (strMode != "template") throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - if (vNodes.empty()) + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + + if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!"); if (IsInitialBlockDownload()) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index e96feaa86..f9f161561 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -89,7 +89,8 @@ UniValue getinfo(const UniValue& params, bool fHelp) #endif obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("timeoffset", GetTimeOffset())); - obj.push_back(Pair("connections", (int)vNodes.size())); + if(g_connman) + obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index ab475f712..0d494a2e7 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -36,9 +36,10 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp) + HelpExampleRpc("getconnectioncount", "") ); - LOCK2(cs_main, cs_vNodes); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - return (int)vNodes.size(); + return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL); } UniValue ping(const UniValue& params, bool fHelp) @@ -64,19 +65,6 @@ UniValue ping(const UniValue& params, bool fHelp) return NullUniValue; } -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); - } -} - UniValue getpeerinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -127,10 +115,11 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) + HelpExampleRpc("getpeerinfo", "") ); - LOCK(cs_main); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); vector vstats; - CopyNodeStats(vstats); + g_connman->GetNodeStats(vstats); UniValue ret(UniValue::VARR); @@ -253,11 +242,12 @@ UniValue disconnectnode(const UniValue& params, bool fHelp) + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") ); - CNode* pNode = FindNode(params[0].get_str()); - if (pNode == NULL) - throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - pNode->fDisconnect = true; + bool ret = g_connman->DisconnectNode(params[0].get_str()); + if (!ret) + throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); return NullUniValue; } @@ -435,7 +425,6 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) ); LOCK(cs_main); - UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("subversion", strSubVersion)); @@ -443,7 +432,8 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); obj.push_back(Pair("localrelay", fRelayTxes)); obj.push_back(Pair("timeoffset", GetTimeOffset())); - obj.push_back(Pair("connections", (int)vNodes.size())); + if(g_connman) + obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); UniValue localAddresses(UniValue::VARR); From 53347f0cb99e514815e44a56439a4a10012238f8 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 19:13:12 -0400 Subject: [PATCH 14/33] net: create generic functor accessors and move vNodes to CConnman --- src/main.cpp | 85 ++++++++++++++++++++++++-------------- src/net.cpp | 83 ++++++++++++++++++++++++++++--------- src/net.h | 27 +++++++----- src/rpc/misc.cpp | 9 ++-- src/rpc/net.cpp | 13 +++--- src/rpc/rawtransaction.cpp | 9 +++- src/wallet/wallet.cpp | 11 ++++- 7 files changed, 164 insertions(+), 73 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f3babb71d..af598d487 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -470,7 +470,7 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { } } -void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom) { +void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom, CConnman& connman) { if (nLocalServices & NODE_WITNESS) { // Don't ever request compact blocks when segwit is enabled. return; @@ -484,11 +484,12 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { // As per BIP152, we only get 3 of our peers to announce // blocks using compact encodings. - CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front()); - if (pnodeStop) { + bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){ pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); + return true; + }); + if(found) lNodesAnnouncingHeaderAndIDs.pop_front(); - } } fAnnounceUsingCMPCTBLOCK = true; pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); @@ -3089,15 +3090,15 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, int nBlockEstimate = 0; if (fCheckpointsEnabled) nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) { + if(connman) { + connman->ForEachNode([nNewHeight, nBlockEstimate, &vHashes](CNode* pnode) { if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) { pnode->PushBlockHash(hash); } } - } + return true; + }); } // Notify external listeners about the new tip. if (!vHashes.empty()) { @@ -4726,6 +4727,45 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) return true; } +static void RelayTransaction(const CTransaction& tx, CConnman& connman) +{ + CInv inv(MSG_TX, tx.GetHash()); + connman.ForEachNode([&inv](CNode* pnode) + { + pnode->PushInventory(inv); + return true; + }); +} + +static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman) +{ + int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) + + // Relay to a limited number of other nodes + // Use deterministic randomness to send to the same nodes for 24 hours + // at a time so the addrKnowns of the chosen nodes prevent repeats + static const uint64_t salt0 = GetRand(std::numeric_limits::max()); + static const uint64_t salt1 = GetRand(std::numeric_limits::max()); + uint64_t hashAddr = addr.GetHash(); + std::multimap mapMix; + const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); + + auto sortfunc = [&mapMix, &hasher](CNode* pnode) { + if (pnode->nVersion >= CADDR_TIME_VERSION) { + uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize(); + mapMix.emplace(hashKey, pnode); + } + return true; + }; + + auto pushfunc = [&addr, &mapMix, &nRelayNodes] { + for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) + mi->second->PushAddress(addr); + }; + + connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); +} + void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) { std::deque::iterator it = pfrom->vRecvGetData.begin(); @@ -5135,26 +5175,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) { // Relay to a limited number of other nodes - { - LOCK(cs_vNodes); - // Use deterministic randomness to send to the same nodes for 24 hours - // at a time so the addrKnowns of the chosen nodes prevent repeats - static const uint64_t salt0 = GetRand(std::numeric_limits::max()); - static const uint64_t salt1 = GetRand(std::numeric_limits::max()); - uint64_t hashAddr = addr.GetHash(); - multimap mapMix; - const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); - BOOST_FOREACH(CNode* pnode, vNodes) - { - if (pnode->nVersion < CADDR_TIME_VERSION) - continue; - uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize(); - mapMix.insert(make_pair(hashKey, pnode)); - } - int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) - for (multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) - ((*mi).second)->PushAddress(addr); - } + RelayAddress(addr, fReachable, connman); } // Do not store addresses outside our network if (fReachable) @@ -5448,7 +5469,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { mempool.check(pcoinsTip); - RelayTransaction(tx); + RelayTransaction(tx, connman); for (unsigned int i = 0; i < tx.vout.size(); i++) { vWorkQueue.emplace_back(inv.hash, i); } @@ -5485,7 +5506,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, continue; if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); - RelayTransaction(orphanTx); + RelayTransaction(orphanTx, connman); for (unsigned int i = 0; i < orphanTx.vout.size(); i++) { vWorkQueue.emplace_back(orphanHash, i); } @@ -5560,7 +5581,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int nDoS = 0; if (!state.IsInvalid(nDoS) || nDoS == 0) { LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); - RelayTransaction(tx); + RelayTransaction(tx, connman); } else { LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); } @@ -5886,7 +5907,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(nLocalServices & NODE_WITNESS)) { // We seem to be rather well-synced, so it appears pfrom was the first to provide us // with this block! Let's get them to announce using compact blocks in the future. - MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom); + MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman); // In any case, we want to download using a compact block, not a regular one vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); } diff --git a/src/net.cpp b/src/net.cpp index e1cfc565d..f20f63e04 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -87,8 +87,6 @@ uint64_t nLocalHostNonce = 0; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; std::string strSubVersion; -std::vector vNodes; -CCriticalSection cs_vNodes; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); NodeId nLastNodeId = 0; @@ -315,7 +313,7 @@ uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0; uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day uint64_t CNode::nMaxOutboundCycleStartTime = 0; -CNode* FindNode(const CNetAddr& ip) +CNode* CConnman::FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -324,7 +322,7 @@ CNode* FindNode(const CNetAddr& ip) return NULL; } -CNode* FindNode(const CSubNet& subNet) +CNode* CConnman::FindNode(const CSubNet& subNet) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -333,7 +331,7 @@ CNode* FindNode(const CSubNet& subNet) return NULL; } -CNode* FindNode(const std::string& addrName) +CNode* CConnman::FindNode(const std::string& addrName) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -342,7 +340,7 @@ CNode* FindNode(const std::string& addrName) return NULL; } -CNode* FindNode(const CService& addr) +CNode* CConnman::FindNode(const CService& addr) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -351,16 +349,6 @@ CNode* FindNode(const CService& addr) return NULL; } -//TODO: This is used in only one place in main, and should be removed -CNode* FindNode(const NodeId nodeid) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->GetId() == nodeid) - return (pnode); - return NULL; -} - CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { @@ -899,7 +887,8 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction * to forge. In order to partition a node the attacker must be * simultaneously better at all of them than honest peers. */ -static bool AttemptToEvictConnection() { +bool CConnman::AttemptToEvictConnection() +{ std::vector vEvictionCandidates; { LOCK(cs_vNodes); @@ -2320,7 +2309,6 @@ bool CConnman::DisconnectNode(const std::string& strNode) } return false; } - bool CConnman::DisconnectNode(NodeId id) { LOCK(cs_vNodes); @@ -2333,7 +2321,7 @@ bool CConnman::DisconnectNode(NodeId id) return false; } -void RelayTransaction(const CTransaction& tx) +void CConnman::RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); LOCK(cs_vNodes); @@ -2671,6 +2659,63 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) LEAVE_CRITICAL_SECTION(cs_vSend); } +bool CConnman::ForNode(NodeId id, std::function func) +{ + CNode* found = nullptr; + LOCK(cs_vNodes); + for (auto&& pnode : vNodes) { + if(pnode->id == id) { + found = pnode; + break; + } + } + return found != nullptr && func(found); +} + +bool CConnman::ForEachNode(std::function func) +{ + LOCK(cs_vNodes); + for (auto&& node : vNodes) + if(!func(node)) + return false; + return true; +} + +bool CConnman::ForEachNode(std::function func) const +{ + LOCK(cs_vNodes); + for (const auto& node : vNodes) + if(!func(node)) + return false; + return true; +} + +bool CConnman::ForEachNodeThen(std::function pre, std::function post) +{ + bool ret = true; + LOCK(cs_vNodes); + for (auto&& node : vNodes) + if(!pre(node)) { + ret = false; + break; + } + post(); + return ret; +} + +bool CConnman::ForEachNodeThen(std::function pre, std::function post) const +{ + bool ret = true; + LOCK(cs_vNodes); + for (const auto& node : vNodes) + if(!pre(node)) { + ret = false; + break; + } + post(); + return ret; +} + int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } diff --git a/src/net.h b/src/net.h index 9e2408cd7..5b1e80bfb 100644 --- a/src/net.h +++ b/src/net.h @@ -95,12 +95,7 @@ struct AddedNodeInfo bool fInbound; }; -CNode* FindNode(const CNetAddr& ip); -CNode* FindNode(const CSubNet& subNet); -CNode* FindNode(const std::string& addrName); -CNode* FindNode(const CService& ip); -CNode* FindNode(const NodeId id); //TODO: Remove this - +class CTransaction; class CNodeStats; class CConnman { @@ -120,6 +115,14 @@ public: bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); + bool ForNode(NodeId id, std::function func); + bool ForEachNode(std::function func); + bool ForEachNode(std::function func) const; + bool ForEachNodeThen(std::function pre, std::function post); + bool ForEachNodeThen(std::function pre, std::function post) const; + + void RelayTransaction(const CTransaction& tx); + // Addrman functions size_t GetAddressCount() const; void SetServices(const CService &addr, ServiceFlags nServices); @@ -182,6 +185,12 @@ private: void ThreadSocketHandler(); void ThreadDNSAddressSeed(); + CNode* FindNode(const CNetAddr& ip); + CNode* FindNode(const CSubNet& subNet); + CNode* FindNode(const std::string& addrName); + CNode* FindNode(const CService& addr); + + bool AttemptToEvictConnection(); CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure); void DeleteNode(CNode* pnode); //!check is the banlist has unwritten changes @@ -204,6 +213,8 @@ private: CCriticalSection cs_vOneShots; std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; + std::vector vNodes; + mutable CCriticalSection cs_vNodes; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); @@ -279,8 +290,6 @@ extern uint64_t nLocalHostNonce; /** Maximum number of connections to simultaneously allow (aka connection slots) */ extern int nMaxConnections; -extern std::vector vNodes; -extern CCriticalSection cs_vNodes; extern limitedmap mapAlreadyAskedFor; extern NodeId nLastNodeId; @@ -828,8 +837,6 @@ public: -class CTransaction; -void RelayTransaction(const CTransaction& tx); /** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index f9f161561..ffd377b48 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -472,14 +472,17 @@ UniValue setmocktime(const UniValue& params, bool fHelp) // atomically with the time change to prevent peers from being // disconnected because we think we haven't communicated with them // in a long time. - LOCK2(cs_main, cs_vNodes); + LOCK(cs_main); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); SetMockTime(params[0].get_int64()); uint64_t t = GetTime(); - BOOST_FOREACH(CNode* pnode, vNodes) { - pnode->nLastSend = pnode->nLastRecv = t; + if(g_connman) { + g_connman->ForEachNode([t](CNode* pnode) { + pnode->nLastSend = pnode->nLastRecv = t; + return true; + }); } return NullUniValue; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 0d494a2e7..509b57aa7 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -55,13 +55,14 @@ UniValue ping(const UniValue& params, bool fHelp) + HelpExampleRpc("ping", "") ); - // Request that each node send a ping during next message processing pass - LOCK2(cs_main, cs_vNodes); - - BOOST_FOREACH(CNode* pNode, vNodes) { - pNode->fPingQueued = true; - } + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + // Request that each node send a ping during next message processing pass + g_connman->ForEachNode([](CNode* pnode) { + pnode->fPingQueued = true; + return true; + }); return NullUniValue; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 9461a7280..3daf1681f 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -891,8 +891,15 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); } - RelayTransaction(tx); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + CInv inv(MSG_TX, hashTx); + g_connman->ForEachNode([&inv](CNode* pnode) + { + pnode->PushInventory(inv); + return true; + }); return hashTx.GetHex(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 4396c2a2b..fd8b056bf 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1460,8 +1460,15 @@ bool CWalletTx::RelayWalletTransaction(CConnman* connman) { if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); - RelayTransaction((CTransaction)*this); - return true; + if (connman) { + CInv inv(MSG_TX, GetHash()); + connman->ForEachNode([&inv](CNode* pnode) + { + pnode->PushInventory(inv); + return true; + }); + return true; + } } } return false; From 6c19d92361fe4afb26dfa5d48a0748b84bca6f12 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 17 Apr 2016 18:34:32 -0400 Subject: [PATCH 15/33] net: move whitelist functions into CConnman --- src/init.cpp | 2 +- src/net.cpp | 9 +++------ src/net.h | 16 ++++++++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 719b648c0..f618e5ccc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1146,7 +1146,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LookupSubNet(net.c_str(), subnet); if (!subnet.IsValid()) return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); - CNode::AddWhitelistedRange(subnet); + connman.AddWhitelistedRange(subnet); } } diff --git a/src/net.cpp b/src/net.cpp index f20f63e04..eb312ef1e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -625,10 +625,7 @@ void CConnman::SetBannedSetDirty(bool dirty) } -std::vector CNode::vWhitelistedRange; -CCriticalSection CNode::cs_vWhitelistedRange; - -bool CNode::IsWhitelistedRange(const CNetAddr &addr) { +bool CConnman::IsWhitelistedRange(const CNetAddr &addr) { LOCK(cs_vWhitelistedRange); BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) { if (subnet.Match(addr)) @@ -637,7 +634,7 @@ bool CNode::IsWhitelistedRange(const CNetAddr &addr) { return false; } -void CNode::AddWhitelistedRange(const CSubNet &subnet) { +void CConnman::AddWhitelistedRange(const CSubNet &subnet) { LOCK(cs_vWhitelistedRange); vWhitelistedRange.push_back(subnet); } @@ -992,7 +989,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) LogPrintf("Warning: Unknown socket family\n"); - bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr); + bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr); { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) diff --git a/src/net.h b/src/net.h index 5b1e80bfb..8d9925265 100644 --- a/src/net.h +++ b/src/net.h @@ -169,6 +169,7 @@ public: bool DisconnectNode(NodeId id); bool DisconnectSubnet(const CSubNet& subnet); + void AddWhitelistedRange(const CSubNet &subnet); private: struct ListenSocket { SOCKET socket; @@ -192,6 +193,8 @@ private: bool AttemptToEvictConnection(); CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure); + bool IsWhitelistedRange(const CNetAddr &addr); + void DeleteNode(CNode* pnode); //!check is the banlist has unwritten changes bool BannedSetIsDirty(); @@ -203,6 +206,11 @@ private: void DumpData(); void DumpBanlist(); + // Whitelisted ranges. Any node connecting from these is automatically + // whitelisted (as well as those connecting to whitelisted binds). + std::vector vWhitelistedRange; + CCriticalSection cs_vWhitelistedRange; + std::vector vhListenSocket; banmap_t setBanned; CCriticalSection cs_setBanned; @@ -432,11 +440,6 @@ public: const uint64_t nKeyedNetGroup; protected: - // Whitelisted ranges. Any node connecting from these is automatically - // whitelisted (as well as those connecting to whitelisted binds). - static std::vector vWhitelistedRange; - static CCriticalSection cs_vWhitelistedRange; - mapMsgCmdSize mapSendBytesPerMsgCmd; mapMsgCmdSize mapRecvBytesPerMsgCmd; @@ -803,9 +806,6 @@ public: void copyStats(CNodeStats &stats); - static bool IsWhitelistedRange(const CNetAddr &ip); - static void AddWhitelistedRange(const CSubNet &subnet); - // Network stats static void RecordBytesRecv(uint64_t bytes); static void RecordBytesSent(uint64_t bytes); From 551e0887db9034b1e6490a267ba864b1d26ff469 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 17 Apr 2016 20:20:34 -0400 Subject: [PATCH 16/33] net: move nLastNodeId to CConnman --- src/net.cpp | 24 +++++++++++------------- src/net.h | 9 +++++---- src/test/DoS_tests.cpp | 10 ++++++---- src/test/net_tests.cpp | 5 +++-- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index eb312ef1e..8bc8ecc43 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -89,9 +89,6 @@ std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -NodeId nLastNodeId = 0; -CCriticalSection cs_nLastNodeId; - static CSemaphore *semOutbound = NULL; boost::condition_variable messageHandlerCondition; @@ -404,7 +401,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), hSocket, addrConnect, pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -1038,7 +1035,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), hSocket, addr, "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2030,6 +2027,7 @@ CConnman::CConnman() { setBannedIsDirty = false; fAddressesInitialized = false; + nLastNodeId = 0; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) @@ -2041,9 +2039,13 @@ bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& return ret; } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +NodeId CConnman::GetNewNodeId() { + return nLastNodeId.fetch_add(1, std::memory_order_relaxed); +} +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +{ uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2089,7 +2091,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2478,7 +2480,7 @@ void CNode::Fuzz(int nChance) unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } -CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), @@ -2531,16 +2533,12 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa minFeeFilter = 0; lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; + id = idIn; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; - { - LOCK(cs_nLastNodeId); - id = nLastNodeId++; - } - if (fLogIPs) LogPrint("net", "Added connection to %s peer=%d\n", addrName, id); else diff --git a/src/net.h b/src/net.h index 8d9925265..36043b0b8 100644 --- a/src/net.h +++ b/src/net.h @@ -196,6 +196,9 @@ private: bool IsWhitelistedRange(const CNetAddr &addr); void DeleteNode(CNode* pnode); + + NodeId GetNewNodeId(); + //!check is the banlist has unwritten changes bool BannedSetIsDirty(); //!set the "dirty" flag for the banlist @@ -223,6 +226,7 @@ private: CCriticalSection cs_vAddedNodes; std::vector vNodes; mutable CCriticalSection cs_vNodes; + std::atomic nLastNodeId; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); @@ -300,9 +304,6 @@ extern int nMaxConnections; extern limitedmap mapAlreadyAskedFor; -extern NodeId nLastNodeId; -extern CCriticalSection cs_nLastNodeId; - /** Subversion as sent to the P2P network in `version` messages */ extern std::string strSubVersion; @@ -501,7 +502,7 @@ public: CAmount lastSentFeeFilter; int64_t nextSendTimeFeeFilter; - CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); + CNode(NodeId id, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 412f94f40..652a8e2ce 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -40,13 +40,15 @@ CService ip(uint32_t i) return CService(CNetAddr(s), Params().GetDefaultPort()); } +static NodeId id = 0; + BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) BOOST_AUTO_TEST_CASE(DoS_banning) { connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, INVALID_SOCKET, addr1, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned @@ -55,7 +57,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); - CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + CNode dummyNode2(id++, INVALID_SOCKET, addr2, "", true); GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); @@ -72,7 +74,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) connman->ClearBanned(); mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, INVALID_SOCKET, addr1, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); @@ -94,7 +96,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode(INVALID_SOCKET, addr, "", true); + CNode dummyNode(id++, INVALID_SOCKET, addr, "", true); GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); dummyNode.nVersion = 1; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 267d1b55e..00fb75716 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -153,6 +153,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted) BOOST_AUTO_TEST_CASE(cnode_simple_test) { SOCKET hSocket = INVALID_SOCKET; + NodeId id = 0; in_addr ipv4Addr; ipv4Addr.s_addr = 0xa0b0c001; @@ -162,12 +163,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) bool fInboundIn = false; // Test that fFeeler is false by default. - CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn); + CNode* pnode1 = new CNode(id++, hSocket, addr, pszDest, fInboundIn); BOOST_CHECK(pnode1->fInbound == false); BOOST_CHECK(pnode1->fFeeler == false); fInboundIn = true; - CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn); + CNode* pnode2 = new CNode(id++, hSocket, addr, pszDest, fInboundIn); BOOST_CHECK(pnode2->fInbound == true); BOOST_CHECK(pnode2->fFeeler == false); } From 960cf2e4058a9c195bf64e1aecb46024f9ef022a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 17 Apr 2016 20:21:58 -0400 Subject: [PATCH 17/33] net: move nLocalHostNonce to CConnman This behavior seems to have been quite racy and broken. Move nLocalHostNonce into CNode, and check received nonces against all non-fully-connected nodes. If there's a match, assume we've connected to ourself. --- src/main.cpp | 2 +- src/net.cpp | 14 ++++++++++++-- src/net.h | 7 ++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index af598d487..43ccb6374 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5025,7 +5025,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Disconnect if we connected to ourself - if (nNonce == nLocalHostNonce && nNonce > 1) + if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce)) { LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); pfrom->fDisconnect = true; diff --git a/src/net.cpp b/src/net.cpp index 8bc8ecc43..71b4b0168 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -83,7 +83,6 @@ CCriticalSection cs_mapLocalHost; std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; -uint64_t nLocalHostNonce = 0; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; std::string strSubVersion; @@ -346,6 +345,16 @@ CNode* CConnman::FindNode(const CService& addr) return NULL; } +bool CConnman::CheckIncomingNonce(uint64_t nonce) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { + if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce) + return false; + } + return true; +} + CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { @@ -465,7 +474,6 @@ void CNode::PushVersion() int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr); - GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else @@ -2535,6 +2543,8 @@ CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::s nextSendTimeFeeFilter = 0; id = idIn; + GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); + BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; diff --git a/src/net.h b/src/net.h index 36043b0b8..32668045c 100644 --- a/src/net.h +++ b/src/net.h @@ -114,6 +114,7 @@ public: void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); + bool CheckIncomingNonce(uint64_t nonce); bool ForNode(NodeId id, std::function func); bool ForEachNode(std::function func); @@ -297,7 +298,6 @@ extern bool fListen; extern ServiceFlags nLocalServices; extern ServiceFlags nRelevantServices; extern bool fRelayTxes; -extern uint64_t nLocalHostNonce; /** Maximum number of connections to simultaneously allow (aka connection slots) */ extern int nMaxConnections; @@ -523,12 +523,17 @@ private: static uint64_t CalculateKeyedNetGroup(const CAddress& ad); + uint64_t nLocalHostNonce; public: NodeId GetId() const { return id; } + uint64_t GetLocalNonce() const { + return nLocalHostNonce; + } + int GetRefCount() { assert(nRefCount >= 0); From ee44fa95761724a83a76dd862a36bd9af0fc021f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 18 Apr 2016 21:33:54 -0400 Subject: [PATCH 18/33] net: move messageHandlerCondition to CConnman --- src/net.cpp | 11 +++++++---- src/net.h | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 71b4b0168..a62ee2291 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -89,7 +89,6 @@ std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static CSemaphore *semOutbound = NULL; -boost::condition_variable messageHandlerCondition; // Signals for message handling static CNodeSignals g_signals; @@ -688,8 +687,9 @@ void CNode::copyStats(CNodeStats &stats) #undef X // requires LOCK(cs_vRecvMsg) -bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) +bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete) { + complete = false; while (nBytes > 0) { // get current incomplete message, or create a new one @@ -728,7 +728,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE; msg.nTime = GetTimeMicros(); - messageHandlerCondition.notify_one(); + complete = true; } } @@ -1247,8 +1247,11 @@ void CConnman::ThreadSocketHandler() int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); if (nBytes > 0) { - if (!pnode->ReceiveMsgBytes(pchBuf, nBytes)) + bool notify = false; + if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) pnode->CloseSocketDisconnect(); + if(notify) + messageHandlerCondition.notify_one(); pnode->nLastRecv = GetTime(); pnode->nRecvBytes += nBytes; pnode->RecordBytesRecv(nBytes); diff --git a/src/net.h b/src/net.h index 32668045c..0e83ff4a0 100644 --- a/src/net.h +++ b/src/net.h @@ -228,6 +228,7 @@ private: std::vector vNodes; mutable CCriticalSection cs_vNodes; std::atomic nLastNodeId; + boost::condition_variable messageHandlerCondition; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); @@ -550,7 +551,7 @@ public: } // requires LOCK(cs_vRecvMsg) - bool ReceiveMsgBytes(const char *pch, unsigned int nBytes); + bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete); // requires LOCK(cs_vRecvMsg) void SetRecvVersion(int nVersionIn) From adf5d4c2e4e7a2979a6ca6de806151fe04c23162 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 21 May 2016 12:04:02 +0200 Subject: [PATCH 19/33] net: SocketSendData returns written size --- src/net.cpp | 5 ++++- src/net.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index a62ee2291..aded8d05d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -791,9 +791,10 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes) // requires LOCK(cs_vSend) -void SocketSendData(CNode *pnode) +size_t SocketSendData(CNode *pnode) { std::deque::iterator it = pnode->vSendMsg.begin(); + size_t nSentSize = 0; while (it != pnode->vSendMsg.end()) { const CSerializeData &data = *it; @@ -804,6 +805,7 @@ void SocketSendData(CNode *pnode) pnode->nSendBytes += nBytes; pnode->nSendOffset += nBytes; pnode->RecordBytesSent(nBytes); + nSentSize += nBytes; if (pnode->nSendOffset == data.size()) { pnode->nSendOffset = 0; pnode->nSendSize -= data.size(); @@ -832,6 +834,7 @@ void SocketSendData(CNode *pnode) assert(pnode->nSendSize == 0); } pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it); + return nSentSize; } static std::list vNodesDisconnected; diff --git a/src/net.h b/src/net.h index 0e83ff4a0..503e009c4 100644 --- a/src/net.h +++ b/src/net.h @@ -236,7 +236,7 @@ unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError); bool StopNode(CConnman& connman); -void SocketSendData(CNode *pnode); +size_t SocketSendData(CNode *pnode); struct CombinerAll { From 63cafa6329e1a0a1daf2d324931aca42ba1cbb19 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 18 Apr 2016 21:44:42 -0400 Subject: [PATCH 20/33] net: move send/recv statistics to CConnman --- src/init.cpp | 2 +- src/main.cpp | 10 +++--- src/net.cpp | 63 +++++++++++++++++--------------- src/net.h | 82 +++++++++++++++++++++--------------------- src/qt/clientmodel.cpp | 8 +++-- src/rpc/net.cpp | 18 +++++----- 6 files changed, 99 insertions(+), 84 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f618e5ccc..a7f893c24 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1240,7 +1240,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif if (mapArgs.count("-maxuploadtarget")) { - CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); + connman.SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); } // ********************************************************* Step 7: load block chain diff --git a/src/main.cpp b/src/main.cpp index 43ccb6374..019db0bdb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4766,7 +4766,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman) { std::deque::iterator it = pfrom->vRecvGetData.begin(); @@ -4808,7 +4808,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // disconnect node in case we have reached the outbound limit for serving historical blocks // never disconnect whitelisted nodes static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical - if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) + if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) { LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); @@ -5312,7 +5312,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); - ProcessGetData(pfrom, chainparams.GetConsensus()); + ProcessGetData(pfrom, chainparams.GetConsensus(), connman); } @@ -5986,7 +5986,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } - if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted) + if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted) { LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); pfrom->fDisconnect = true; @@ -6202,7 +6202,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman) bool fOk = true; if (!pfrom->vRecvGetData.empty()) - ProcessGetData(pfrom, chainparams.GetConsensus()); + ProcessGetData(pfrom, chainparams.GetConsensus(), connman); // this maintains the order of responses if (!pfrom->vRecvGetData.empty()) return fOk; diff --git a/src/net.cpp b/src/net.cpp index aded8d05d..0787b16ad 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -298,15 +298,6 @@ bool IsReachable(const CNetAddr& addr) return IsReachable(net); } -uint64_t CNode::nTotalBytesRecv = 0; -uint64_t CNode::nTotalBytesSent = 0; -CCriticalSection CNode::cs_totalBytesRecv; -CCriticalSection CNode::cs_totalBytesSent; - -uint64_t CNode::nMaxOutboundLimit = 0; -uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0; -uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day -uint64_t CNode::nMaxOutboundCycleStartTime = 0; CNode* CConnman::FindNode(const CNetAddr& ip) { @@ -804,7 +795,6 @@ size_t SocketSendData(CNode *pnode) pnode->nLastSend = GetTime(); pnode->nSendBytes += nBytes; pnode->nSendOffset += nBytes; - pnode->RecordBytesSent(nBytes); nSentSize += nBytes; if (pnode->nSendOffset == data.size()) { pnode->nSendOffset = 0; @@ -1176,9 +1166,15 @@ void CConnman::ThreadSocketHandler() // * We process a message in the buffer (message handler thread). { TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend && !pnode->vSendMsg.empty()) { - FD_SET(pnode->hSocket, &fdsetSend); - continue; + if (lockSend) { + if (pnode->nOptimisticBytesWritten) { + RecordBytesSent(pnode->nOptimisticBytesWritten); + pnode->nOptimisticBytesWritten = 0; + } + if (!pnode->vSendMsg.empty()) { + FD_SET(pnode->hSocket, &fdsetSend); + continue; + } } } { @@ -1257,7 +1253,7 @@ void CConnman::ThreadSocketHandler() messageHandlerCondition.notify_one(); pnode->nLastRecv = GetTime(); pnode->nRecvBytes += nBytes; - pnode->RecordBytesRecv(nBytes); + RecordBytesRecv(nBytes); } else if (nBytes == 0) { @@ -1289,8 +1285,11 @@ void CConnman::ThreadSocketHandler() if (FD_ISSET(pnode->hSocket, &fdsetSend)) { TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) - SocketSendData(pnode); + if (lockSend) { + size_t nBytes = SocketSendData(pnode); + if (nBytes) + RecordBytesSent(nBytes); + } } // @@ -2060,6 +2059,13 @@ NodeId CConnman::GetNewNodeId() bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) { + nTotalBytesRecv = 0; + nTotalBytesSent = 0; + nMaxOutboundLimit = 0; + nMaxOutboundTotalBytesSentInCycle = 0; + nMaxOutboundTimeframe = 60*60*24; //1 day + nMaxOutboundCycleStartTime = 0; + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2344,13 +2350,13 @@ void CConnman::RelayTransaction(const CTransaction& tx) } } -void CNode::RecordBytesRecv(uint64_t bytes) +void CConnman::RecordBytesRecv(uint64_t bytes) { LOCK(cs_totalBytesRecv); nTotalBytesRecv += bytes; } -void CNode::RecordBytesSent(uint64_t bytes) +void CConnman::RecordBytesSent(uint64_t bytes) { LOCK(cs_totalBytesSent); nTotalBytesSent += bytes; @@ -2367,7 +2373,7 @@ void CNode::RecordBytesSent(uint64_t bytes) nMaxOutboundTotalBytesSentInCycle += bytes; } -void CNode::SetMaxOutboundTarget(uint64_t limit) +void CConnman::SetMaxOutboundTarget(uint64_t limit) { LOCK(cs_totalBytesSent); uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SERIALIZED_SIZE; @@ -2377,19 +2383,19 @@ void CNode::SetMaxOutboundTarget(uint64_t limit) LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum); } -uint64_t CNode::GetMaxOutboundTarget() +uint64_t CConnman::GetMaxOutboundTarget() { LOCK(cs_totalBytesSent); return nMaxOutboundLimit; } -uint64_t CNode::GetMaxOutboundTimeframe() +uint64_t CConnman::GetMaxOutboundTimeframe() { LOCK(cs_totalBytesSent); return nMaxOutboundTimeframe; } -uint64_t CNode::GetMaxOutboundTimeLeftInCycle() +uint64_t CConnman::GetMaxOutboundTimeLeftInCycle() { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2403,7 +2409,7 @@ uint64_t CNode::GetMaxOutboundTimeLeftInCycle() return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime(); } -void CNode::SetMaxOutboundTimeframe(uint64_t timeframe) +void CConnman::SetMaxOutboundTimeframe(uint64_t timeframe) { LOCK(cs_totalBytesSent); if (nMaxOutboundTimeframe != timeframe) @@ -2415,7 +2421,7 @@ void CNode::SetMaxOutboundTimeframe(uint64_t timeframe) nMaxOutboundTimeframe = timeframe; } -bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) +bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2435,7 +2441,7 @@ bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) return false; } -uint64_t CNode::GetOutboundTargetBytesLeft() +uint64_t CConnman::GetOutboundTargetBytesLeft() { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2444,13 +2450,13 @@ uint64_t CNode::GetOutboundTargetBytesLeft() return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle; } -uint64_t CNode::GetTotalBytesRecv() +uint64_t CConnman::GetTotalBytesRecv() { LOCK(cs_totalBytesRecv); return nTotalBytesRecv; } -uint64_t CNode::GetTotalBytesSent() +uint64_t CConnman::GetTotalBytesSent() { LOCK(cs_totalBytesSent); return nTotalBytesSent; @@ -2548,6 +2554,7 @@ CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::s lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; id = idIn; + nOptimisticBytesWritten = 0; GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); @@ -2665,7 +2672,7 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) // If write queue empty, attempt "optimistic write" if (it == vSendMsg.begin()) - SocketSendData(this); + nOptimisticBytesWritten += SocketSendData(this); LEAVE_CRITICAL_SECTION(cs_vSend); } diff --git a/src/net.h b/src/net.h index 503e009c4..e2d98a90d 100644 --- a/src/net.h +++ b/src/net.h @@ -171,6 +171,31 @@ public: bool DisconnectSubnet(const CSubNet& subnet); void AddWhitelistedRange(const CSubNet &subnet); + + //!set the max outbound target in bytes + void SetMaxOutboundTarget(uint64_t limit); + uint64_t GetMaxOutboundTarget(); + + //!set the timeframe for the max outbound target + void SetMaxOutboundTimeframe(uint64_t timeframe); + uint64_t GetMaxOutboundTimeframe(); + + //!check if the outbound target is reached + // if param historicalBlockServingLimit is set true, the function will + // response true if the limit for serving historical blocks has been reached + bool OutboundTargetReached(bool historicalBlockServingLimit); + + //!response the bytes left in the current max outbound cycle + // in case of no limit, it will always response 0 + uint64_t GetOutboundTargetBytesLeft(); + + //!response the time in second left in the current max outbound cycle + // in case of no limit, it will always response 0 + uint64_t GetMaxOutboundTimeLeftInCycle(); + + uint64_t GetTotalBytesRecv(); + uint64_t GetTotalBytesSent(); + private: struct ListenSocket { SOCKET socket; @@ -210,6 +235,22 @@ private: void DumpData(); void DumpBanlist(); + // Network stats + void RecordBytesRecv(uint64_t bytes); + void RecordBytesSent(uint64_t bytes); + + // Network usage totals + CCriticalSection cs_totalBytesRecv; + CCriticalSection cs_totalBytesSent; + uint64_t nTotalBytesRecv; + uint64_t nTotalBytesSent; + + // outbound limit & stats + uint64_t nMaxOutboundTotalBytesSentInCycle; + uint64_t nMaxOutboundCycleStartTime; + uint64_t nMaxOutboundLimit; + uint64_t nMaxOutboundTimeframe; + // Whitelisted ranges. Any node connecting from these is automatically // whitelisted (as well as those connecting to whitelisted binds). std::vector vWhitelistedRange; @@ -396,6 +437,7 @@ public: CDataStream ssSend; size_t nSendSize; // total size of all vSendMsg entries size_t nSendOffset; // offset inside the first vSendMsg already sent + uint64_t nOptimisticBytesWritten; uint64_t nSendBytes; std::deque vSendMsg; CCriticalSection cs_vSend; @@ -507,18 +549,6 @@ public: ~CNode(); private: - // Network usage totals - static CCriticalSection cs_totalBytesRecv; - static CCriticalSection cs_totalBytesSent; - static uint64_t nTotalBytesRecv; - static uint64_t nTotalBytesSent; - - // outbound limit & stats - static uint64_t nMaxOutboundTotalBytesSentInCycle; - static uint64_t nMaxOutboundCycleStartTime; - static uint64_t nMaxOutboundLimit; - static uint64_t nMaxOutboundTimeframe; - CNode(const CNode&); void operator=(const CNode&); @@ -812,34 +842,6 @@ public: void CloseSocketDisconnect(); void copyStats(CNodeStats &stats); - - // Network stats - static void RecordBytesRecv(uint64_t bytes); - static void RecordBytesSent(uint64_t bytes); - - static uint64_t GetTotalBytesRecv(); - static uint64_t GetTotalBytesSent(); - - //!set the max outbound target in bytes - static void SetMaxOutboundTarget(uint64_t limit); - static uint64_t GetMaxOutboundTarget(); - - //!set the timeframe for the max outbound target - static void SetMaxOutboundTimeframe(uint64_t timeframe); - static uint64_t GetMaxOutboundTimeframe(); - - //!check if the outbound target is reached - // if param historicalBlockServingLimit is set true, the function will - // response true if the limit for serving historical blocks has been reached - static bool OutboundTargetReached(bool historicalBlockServingLimit); - - //!response the bytes left in the current max outbound cycle - // in case of no limit, it will always response 0 - static uint64_t GetOutboundTargetBytesLeft(); - - //!response the time in second left in the current max outbound cycle - // in case of no limit, it will always response 0 - static uint64_t GetMaxOutboundTimeLeftInCycle(); }; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index f72bbfe6b..83c78850e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -72,12 +72,16 @@ int ClientModel::getNumBlocks() const quint64 ClientModel::getTotalBytesRecv() const { - return CNode::GetTotalBytesRecv(); + if(!g_connman) + return 0; + return g_connman->GetTotalBytesRecv(); } quint64 ClientModel::getTotalBytesSent() const { - return CNode::GetTotalBytesSent(); + if(!g_connman) + return 0; + return g_connman->GetTotalBytesSent(); } QDateTime ClientModel::getLastBlockDate() const diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 509b57aa7..4fe582399 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -347,19 +347,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp) + HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); - obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); + obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv())); + obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); UniValue outboundLimit(UniValue::VOBJ); - outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe())); - outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget())); - outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false))); - outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true))); - outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft())); - outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle())); + outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe())); + outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget())); + outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false))); + outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true))); + outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft())); + outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle())); obj.push_back(Pair("uploadtarget", outboundLimit)); return obj; } From be9c796dc51c05cab0b84d2e66c928973c6e5ed6 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 19 Apr 2016 00:01:19 -0400 Subject: [PATCH 21/33] net: move SendBufferSize/ReceiveFloodSize to CConnman --- src/main.cpp | 10 +++++++--- src/net.cpp | 13 +++++++++---- src/net.h | 10 +++++++--- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 019db0bdb..db9d0d3f1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4769,6 +4769,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman) { std::deque::iterator it = pfrom->vRecvGetData.begin(); + unsigned int nMaxSendBufferSize = connman.GetSendBufferSize(); vector vNotFound; @@ -4776,7 +4777,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam while (it != pfrom->vRecvGetData.end()) { // Don't bother if send buffer is too full to respond anyway - if (pfrom->nSendSize >= SendBufferSize()) + if (pfrom->nSendSize >= nMaxSendBufferSize) break; const CInv &inv = *it; @@ -4934,6 +4935,8 @@ uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman) { + unsigned int nMaxSendBufferSize = connman.GetSendBufferSize(); + LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) { @@ -5283,7 +5286,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Track requests for our stuff GetMainSignals().Inventory(inv.hash); - if (pfrom->nSendSize > (SendBufferSize() * 2)) { + if (pfrom->nSendSize > (nMaxSendBufferSize * 2)) { Misbehaving(pfrom->GetId(), 50); return error("send buffer size() = %u", pfrom->nSendSize); } @@ -6188,6 +6191,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bool ProcessMessages(CNode* pfrom, CConnman& connman) { const CChainParams& chainparams = Params(); + unsigned int nMaxSendBufferSize = connman.GetSendBufferSize(); //if (fDebug) // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); @@ -6210,7 +6214,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman) std::deque::iterator it = pfrom->vRecvMsg.begin(); while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) { // Don't bother if send buffer is too full to respond anyway - if (pfrom->nSendSize >= SendBufferSize()) + if (pfrom->nSendSize >= nMaxSendBufferSize) break; // get next message diff --git a/src/net.cpp b/src/net.cpp index 0787b16ad..2839474cb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1181,7 +1181,7 @@ void CConnman::ThreadSocketHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv && ( pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() || - pnode->GetTotalRecvSize() <= ReceiveFloodSize())) + pnode->GetTotalRecvSize() <= GetReceiveFloodSize())) FD_SET(pnode->hSocket, &fdsetRecv); } } @@ -1851,7 +1851,7 @@ void CConnman::ThreadMessageHandler() if (!GetNodeSignals().ProcessMessages(pnode, *this)) pnode->CloseSocketDisconnect(); - if (pnode->nSendSize < SendBufferSize()) + if (pnode->nSendSize < GetSendBufferSize()) { if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete())) { @@ -2041,6 +2041,8 @@ CConnman::CConnman() setBannedIsDirty = false; fAddressesInitialized = false; nLastNodeId = 0; + nSendBufferMaxSize = 0; + nReceiveFloodSize = 0; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) @@ -2066,6 +2068,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nMaxOutboundTimeframe = 60*60*24; //1 day nMaxOutboundCycleStartTime = 0; + nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); + nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2497,8 +2502,8 @@ void CNode::Fuzz(int nChance) Fuzz(2); } -unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } -unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } +unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } +unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), diff --git a/src/net.h b/src/net.h index e2d98a90d..e5fbf6549 100644 --- a/src/net.h +++ b/src/net.h @@ -82,9 +82,6 @@ static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK; // NOTE: When adjusting this, update rpcnet:setban's help ("24h") static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban -unsigned int ReceiveFloodSize(); -unsigned int SendBufferSize(); - typedef int NodeId; struct AddedNodeInfo @@ -170,6 +167,8 @@ public: bool DisconnectNode(NodeId id); bool DisconnectSubnet(const CSubNet& subnet); + unsigned int GetSendBufferSize() const; + void AddWhitelistedRange(const CSubNet &subnet); //!set the max outbound target in bytes @@ -235,6 +234,8 @@ private: void DumpData(); void DumpBanlist(); + unsigned int GetReceiveFloodSize() const; + // Network stats void RecordBytesRecv(uint64_t bytes); void RecordBytesSent(uint64_t bytes); @@ -256,6 +257,9 @@ private: std::vector vWhitelistedRange; CCriticalSection cs_vWhitelistedRange; + unsigned int nSendBufferMaxSize; + unsigned int nReceiveFloodSize; + std::vector vhListenSocket; banmap_t setBanned; CCriticalSection cs_setBanned; From bd72937dc462b86f0e84184b270a232f7bfaa8db Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 19 Apr 2016 00:04:58 -0400 Subject: [PATCH 22/33] net: move nLocalServices/nRelevantServices to CConnman These are in-turn passed to CNode at connection time. This allows us to offer different services to different peers (or test the effects of doing so). --- src/init.cpp | 5 ++++- src/main.cpp | 12 ++++++------ src/net.cpp | 32 ++++++++++++++++++-------------- src/net.h | 24 ++++++++++++++++++------ src/rpc/net.cpp | 3 ++- src/test/DoS_tests.cpp | 8 ++++---- src/test/net_tests.cpp | 4 ++-- 7 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index a7f893c24..644d6721e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -982,6 +982,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Option to startup with mocktime set (used for regression testing): SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op + ServiceFlags nLocalServices = NODE_NETWORK; + ServiceFlags nRelevantServices = NODE_NETWORK; + if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); @@ -1506,7 +1509,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartTorControl(threadGroup, scheduler); std::string strNodeError; - if(!StartNode(connman, threadGroup, scheduler, strNodeError)) + if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, strNodeError)) return InitError(strNodeError); // ********************************************************* Step 12: finished diff --git a/src/main.cpp b/src/main.cpp index db9d0d3f1..a916cbc12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -471,7 +471,7 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { } void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom, CConnman& connman) { - if (nLocalServices & NODE_WITNESS) { + if (pfrom->GetLocalServices() & NODE_WITNESS) { // Don't ever request compact blocks when segwit is enabled. return; } @@ -4945,7 +4945,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - if (!(nLocalServices & NODE_BLOOM) && + if (!(pfrom->GetLocalServices() & NODE_BLOOM) && (strCommand == NetMsgType::FILTERLOAD || strCommand == NetMsgType::FILTERADD || strCommand == NetMsgType::FILTERCLEAR)) @@ -5068,7 +5068,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Advertise our address if (fListen && !IsInitialBlockDownload()) { - CAddress addr = GetLocalAddress(&pfrom->addr); + CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices()); if (addr.IsRoutable()) { LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); @@ -5263,7 +5263,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER && (!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { inv.type |= nFetchFlags; - if (nodestate->fProvidesHeaderAndIDs && !(nLocalServices & NODE_WITNESS)) + if (nodestate->fProvidesHeaderAndIDs && !(pfrom->GetLocalServices() & NODE_WITNESS)) vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash)); else vToFetch.push_back(inv); @@ -5907,7 +5907,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); } if (vGetData.size() > 0) { - if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(nLocalServices & NODE_WITNESS)) { + if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(pfrom->GetLocalServices() & NODE_WITNESS)) { // We seem to be rather well-synced, so it appears pfrom was the first to provide us // with this block! Let's get them to announce using compact blocks in the future. MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman); @@ -5982,7 +5982,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::MEMPOOL) { - if (!(nLocalServices & NODE_BLOOM) && !pfrom->fWhitelisted) + if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted) { LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId()); pfrom->fDisconnect = true; diff --git a/src/net.cpp b/src/net.cpp index 2839474cb..66e3d91f4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -69,15 +69,11 @@ namespace { const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; -/** Services this node implementation cares about */ -ServiceFlags nRelevantServices = NODE_NETWORK; - // // Global state variables // bool fDiscover = true; bool fListen = true; -ServiceFlags nLocalServices = NODE_NETWORK; bool fRelayTxes = true; CCriticalSection cs_mapLocalHost; std::map mapLocalHost; @@ -155,7 +151,7 @@ static std::vector convertSeed6(const std::vector &vSeedsIn // Otherwise, return the unroutable 0.0.0.0 but filled in with // the normal parameters, since the IP may be changed to a useful // one by discovery. -CAddress GetLocalAddress(const CNetAddr *paddrPeer) +CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) { CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE); CService addr; @@ -187,7 +183,7 @@ void AdvertiseLocal(CNode *pnode) { if (fListen && pnode->fSuccessfullyConnected) { - CAddress addrLocal = GetLocalAddress(&pnode->addr); + CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices()); // If discovery is enabled, sometimes give our peer the address it // tells us that it sees us as in case it has a better idea of our // address than we do. @@ -400,7 +396,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addrConnect, pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -463,7 +459,7 @@ void CNode::PushVersion() int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); - CAddress addrMe = GetLocalAddress(&addr); + CAddress addrMe = GetLocalAddress(&addr, nLocalServices); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else @@ -1036,7 +1032,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addr, "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2045,11 +2041,11 @@ CConnman::CConnman() nReceiveFloodSize = 0; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, strNodeError); return ret; } @@ -2059,13 +2055,15 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; nMaxOutboundLimit = 0; nMaxOutboundTotalBytesSentInCycle = 0; nMaxOutboundTimeframe = 60*60*24; //1 day + nLocalServices = nLocalServicesIn; + nRelevantServices = nRelevantServicesIn; nMaxOutboundCycleStartTime = 0; nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); @@ -2116,7 +2114,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2467,6 +2465,11 @@ uint64_t CConnman::GetTotalBytesSent() return nTotalBytesSent; } +ServiceFlags CConnman::GetLocalServices() const +{ + return nLocalServices; +} + void CNode::Fuzz(int nChance) { if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake @@ -2505,7 +2508,7 @@ void CNode::Fuzz(int nChance) unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } -CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), @@ -2560,6 +2563,7 @@ CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::s nextSendTimeFeeFilter = 0; id = idIn; nOptimisticBytesWritten = 0; + nLocalServices = nLocalServicesIn; GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); diff --git a/src/net.h b/src/net.h index e5fbf6549..25e473c5f 100644 --- a/src/net.h +++ b/src/net.h @@ -107,7 +107,7 @@ public: CConnman(); ~CConnman(); - bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError); + bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, std::string& strNodeError); void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); @@ -171,6 +171,8 @@ public: void AddWhitelistedRange(const CSubNet &subnet); + ServiceFlags GetLocalServices() const; + //!set the max outbound target in bytes void SetMaxOutboundTarget(uint64_t limit); uint64_t GetMaxOutboundTarget(); @@ -274,12 +276,18 @@ private: mutable CCriticalSection cs_vNodes; std::atomic nLastNodeId; boost::condition_variable messageHandlerCondition; + + /** Services this instance offers */ + ServiceFlags nLocalServices; + + /** Services this instance cares about */ + ServiceFlags nRelevantServices; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError); +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError); bool StopNode(CConnman& connman); size_t SocketSendData(CNode *pnode); @@ -336,13 +344,11 @@ bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); bool IsReachable(enum Network net); bool IsReachable(const CNetAddr &addr); -CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); +CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices); extern bool fDiscover; extern bool fListen; -extern ServiceFlags nLocalServices; -extern ServiceFlags nRelevantServices; extern bool fRelayTxes; /** Maximum number of connections to simultaneously allow (aka connection slots) */ @@ -549,7 +555,7 @@ public: CAmount lastSentFeeFilter; int64_t nextSendTimeFeeFilter; - CNode(NodeId id, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); + CNode(NodeId id, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: @@ -559,6 +565,7 @@ private: static uint64_t CalculateKeyedNetGroup(const CAddress& ad); uint64_t nLocalHostNonce; + ServiceFlags nLocalServices; public: NodeId GetId() const { @@ -846,6 +853,11 @@ public: void CloseSocketDisconnect(); void copyStats(CNodeStats &stats); + + ServiceFlags GetLocalServices() const + { + return nLocalServices; + } }; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 4fe582399..61b6b62c9 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -432,7 +432,8 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("subversion", strSubVersion)); obj.push_back(Pair("protocolversion",PROTOCOL_VERSION)); - obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); + if(g_connman) + obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices()))); obj.push_back(Pair("localrelay", fRelayTxes)); obj.push_back(Pair("timeoffset", GetTimeOffset())); if(g_connman) diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 652a8e2ce..2265f43a6 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) { connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, INVALID_SOCKET, addr1, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); - CNode dummyNode2(id++, INVALID_SOCKET, addr2, "", true); + CNode dummyNode2(id++, NODE_NETWORK, INVALID_SOCKET, addr2, "", true); GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) connman->ClearBanned(); mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, INVALID_SOCKET, addr1, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode(id++, INVALID_SOCKET, addr, "", true); + CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, "", true); GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); dummyNode.nVersion = 1; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 00fb75716..1019b12c1 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -163,12 +163,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) bool fInboundIn = false; // Test that fFeeler is false by default. - CNode* pnode1 = new CNode(id++, hSocket, addr, pszDest, fInboundIn); + CNode* pnode1 = new CNode(id++, NODE_NETWORK, hSocket, addr, pszDest, fInboundIn); BOOST_CHECK(pnode1->fInbound == false); BOOST_CHECK(pnode1->fFeeler == false); fInboundIn = true; - CNode* pnode2 = new CNode(id++, hSocket, addr, pszDest, fInboundIn); + CNode* pnode2 = new CNode(id++, NODE_NETWORK, hSocket, addr, pszDest, fInboundIn); BOOST_CHECK(pnode2->fInbound == true); BOOST_CHECK(pnode2->fFeeler == false); } From 8a593694b1495656411717fbae5d3167576df973 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 19 Apr 2016 00:15:52 -0400 Subject: [PATCH 23/33] net: move semOutbound to CConnman --- src/net.cpp | 3 +-- src/net.h | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 66e3d91f4..853c0cdd6 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -84,8 +84,6 @@ std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -static CSemaphore *semOutbound = NULL; - // Signals for message handling static CNodeSignals g_signals; CNodeSignals& GetNodeSignals() { return g_signals; } @@ -2039,6 +2037,7 @@ CConnman::CConnman() nLastNodeId = 0; nSendBufferMaxSize = 0; nReceiveFloodSize = 0; + semOutbound = NULL; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError) diff --git a/src/net.h b/src/net.h index 25e473c5f..36ebadf13 100644 --- a/src/net.h +++ b/src/net.h @@ -282,6 +282,8 @@ private: /** Services this instance cares about */ ServiceFlags nRelevantServices; + + CSemaphore *semOutbound; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); From fdf69ff21aef8ed8071a757979f4239537f7afba Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 22 May 2016 09:52:03 +0200 Subject: [PATCH 24/33] net: move max/max-outbound to CConnman --- src/init.cpp | 5 +++-- src/net.cpp | 24 +++++++++++++----------- src/net.h | 11 ++++++----- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 644d6721e..599dac39b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -861,7 +861,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Make sure enough file descriptors are available int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); - nMaxConnections = std::max(nUserMaxConnections, 0); + int nMaxConnections = std::max(nUserMaxConnections, 0); // Trim requested connection counts, to fit into system limitations nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); @@ -1509,7 +1509,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartTorControl(threadGroup, scheduler); std::string strNodeError; - if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, strNodeError)) + int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); + if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, strNodeError)) return InitError(strNodeError); // ********************************************************* Step 12: finished diff --git a/src/net.cpp b/src/net.cpp index 853c0cdd6..fe4daaaeb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -63,7 +63,6 @@ namespace { - const int MAX_OUTBOUND_CONNECTIONS = 8; const int MAX_FEELER_CONNECTIONS = 1; } @@ -79,7 +78,6 @@ CCriticalSection cs_mapLocalHost; std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; -int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); @@ -974,7 +972,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; - int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); + int nMaxInbound = nMaxConnections - (nMaxOutbound + MAX_FEELER_CONNECTIONS); assert(nMaxInbound > 0); if (hSocket != INVALID_SOCKET) @@ -1626,7 +1624,7 @@ void CConnman::ThreadOpenConnections() } } } - assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS)); + assert(nOutbound <= (nMaxOutbound + MAX_FEELER_CONNECTIONS)); // Feeler Connections // @@ -1641,7 +1639,7 @@ void CConnman::ThreadOpenConnections() // * Only make a feeler connection once every few minutes. // bool fFeeler = false; - if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) { + if (nOutbound >= nMaxOutbound) { int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds). if (nTime > nNextFeeler) { nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL); @@ -2038,13 +2036,15 @@ CConnman::CConnman() nSendBufferMaxSize = 0; nReceiveFloodSize = 0; semOutbound = NULL; + nMaxConnections = 0; + nMaxOutbound = 0; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, strNodeError); return ret; } @@ -2054,7 +2054,7 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; @@ -2065,6 +2065,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se nRelevantServices = nRelevantServicesIn; nMaxOutboundCycleStartTime = 0; + nMaxConnections = nMaxConnectionsIn; + nMaxOutbound = std::min((nMaxOutboundIn), nMaxConnections); + nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); @@ -2106,8 +2109,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); - semOutbound = new CSemaphore(nMaxOutbound); + semOutbound = new CSemaphore(std::min((nMaxOutbound + MAX_FEELER_CONNECTIONS), nMaxConnections)); } if (pnodeLocalHost == NULL) { @@ -2174,7 +2176,7 @@ instance_of_cnetcleanup; void CConnman::Stop() { if (semOutbound) - for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) + for (int i=0; i<(nMaxOutbound + MAX_FEELER_CONNECTIONS); i++) semOutbound->post(); if (fAddressesInitialized) diff --git a/src/net.h b/src/net.h index 36ebadf13..0859190d3 100644 --- a/src/net.h +++ b/src/net.h @@ -54,6 +54,8 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000; static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000; /** Maximum length of strSubVer in `version` message */ static const unsigned int MAX_SUBVERSION_LENGTH = 256; +/** Maximum number of outgoing nodes */ +static const int MAX_OUTBOUND_CONNECTIONS = 8; /** -listen default */ static const bool DEFAULT_LISTEN = true; /** -upnp default */ @@ -107,7 +109,7 @@ public: CConnman(); ~CConnman(); - bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, std::string& strNodeError); + bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError); void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); @@ -284,12 +286,14 @@ private: ServiceFlags nRelevantServices; CSemaphore *semOutbound; + int nMaxConnections; + int nMaxOutbound; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError); +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnections, int nMaxOutbound, std::string& strNodeError); bool StopNode(CConnman& connman); size_t SocketSendData(CNode *pnode); @@ -353,9 +357,6 @@ extern bool fDiscover; extern bool fListen; extern bool fRelayTxes; -/** Maximum number of connections to simultaneously allow (aka connection slots) */ -extern int nMaxConnections; - extern limitedmap mapAlreadyAskedFor; /** Subversion as sent to the P2P network in `version` messages */ From f60b9059e4958245bda82e9656c52a31d5268ad9 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 24 May 2016 16:42:17 -0400 Subject: [PATCH 25/33] net: Pass best block known height into CConnman CConnman then passes the current best height into CNode at creation time. This way CConnman/CNode have no dependency on main for height, and the signals only move in one direction. This also helps to prevent identity leakage a tiny bit. Before this change, an attacker could theoretically make 2 connections on different interfaces. They would connect fully on one, and only establish the initial connection on the other. Once they receive a new block, they would relay it to your first connection, and immediately commence the version handshake on the second. Since the new block height is reflected immediately, they could attempt to learn whether the two connections were correlated. This is, of course, incredibly unlikely to work due to the small timings involved and receipt from other senders. But it doesn't hurt to lock-in nBestHeight at the time of connection, rather than letting the remote choose the time. --- src/init.cpp | 2 +- src/main.cpp | 10 ++-------- src/net.cpp | 36 ++++++++++++++++++++++++------------ src/net.h | 13 +++++++++---- src/test/DoS_tests.cpp | 8 ++++---- src/test/net_tests.cpp | 5 +++-- 6 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 599dac39b..4dce8be81 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1510,7 +1510,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::string strNodeError; int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); - if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, strNodeError)) + if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, chainActive.Height(), strNodeError)) return InitError(strNodeError); // ********************************************************* Step 12: finished diff --git a/src/main.cpp b/src/main.cpp index a916cbc12..1835d9712 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -325,12 +325,6 @@ CNodeState *State(NodeId pnode) { return &it->second; } -int GetHeight() -{ - LOCK(cs_main); - return chainActive.Height(); -} - void UpdatePreferredDownload(CNode* node, CNodeState* state) { nPreferredDownload -= state->fPreferredDownload; @@ -639,7 +633,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { void RegisterNodeSignals(CNodeSignals& nodeSignals) { - nodeSignals.GetHeight.connect(&GetHeight); nodeSignals.ProcessMessages.connect(&ProcessMessages); nodeSignals.SendMessages.connect(&SendMessages); nodeSignals.InitializeNode.connect(&InitializeNode); @@ -648,7 +641,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals) void UnregisterNodeSignals(CNodeSignals& nodeSignals) { - nodeSignals.GetHeight.disconnect(&GetHeight); nodeSignals.ProcessMessages.disconnect(&ProcessMessages); nodeSignals.SendMessages.disconnect(&SendMessages); nodeSignals.InitializeNode.disconnect(&InitializeNode); @@ -3058,6 +3050,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, // When we reach this point, we switched to a new tip (stored in pindexNewTip). // Notifications/callbacks that can run without cs_main + if(connman) + connman->SetBestHeight(nNewHeight); // throw all transactions though the signal-interface // while _not_ holding the cs_main lock diff --git a/src/net.cpp b/src/net.cpp index fe4daaaeb..d51095255 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -392,7 +392,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -451,17 +451,15 @@ void CNode::CloseSocketDisconnect() void CNode::PushVersion() { - int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0); - int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr, nLocalServices); if (fLogIPs) - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id); else - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), id); PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes); + nLocalHostNonce, strSubVersion, nMyStartingHeight, ::fRelayTxes); } @@ -1028,7 +1026,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2038,13 +2036,14 @@ CConnman::CConnman() semOutbound = NULL; nMaxConnections = 0; nMaxOutbound = 0; + nBestHeight = 0; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, strNodeError); return ret; } @@ -2054,7 +2053,7 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; @@ -2071,6 +2070,8 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + SetBestHeight(nBestHeightIn); + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2115,7 +2116,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2471,6 +2472,16 @@ ServiceFlags CConnman::GetLocalServices() const return nLocalServices; } +void CConnman::SetBestHeight(int height) +{ + nBestHeight.store(height, std::memory_order_release); +} + +int CConnman::GetBestHeight() const +{ + return nBestHeight.load(std::memory_order_acquire); +} + void CNode::Fuzz(int nChance) { if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake @@ -2509,7 +2520,7 @@ void CNode::Fuzz(int nChance) unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), @@ -2567,6 +2578,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const nLocalServices = nLocalServicesIn; GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); + nMyStartingHeight = nMyStartingHeightIn; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; diff --git a/src/net.h b/src/net.h index 0859190d3..852822d85 100644 --- a/src/net.h +++ b/src/net.h @@ -109,7 +109,7 @@ public: CConnman(); ~CConnman(); - bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError); + bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError); void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); @@ -199,6 +199,10 @@ public: uint64_t GetTotalBytesRecv(); uint64_t GetTotalBytesSent(); + void SetBestHeight(int height); + int GetBestHeight() const; + + private: struct ListenSocket { SOCKET socket; @@ -288,12 +292,13 @@ private: CSemaphore *semOutbound; int nMaxConnections; int nMaxOutbound; + std::atomic nBestHeight; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnections, int nMaxOutbound, std::string& strNodeError); +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnections, int nMaxOutbound, int nBestHeightIn, std::string& strNodeError); bool StopNode(CConnman& connman); size_t SocketSendData(CNode *pnode); @@ -315,7 +320,6 @@ struct CombinerAll // Signals for message handling struct CNodeSignals { - boost::signals2::signal GetHeight; boost::signals2::signal ProcessMessages; boost::signals2::signal SendMessages; boost::signals2::signal InitializeNode; @@ -558,7 +562,7 @@ public: CAmount lastSentFeeFilter; int64_t nextSendTimeFeeFilter; - CNode(NodeId id, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); + CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: @@ -569,6 +573,7 @@ private: uint64_t nLocalHostNonce; ServiceFlags nLocalServices; + int nMyStartingHeight; public: NodeId GetId() const { diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 2265f43a6..33f107d84 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) { connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, NODE_NETWORK, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); - CNode dummyNode2(id++, NODE_NETWORK, INVALID_SOCKET, addr2, "", true); + CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, "", true); GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) connman->ClearBanned(); mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, NODE_NETWORK, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, "", true); + CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, "", true); GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); dummyNode.nVersion = 1; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 1019b12c1..bc9a98ab0 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -154,6 +154,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) { SOCKET hSocket = INVALID_SOCKET; NodeId id = 0; + int height = 0; in_addr ipv4Addr; ipv4Addr.s_addr = 0xa0b0c001; @@ -163,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) bool fInboundIn = false; // Test that fFeeler is false by default. - CNode* pnode1 = new CNode(id++, NODE_NETWORK, hSocket, addr, pszDest, fInboundIn); + CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn); BOOST_CHECK(pnode1->fInbound == false); BOOST_CHECK(pnode1->fFeeler == false); fInboundIn = true; - CNode* pnode2 = new CNode(id++, NODE_NETWORK, hSocket, addr, pszDest, fInboundIn); + CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn); BOOST_CHECK(pnode2->fInbound == true); BOOST_CHECK(pnode2->fFeeler == false); } From e81a602cf02edfb21c3ec097bd7cf71f189ed783 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 25 May 2016 21:26:46 -0400 Subject: [PATCH 26/33] net: pass CClientUIInterface into CConnman --- src/init.cpp | 2 +- src/net.cpp | 27 +++++++++++++++++---------- src/net.h | 7 +++++-- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4dce8be81..9e2ed62a9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1510,7 +1510,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::string strNodeError; int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); - if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, chainActive.Height(), strNodeError)) + if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, chainActive.Height(), &uiInterface, strNodeError)) return InitError(strNodeError); // ********************************************************* Step 12: finished diff --git a/src/net.cpp b/src/net.cpp index d51095255..13218b422 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -474,7 +474,8 @@ void CConnman::ClearBanned() setBannedIsDirty = true; } DumpBanlist(); //store banlist to disk - uiInterface.BannedListChanged(); + if(clientInterface) + clientInterface->BannedListChanged(); } bool CConnman::IsBanned(CNetAddr ip) @@ -534,7 +535,8 @@ void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t ba else return; } - uiInterface.BannedListChanged(); + if(clientInterface) + clientInterface->BannedListChanged(); { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { @@ -558,7 +560,8 @@ bool CConnman::Unban(const CSubNet &subNet) { return false; setBannedIsDirty = true; } - uiInterface.BannedListChanged(); + if(clientInterface) + clientInterface->BannedListChanged(); DumpBanlist(); //store banlist to disk immediately return true; } @@ -1104,7 +1107,8 @@ void CConnman::ThreadSocketHandler() } if(vNodes.size() != nPrevNodeCount) { nPrevNodeCount = vNodes.size(); - uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount); + if(clientInterface) + clientInterface->NotifyNumConnectionsChanged(nPrevNodeCount); } // @@ -2037,13 +2041,14 @@ CConnman::CConnman() nMaxConnections = 0; nMaxOutbound = 0; nBestHeight = 0; + clientInterface = NULL; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, interfaceIn, strNodeError); return ret; } @@ -2053,7 +2058,7 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; @@ -2072,7 +2077,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se SetBestHeight(nBestHeightIn); - uiInterface.InitMessage(_("Loading addresses...")); + clientInterface = interfaceIn; + if (clientInterface) + clientInterface->InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); { @@ -2085,8 +2092,8 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se DumpAddresses(); } } - - uiInterface.InitMessage(_("Loading banlist...")); + if (clientInterface) + clientInterface->InitMessage(_("Loading banlist...")); // Load addresses from banlist.dat nStart = GetTimeMillis(); CBanDB bandb; diff --git a/src/net.h b/src/net.h index 852822d85..a45e18da6 100644 --- a/src/net.h +++ b/src/net.h @@ -96,6 +96,8 @@ struct AddedNodeInfo class CTransaction; class CNodeStats; +class CClientUIInterface; + class CConnman { public: @@ -109,7 +111,7 @@ public: CConnman(); ~CConnman(); - bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError); + bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError); void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); @@ -293,12 +295,13 @@ private: int nMaxConnections; int nMaxOutbound; std::atomic nBestHeight; + CClientUIInterface* clientInterface; }; extern std::unique_ptr g_connman; void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnections, int nMaxOutbound, int nBestHeightIn, std::string& strNodeError); +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnections, int nMaxOutbound, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError); bool StopNode(CConnman& connman); size_t SocketSendData(CNode *pnode); From bafa5fc5a1ba33337b5eb3d8ae24ba2fac2949f8 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 26 May 2016 23:29:39 -0400 Subject: [PATCH 27/33] net: Drop StartNode/StopNode and use CConnman directly --- src/init.cpp | 10 ++++++++-- src/net.cpp | 24 ++---------------------- src/net.h | 3 +-- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 9e2ed62a9..4e1c8e1b6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -199,7 +199,8 @@ void Shutdown() if (pwalletMain) pwalletMain->Flush(false); #endif - StopNode(*g_connman); + MapPort(false); + g_connman->Stop(); g_connman.reset(); StopTorControl(); @@ -1508,9 +1509,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); + Discover(threadGroup); + + // Map ports with UPnP + MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); + std::string strNodeError; int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); - if(!StartNode(connman, threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, chainActive.Height(), &uiInterface, strNodeError)) + if(!connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, chainActive.Height(), &uiInterface, strNodeError)) return InitError(strNodeError); // ********************************************************* Step 12: finished diff --git a/src/net.cpp b/src/net.cpp index 13218b422..15c066cd7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1979,7 +1979,7 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b return true; } -void static Discover(boost::thread_group& threadGroup) +void Discover(boost::thread_group& threadGroup) { if (!fDiscover) return; @@ -2044,15 +2044,6 @@ CConnman::CConnman() clientInterface = NULL; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) -{ - Discover(threadGroup); - - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, interfaceIn, strNodeError); - - return ret; -} - NodeId CConnman::GetNewNodeId() { return nLastNodeId.fetch_add(1, std::memory_order_relaxed); @@ -2136,9 +2127,6 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se else threadGroup.create_thread(boost::bind(&TraceThread >, "dnsseed", boost::function(boost::bind(&CConnman::ThreadDNSAddressSeed, this)))); - // Map ports with UPnP - MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); - // Send and receive from sockets, accept connections threadGroup.create_thread(boost::bind(&TraceThread >, "net", boost::function(boost::bind(&CConnman::ThreadSocketHandler, this)))); @@ -2157,15 +2145,6 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se return true; } -bool StopNode(CConnman& connman) -{ - LogPrintf("StopNode()\n"); - MapPort(false); - - connman.Stop(); - return true; -} - class CNetCleanup { public: @@ -2183,6 +2162,7 @@ instance_of_cnetcleanup; void CConnman::Stop() { + LogPrintf("%s\n",__func__); if (semOutbound) for (int i=0; i<(nMaxOutbound + MAX_FEELER_CONNECTIONS); i++) semOutbound->post(); diff --git a/src/net.h b/src/net.h index a45e18da6..e08409e81 100644 --- a/src/net.h +++ b/src/net.h @@ -298,11 +298,10 @@ private: CClientUIInterface* clientInterface; }; extern std::unique_ptr g_connman; +void Discover(boost::thread_group& threadGroup); void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnections, int nMaxOutbound, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError); -bool StopNode(CConnman& connman); size_t SocketSendData(CNode *pnode); struct CombinerAll From a19553b992f40b9f98e6e0be4cd529a89746ef50 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 26 May 2016 23:53:08 -0400 Subject: [PATCH 28/33] net: Introduce CConnection::Options to avoid passing so many params --- src/init.cpp | 11 +++++++++-- src/net.cpp | 14 +++++++------- src/net.h | 11 ++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4e1c8e1b6..e10803643 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1515,8 +1515,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); std::string strNodeError; - int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); - if(!connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnections, nMaxOutbound, chainActive.Height(), &uiInterface, strNodeError)) + CConnman::Options connOptions; + connOptions.nLocalServices = nLocalServices; + connOptions.nRelevantServices = nRelevantServices; + connOptions.nMaxConnections = nMaxConnections; + connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections); + connOptions.nBestHeight = chainActive.Height(); + connOptions.uiInterface = &uiInterface; + + if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions)) return InitError(strNodeError); // ********************************************************* Step 12: finished diff --git a/src/net.cpp b/src/net.cpp index 15c066cd7..8ea600b37 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2049,26 +2049,26 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options connOptions) { nTotalBytesRecv = 0; nTotalBytesSent = 0; nMaxOutboundLimit = 0; nMaxOutboundTotalBytesSentInCycle = 0; nMaxOutboundTimeframe = 60*60*24; //1 day - nLocalServices = nLocalServicesIn; - nRelevantServices = nRelevantServicesIn; nMaxOutboundCycleStartTime = 0; - nMaxConnections = nMaxConnectionsIn; - nMaxOutbound = std::min((nMaxOutboundIn), nMaxConnections); + nRelevantServices = connOptions.nRelevantServices; + nLocalServices = connOptions.nLocalServices; + nMaxConnections = connOptions.nMaxConnections; + nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); - SetBestHeight(nBestHeightIn); + SetBestHeight(connOptions.nBestHeight); - clientInterface = interfaceIn; + clientInterface = connOptions.uiInterface; if (clientInterface) clientInterface->InitMessage(_("Loading addresses...")); // Load addresses from peers.dat diff --git a/src/net.h b/src/net.h index e08409e81..8067ee68a 100644 --- a/src/net.h +++ b/src/net.h @@ -109,9 +109,18 @@ public: CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT), }; + struct Options + { + ServiceFlags nLocalServices = NODE_NONE; + ServiceFlags nRelevantServices = NODE_NONE; + int nMaxConnections = 0; + int nMaxOutbound = 0; + int nBestHeight = 0; + CClientUIInterface* uiInterface = nullptr; + }; CConnman(); ~CConnman(); - bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError); + bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options options); void Stop(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); From fa2f8bc47fa17deccb281b750ff6c48402c5b1ce Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 27 May 2016 00:00:02 -0400 Subject: [PATCH 29/33] net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options --- src/init.cpp | 2 ++ src/net.cpp | 4 ++-- src/net.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index e10803643..8f7cef20c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1522,6 +1522,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections); connOptions.nBestHeight = chainActive.Height(); connOptions.uiInterface = &uiInterface; + connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); + connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions)) return InitError(strNodeError); diff --git a/src/net.cpp b/src/net.cpp index 8ea600b37..9b18a3274 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2063,8 +2063,8 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); - nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); - nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + nSendBufferMaxSize = connOptions.nSendBufferMaxSize; + nReceiveFloodSize = connOptions.nSendBufferMaxSize; SetBestHeight(connOptions.nBestHeight); diff --git a/src/net.h b/src/net.h index 8067ee68a..a50066da9 100644 --- a/src/net.h +++ b/src/net.h @@ -117,6 +117,8 @@ public: int nMaxOutbound = 0; int nBestHeight = 0; CClientUIInterface* uiInterface = nullptr; + unsigned int nSendBufferMaxSize = 0; + unsigned int nReceiveFloodSize = 0; }; CConnman(); ~CConnman(); From 98591c50273b13cfc5419548b527280d6a84a43d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 27 May 2016 01:00:01 -0400 Subject: [PATCH 30/33] net: move vNodesDisconnected into CConnman --- src/net.cpp | 2 -- src/net.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 9b18a3274..508b0dd96 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -820,8 +820,6 @@ size_t SocketSendData(CNode *pnode) return nSentSize; } -static std::list vNodesDisconnected; - struct NodeEvictionCandidate { NodeId id; diff --git a/src/net.h b/src/net.h index a50066da9..018126d67 100644 --- a/src/net.h +++ b/src/net.h @@ -292,6 +292,7 @@ private: std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; std::vector vNodes; + std::list vNodesDisconnected; mutable CCriticalSection cs_vNodes; std::atomic nLastNodeId; boost::condition_variable messageHandlerCondition; From d1a2295f0d58423652b124b48fc887a9721b765c Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Wed, 15 Jun 2016 19:28:04 -0400 Subject: [PATCH 31/33] Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting --- src/main.cpp | 3 --- src/net.cpp | 37 +++++++++++++++++++++++++++++++++---- src/net.h | 12 ++++++++---- src/rpc/misc.cpp | 1 - src/rpc/net.cpp | 1 - src/rpc/rawtransaction.cpp | 1 - src/wallet/wallet.cpp | 1 - 7 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1835d9712..e4c9ce562 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3091,7 +3091,6 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, pnode->PushBlockHash(hash); } } - return true; }); } // Notify external listeners about the new tip. @@ -4727,7 +4726,6 @@ static void RelayTransaction(const CTransaction& tx, CConnman& connman) connman.ForEachNode([&inv](CNode* pnode) { pnode->PushInventory(inv); - return true; }); } @@ -4749,7 +4747,6 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize(); mapMix.emplace(hashKey, pnode); } - return true; }; auto pushfunc = [&addr, &mapMix, &nRelayNodes] { diff --git a/src/net.cpp b/src/net.cpp index 508b0dd96..bf5cc07db 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2697,7 +2697,7 @@ bool CConnman::ForNode(NodeId id, std::function func) return found != nullptr && func(found); } -bool CConnman::ForEachNode(std::function func) +bool CConnman::ForEachNodeContinueIf(std::function func) { LOCK(cs_vNodes); for (auto&& node : vNodes) @@ -2706,7 +2706,7 @@ bool CConnman::ForEachNode(std::function func) return true; } -bool CConnman::ForEachNode(std::function func) const +bool CConnman::ForEachNodeContinueIf(std::function func) const { LOCK(cs_vNodes); for (const auto& node : vNodes) @@ -2715,7 +2715,7 @@ bool CConnman::ForEachNode(std::function func) const return true; } -bool CConnman::ForEachNodeThen(std::function pre, std::function post) +bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) { bool ret = true; LOCK(cs_vNodes); @@ -2728,7 +2728,7 @@ bool CConnman::ForEachNodeThen(std::function pre, std::funct return ret; } -bool CConnman::ForEachNodeThen(std::function pre, std::function post) const +bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) const { bool ret = true; LOCK(cs_vNodes); @@ -2741,6 +2741,35 @@ bool CConnman::ForEachNodeThen(std::function pre, std: return ret; } +void CConnman::ForEachNode(std::function func) +{ + LOCK(cs_vNodes); + for (auto&& node : vNodes) + func(node); +} + +void CConnman::ForEachNode(std::function func) const +{ + LOCK(cs_vNodes); + for (const auto& node : vNodes) + func(node); +} + +void CConnman::ForEachNodeThen(std::function pre, std::function post) +{ + LOCK(cs_vNodes); + for (auto&& node : vNodes) + pre(node); + post(); +} + +void CConnman::ForEachNodeThen(std::function pre, std::function post) const +{ + LOCK(cs_vNodes); + for (const auto& node : vNodes) + pre(node); + post(); +} int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } diff --git a/src/net.h b/src/net.h index 018126d67..6ee0430f2 100644 --- a/src/net.h +++ b/src/net.h @@ -129,10 +129,14 @@ public: bool CheckIncomingNonce(uint64_t nonce); bool ForNode(NodeId id, std::function func); - bool ForEachNode(std::function func); - bool ForEachNode(std::function func) const; - bool ForEachNodeThen(std::function pre, std::function post); - bool ForEachNodeThen(std::function pre, std::function post) const; + bool ForEachNodeContinueIf(std::function func); + bool ForEachNodeContinueIf(std::function func) const; + bool ForEachNodeContinueIfThen(std::function pre, std::function post); + bool ForEachNodeContinueIfThen(std::function pre, std::function post) const; + void ForEachNode(std::function func); + void ForEachNode(std::function func) const; + void ForEachNodeThen(std::function pre, std::function post); + void ForEachNodeThen(std::function pre, std::function post) const; void RelayTransaction(const CTransaction& tx); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index ffd377b48..2b5782367 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -481,7 +481,6 @@ UniValue setmocktime(const UniValue& params, bool fHelp) if(g_connman) { g_connman->ForEachNode([t](CNode* pnode) { pnode->nLastSend = pnode->nLastRecv = t; - return true; }); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 61b6b62c9..b011029f5 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -61,7 +61,6 @@ UniValue ping(const UniValue& params, bool fHelp) // Request that each node send a ping during next message processing pass g_connman->ForEachNode([](CNode* pnode) { pnode->fPingQueued = true; - return true; }); return NullUniValue; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3daf1681f..d2ad0a52b 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -898,7 +898,6 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) g_connman->ForEachNode([&inv](CNode* pnode) { pnode->PushInventory(inv); - return true; }); return hashTx.GetHex(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index fd8b056bf..60ac2ea16 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1465,7 +1465,6 @@ bool CWalletTx::RelayWalletTransaction(CConnman* connman) connman->ForEachNode([&inv](CNode* pnode) { pnode->PushInventory(inv); - return true; }); return true; } From e700cd0bc885340563df9e6b7a5b6c6603b8c984 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sun, 19 Jun 2016 21:42:15 -0400 Subject: [PATCH 32/33] Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead --- src/net.cpp | 73 ------------------------------------------- src/net.h | 90 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 81 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index bf5cc07db..19c14e105 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2697,79 +2697,6 @@ bool CConnman::ForNode(NodeId id, std::function func) return found != nullptr && func(found); } -bool CConnman::ForEachNodeContinueIf(std::function func) -{ - LOCK(cs_vNodes); - for (auto&& node : vNodes) - if(!func(node)) - return false; - return true; -} - -bool CConnman::ForEachNodeContinueIf(std::function func) const -{ - LOCK(cs_vNodes); - for (const auto& node : vNodes) - if(!func(node)) - return false; - return true; -} - -bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) -{ - bool ret = true; - LOCK(cs_vNodes); - for (auto&& node : vNodes) - if(!pre(node)) { - ret = false; - break; - } - post(); - return ret; -} - -bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) const -{ - bool ret = true; - LOCK(cs_vNodes); - for (const auto& node : vNodes) - if(!pre(node)) { - ret = false; - break; - } - post(); - return ret; -} - -void CConnman::ForEachNode(std::function func) -{ - LOCK(cs_vNodes); - for (auto&& node : vNodes) - func(node); -} - -void CConnman::ForEachNode(std::function func) const -{ - LOCK(cs_vNodes); - for (const auto& node : vNodes) - func(node); -} - -void CConnman::ForEachNodeThen(std::function pre, std::function post) -{ - LOCK(cs_vNodes); - for (auto&& node : vNodes) - pre(node); - post(); -} - -void CConnman::ForEachNodeThen(std::function pre, std::function post) const -{ - LOCK(cs_vNodes); - for (const auto& node : vNodes) - pre(node); - post(); -} int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } diff --git a/src/net.h b/src/net.h index 6ee0430f2..97604ca56 100644 --- a/src/net.h +++ b/src/net.h @@ -129,14 +129,88 @@ public: bool CheckIncomingNonce(uint64_t nonce); bool ForNode(NodeId id, std::function func); - bool ForEachNodeContinueIf(std::function func); - bool ForEachNodeContinueIf(std::function func) const; - bool ForEachNodeContinueIfThen(std::function pre, std::function post); - bool ForEachNodeContinueIfThen(std::function pre, std::function post) const; - void ForEachNode(std::function func); - void ForEachNode(std::function func) const; - void ForEachNodeThen(std::function pre, std::function post); - void ForEachNodeThen(std::function pre, std::function post) const; + + template + bool ForEachNodeContinueIf(Callable&& func) + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) + if(!func(node)) + return false; + return true; + }; + + template + bool ForEachNodeContinueIf(Callable&& func) const + { + LOCK(cs_vNodes); + for (const auto& node : vNodes) + if(!func(node)) + return false; + return true; + }; + + template + bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post) + { + bool ret = true; + LOCK(cs_vNodes); + for (auto&& node : vNodes) + if(!pre(node)) { + ret = false; + break; + } + post(); + return ret; + }; + + template + bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post) const + { + bool ret = true; + LOCK(cs_vNodes); + for (const auto& node : vNodes) + if(!pre(node)) { + ret = false; + break; + } + post(); + return ret; + }; + + template + void ForEachNode(Callable&& func) + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) + func(node); + }; + + template + void ForEachNode(Callable&& func) const + { + LOCK(cs_vNodes); + for (const auto& node : vNodes) + func(node); + }; + + template + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) + pre(node); + post(); + }; + + template + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const + { + LOCK(cs_vNodes); + for (const auto& node : vNodes) + pre(node); + post(); + }; void RelayTransaction(const CTransaction& tx); From 0103c5b90fa61b5d159a825fcb5a05ca31d0d1c3 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 31 Aug 2016 13:17:28 -0400 Subject: [PATCH 33/33] net: move MAX_FEELER_CONNECTIONS into connman --- src/init.cpp | 1 + src/net.cpp | 14 +++++--------- src/net.h | 2 ++ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 8f7cef20c..a8b2cde36 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1520,6 +1520,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nRelevantServices = nRelevantServices; connOptions.nMaxConnections = nMaxConnections; connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections); + connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chainActive.Height(); connOptions.uiInterface = &uiInterface; connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); diff --git a/src/net.cpp b/src/net.cpp index 19c14e105..b39ef9f54 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -61,11 +61,6 @@ #endif #endif - -namespace { - const int MAX_FEELER_CONNECTIONS = 1; -} - const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; // @@ -971,7 +966,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; - int nMaxInbound = nMaxConnections - (nMaxOutbound + MAX_FEELER_CONNECTIONS); + int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler); assert(nMaxInbound > 0); if (hSocket != INVALID_SOCKET) @@ -1624,7 +1619,7 @@ void CConnman::ThreadOpenConnections() } } } - assert(nOutbound <= (nMaxOutbound + MAX_FEELER_CONNECTIONS)); + assert(nOutbound <= (nMaxOutbound + nMaxFeeler)); // Feeler Connections // @@ -2060,6 +2055,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nLocalServices = connOptions.nLocalServices; nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); + nMaxFeeler = connOptions.nMaxFeeler; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nSendBufferMaxSize; @@ -2106,7 +2102,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (semOutbound == NULL) { // initialize semaphore - semOutbound = new CSemaphore(std::min((nMaxOutbound + MAX_FEELER_CONNECTIONS), nMaxConnections)); + semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); } if (pnodeLocalHost == NULL) { @@ -2162,7 +2158,7 @@ void CConnman::Stop() { LogPrintf("%s\n",__func__); if (semOutbound) - for (int i=0; i<(nMaxOutbound + MAX_FEELER_CONNECTIONS); i++) + for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) semOutbound->post(); if (fAddressesInitialized) diff --git a/src/net.h b/src/net.h index 97604ca56..a48ee02c4 100644 --- a/src/net.h +++ b/src/net.h @@ -115,6 +115,7 @@ public: ServiceFlags nRelevantServices = NODE_NONE; int nMaxConnections = 0; int nMaxOutbound = 0; + int nMaxFeeler = 0; int nBestHeight = 0; CClientUIInterface* uiInterface = nullptr; unsigned int nSendBufferMaxSize = 0; @@ -384,6 +385,7 @@ private: CSemaphore *semOutbound; int nMaxConnections; int nMaxOutbound; + int nMaxFeeler; std::atomic nBestHeight; CClientUIInterface* clientInterface; };