mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 21:12:48 +01:00
commit
e3c063b315
290
src/main.cpp
290
src/main.cpp
@ -3029,6 +3029,115 @@ bool static AlreadyHave(const CInv& inv)
|
|||||||
unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
|
unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
|
||||||
|
|
||||||
|
|
||||||
|
void static ProcessGetData(CNode* pfrom)
|
||||||
|
{
|
||||||
|
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
|
||||||
|
|
||||||
|
vector<CInv> vNotFound;
|
||||||
|
|
||||||
|
while (it != pfrom->vRecvGetData.end()) {
|
||||||
|
// Don't bother if send buffer is too full to respond anyway
|
||||||
|
if (pfrom->nSendSize >= SendBufferSize())
|
||||||
|
break;
|
||||||
|
|
||||||
|
const CInv &inv = *it;
|
||||||
|
{
|
||||||
|
if (fShutdown)
|
||||||
|
break;
|
||||||
|
it++;
|
||||||
|
|
||||||
|
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
|
||||||
|
{
|
||||||
|
// Send block from disk
|
||||||
|
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
|
||||||
|
if (mi != mapBlockIndex.end())
|
||||||
|
{
|
||||||
|
CBlock block;
|
||||||
|
block.ReadFromDisk((*mi).second);
|
||||||
|
if (inv.type == MSG_BLOCK)
|
||||||
|
pfrom->PushMessage("block", block);
|
||||||
|
else // MSG_FILTERED_BLOCK)
|
||||||
|
{
|
||||||
|
LOCK(pfrom->cs_filter);
|
||||||
|
if (pfrom->pfilter)
|
||||||
|
{
|
||||||
|
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
|
||||||
|
pfrom->PushMessage("merkleblock", merkleBlock);
|
||||||
|
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
|
||||||
|
// This avoids hurting performance by pointlessly requiring a round-trip
|
||||||
|
// Note that there is currently no way for a node to request any single transactions we didnt send here -
|
||||||
|
// they must either disconnect and retry or request the full block.
|
||||||
|
// Thus, the protocol spec specified allows for us to provide duplicate txn here,
|
||||||
|
// however we MUST always provide at least what the remote peer needs
|
||||||
|
typedef std::pair<unsigned int, uint256> PairType;
|
||||||
|
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
|
||||||
|
if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
|
||||||
|
pfrom->PushMessage("tx", block.vtx[pair.first]);
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// no response
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger them to send a getblocks request for the next batch of inventory
|
||||||
|
if (inv.hash == pfrom->hashContinue)
|
||||||
|
{
|
||||||
|
// Bypass PushInventory, this must send even if redundant,
|
||||||
|
// and we want it right after the last block so they don't
|
||||||
|
// wait for other stuff first.
|
||||||
|
vector<CInv> vInv;
|
||||||
|
vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
|
||||||
|
pfrom->PushMessage("inv", vInv);
|
||||||
|
pfrom->hashContinue = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (inv.IsKnownType())
|
||||||
|
{
|
||||||
|
// Send stream from relay memory
|
||||||
|
bool pushed = false;
|
||||||
|
{
|
||||||
|
LOCK(cs_mapRelay);
|
||||||
|
map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
|
||||||
|
if (mi != mapRelay.end()) {
|
||||||
|
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
|
||||||
|
pushed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pushed && inv.type == MSG_TX) {
|
||||||
|
LOCK(mempool.cs);
|
||||||
|
if (mempool.exists(inv.hash)) {
|
||||||
|
CTransaction tx = mempool.lookup(inv.hash);
|
||||||
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss.reserve(1000);
|
||||||
|
ss << tx;
|
||||||
|
pfrom->PushMessage("tx", ss);
|
||||||
|
pushed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pushed) {
|
||||||
|
vNotFound.push_back(inv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track requests for our stuff.
|
||||||
|
Inventory(inv.hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it);
|
||||||
|
|
||||||
|
if (!vNotFound.empty()) {
|
||||||
|
// Let the peer know that we didn't find what it asked for, so it doesn't
|
||||||
|
// have to wait around forever. Currently only SPV clients actually care
|
||||||
|
// about this message: it's needed when they are recursively walking the
|
||||||
|
// dependencies of relevant unconfirmed transactions. SPV clients want to
|
||||||
|
// do that because they want to know about (and store and rebroadcast and
|
||||||
|
// risk analyze) the dependencies of transactions relevant to them, without
|
||||||
|
// having to download the entire memory pool.
|
||||||
|
pfrom->PushMessage("notfound", vNotFound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||||
{
|
{
|
||||||
RandAddSeedPerfmon();
|
RandAddSeedPerfmon();
|
||||||
@ -3104,7 +3213,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
|
|
||||||
// Change version
|
// Change version
|
||||||
pfrom->PushMessage("verack");
|
pfrom->PushMessage("verack");
|
||||||
pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
|
pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
|
||||||
|
|
||||||
if (!pfrom->fInbound)
|
if (!pfrom->fInbound)
|
||||||
{
|
{
|
||||||
@ -3168,7 +3277,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
|
|
||||||
else if (strCommand == "verack")
|
else if (strCommand == "verack")
|
||||||
{
|
{
|
||||||
pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
|
pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3302,101 +3411,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
if (fDebugNet || (vInv.size() != 1))
|
if (fDebugNet || (vInv.size() != 1))
|
||||||
printf("received getdata (%"PRIszu" invsz)\n", vInv.size());
|
printf("received getdata (%"PRIszu" invsz)\n", vInv.size());
|
||||||
|
|
||||||
vector<CInv> vNotFound;
|
if ((fDebugNet && vInv.size() > 0) || (vInv.size() == 1))
|
||||||
BOOST_FOREACH(const CInv& inv, vInv)
|
printf("received getdata for: %s\n", vInv[0].ToString().c_str());
|
||||||
{
|
|
||||||
if (fShutdown)
|
|
||||||
return true;
|
|
||||||
if (fDebugNet || (vInv.size() == 1))
|
|
||||||
printf("received getdata for: %s\n", inv.ToString().c_str());
|
|
||||||
|
|
||||||
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
|
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
|
||||||
{
|
ProcessGetData(pfrom);
|
||||||
// Send block from disk
|
|
||||||
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
|
|
||||||
if (mi != mapBlockIndex.end())
|
|
||||||
{
|
|
||||||
CBlock block;
|
|
||||||
block.ReadFromDisk((*mi).second);
|
|
||||||
if (inv.type == MSG_BLOCK)
|
|
||||||
pfrom->PushMessage("block", block);
|
|
||||||
else // MSG_FILTERED_BLOCK)
|
|
||||||
{
|
|
||||||
LOCK(pfrom->cs_filter);
|
|
||||||
if (pfrom->pfilter)
|
|
||||||
{
|
|
||||||
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
|
|
||||||
pfrom->PushMessage("merkleblock", merkleBlock);
|
|
||||||
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
|
|
||||||
// This avoids hurting performance by pointlessly requiring a round-trip
|
|
||||||
// Note that there is currently no way for a node to request any single transactions we didnt send here -
|
|
||||||
// they must either disconnect and retry or request the full block.
|
|
||||||
// Thus, the protocol spec specified allows for us to provide duplicate txn here,
|
|
||||||
// however we MUST always provide at least what the remote peer needs
|
|
||||||
typedef std::pair<unsigned int, uint256> PairType;
|
|
||||||
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
|
|
||||||
if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
|
|
||||||
pfrom->PushMessage("tx", block.vtx[pair.first]);
|
|
||||||
}
|
|
||||||
// else
|
|
||||||
// no response
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger them to send a getblocks request for the next batch of inventory
|
|
||||||
if (inv.hash == pfrom->hashContinue)
|
|
||||||
{
|
|
||||||
// Bypass PushInventory, this must send even if redundant,
|
|
||||||
// and we want it right after the last block so they don't
|
|
||||||
// wait for other stuff first.
|
|
||||||
vector<CInv> vInv;
|
|
||||||
vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
|
|
||||||
pfrom->PushMessage("inv", vInv);
|
|
||||||
pfrom->hashContinue = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (inv.IsKnownType())
|
|
||||||
{
|
|
||||||
// Send stream from relay memory
|
|
||||||
bool pushed = false;
|
|
||||||
{
|
|
||||||
LOCK(cs_mapRelay);
|
|
||||||
map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
|
|
||||||
if (mi != mapRelay.end()) {
|
|
||||||
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
|
|
||||||
pushed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pushed && inv.type == MSG_TX) {
|
|
||||||
LOCK(mempool.cs);
|
|
||||||
if (mempool.exists(inv.hash)) {
|
|
||||||
CTransaction tx = mempool.lookup(inv.hash);
|
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
|
||||||
ss.reserve(1000);
|
|
||||||
ss << tx;
|
|
||||||
pfrom->PushMessage("tx", ss);
|
|
||||||
pushed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pushed) {
|
|
||||||
vNotFound.push_back(inv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Track requests for our stuff.
|
|
||||||
Inventory(inv.hash);
|
|
||||||
|
|
||||||
if (!vNotFound.empty()) {
|
|
||||||
// Let the peer know that we didn't find what it asked for, so it doesn't
|
|
||||||
// have to wait around forever. Currently only SPV clients actually care
|
|
||||||
// about this message: it's needed when they are recursively walking the
|
|
||||||
// dependencies of relevant unconfirmed transactions. SPV clients want to
|
|
||||||
// do that because they want to know about (and store and rebroadcast and
|
|
||||||
// risk analyze) the dependencies of transactions relevant to them, without
|
|
||||||
// having to download the entire memory pool.
|
|
||||||
pfrom->PushMessage("notfound", vNotFound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3705,13 +3724,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// requires LOCK(cs_vRecvMsg)
|
||||||
bool ProcessMessages(CNode* pfrom)
|
bool ProcessMessages(CNode* pfrom)
|
||||||
{
|
{
|
||||||
CDataStream& vRecv = pfrom->vRecv;
|
|
||||||
if (vRecv.empty())
|
|
||||||
return true;
|
|
||||||
//if (fDebug)
|
//if (fDebug)
|
||||||
// printf("ProcessMessages(%u bytes)\n", vRecv.size());
|
// printf("ProcessMessages(%zu messages)\n", pfrom->vRecvMsg.size());
|
||||||
|
|
||||||
//
|
//
|
||||||
// Message format
|
// Message format
|
||||||
@ -3721,33 +3738,41 @@ bool ProcessMessages(CNode* pfrom)
|
|||||||
// (4) checksum
|
// (4) checksum
|
||||||
// (x) data
|
// (x) data
|
||||||
//
|
//
|
||||||
|
bool fOk = true;
|
||||||
|
|
||||||
loop
|
if (!pfrom->vRecvGetData.empty())
|
||||||
{
|
ProcessGetData(pfrom);
|
||||||
|
|
||||||
|
std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin();
|
||||||
|
while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) {
|
||||||
// Don't bother if send buffer is too full to respond anyway
|
// Don't bother if send buffer is too full to respond anyway
|
||||||
if (pfrom->vSend.size() >= SendBufferSize())
|
if (pfrom->nSendSize >= SendBufferSize())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// get next message
|
||||||
|
CNetMessage& msg = *it;
|
||||||
|
|
||||||
|
//if (fDebug)
|
||||||
|
// printf("ProcessMessages(message %u msgsz, %zu bytes, complete:%s)\n",
|
||||||
|
// msg.hdr.nMessageSize, msg.vRecv.size(),
|
||||||
|
// msg.complete() ? "Y" : "N");
|
||||||
|
|
||||||
|
// end, if an incomplete message is found
|
||||||
|
if (!msg.complete())
|
||||||
|
break;
|
||||||
|
|
||||||
|
// at this point, any failure means we can delete the current message
|
||||||
|
it++;
|
||||||
|
|
||||||
// Scan for message start
|
// Scan for message start
|
||||||
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
|
if (memcmp(msg.hdr.pchMessageStart, pchMessageStart, sizeof(pchMessageStart)) != 0) {
|
||||||
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
|
printf("\n\nPROCESSMESSAGE: INVALID MESSAGESTART\n\n");
|
||||||
if (vRecv.end() - pstart < nHeaderSize)
|
fOk = false;
|
||||||
{
|
|
||||||
if ((int)vRecv.size() > nHeaderSize)
|
|
||||||
{
|
|
||||||
printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
|
|
||||||
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pstart - vRecv.begin() > 0)
|
|
||||||
printf("\n\nPROCESSMESSAGE SKIPPED %"PRIpdd" BYTES\n\n", pstart - vRecv.begin());
|
|
||||||
vRecv.erase(vRecv.begin(), pstart);
|
|
||||||
|
|
||||||
// Read header
|
// Read header
|
||||||
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
|
CMessageHeader& hdr = msg.hdr;
|
||||||
CMessageHeader hdr;
|
|
||||||
vRecv >> hdr;
|
|
||||||
if (!hdr.IsValid())
|
if (!hdr.IsValid())
|
||||||
{
|
{
|
||||||
printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
|
printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
|
||||||
@ -3757,19 +3782,9 @@ bool ProcessMessages(CNode* pfrom)
|
|||||||
|
|
||||||
// Message size
|
// Message size
|
||||||
unsigned int nMessageSize = hdr.nMessageSize;
|
unsigned int nMessageSize = hdr.nMessageSize;
|
||||||
if (nMessageSize > MAX_SIZE)
|
|
||||||
{
|
|
||||||
printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (nMessageSize > vRecv.size())
|
|
||||||
{
|
|
||||||
// Rewind and wait for rest of message
|
|
||||||
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checksum
|
// Checksum
|
||||||
|
CDataStream& vRecv = msg.vRecv;
|
||||||
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
|
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
|
||||||
unsigned int nChecksum = 0;
|
unsigned int nChecksum = 0;
|
||||||
memcpy(&nChecksum, &hash, sizeof(nChecksum));
|
memcpy(&nChecksum, &hash, sizeof(nChecksum));
|
||||||
@ -3780,20 +3795,16 @@ bool ProcessMessages(CNode* pfrom)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy message to its own buffer
|
|
||||||
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
|
|
||||||
vRecv.ignore(nMessageSize);
|
|
||||||
|
|
||||||
// Process message
|
// Process message
|
||||||
bool fRet = false;
|
bool fRet = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
fRet = ProcessMessage(pfrom, strCommand, vMsg);
|
fRet = ProcessMessage(pfrom, strCommand, vRecv);
|
||||||
}
|
}
|
||||||
if (fShutdown)
|
if (fShutdown)
|
||||||
return true;
|
break;
|
||||||
}
|
}
|
||||||
catch (std::ios_base::failure& e)
|
catch (std::ios_base::failure& e)
|
||||||
{
|
{
|
||||||
@ -3822,8 +3833,11 @@ bool ProcessMessages(CNode* pfrom)
|
|||||||
printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
|
printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
vRecv.Compact();
|
// In case the connection got shut down, its receive buffer was wiped
|
||||||
return true;
|
if (!pfrom->fDisconnect)
|
||||||
|
pfrom->vRecvMsg.erase(pfrom->vRecvMsg.begin(), it);
|
||||||
|
|
||||||
|
return fOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3837,7 +3851,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|||||||
|
|
||||||
// Keep-alive ping. We send a nonce of zero because we don't use it anywhere
|
// Keep-alive ping. We send a nonce of zero because we don't use it anywhere
|
||||||
// right now.
|
// right now.
|
||||||
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
|
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSendMsg.empty()) {
|
||||||
uint64 nonce = 0;
|
uint64 nonce = 0;
|
||||||
if (pto->nVersion > BIP0031_VERSION)
|
if (pto->nVersion > BIP0031_VERSION)
|
||||||
pto->PushMessage("ping", nonce);
|
pto->PushMessage("ping", nonce);
|
||||||
|
181
src/net.cpp
181
src/net.cpp
@ -536,7 +536,11 @@ void CNode::CloseSocketDisconnect()
|
|||||||
printf("disconnecting node %s\n", addrName.c_str());
|
printf("disconnecting node %s\n", addrName.c_str());
|
||||||
closesocket(hSocket);
|
closesocket(hSocket);
|
||||||
hSocket = INVALID_SOCKET;
|
hSocket = INVALID_SOCKET;
|
||||||
vRecv.clear();
|
|
||||||
|
// in case this fails, we'll empty the recv buffer when the CNode is deleted
|
||||||
|
TRY_LOCK(cs_vRecvMsg, lockRecv);
|
||||||
|
if (lockRecv)
|
||||||
|
vRecvMsg.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,6 +632,77 @@ void CNode::copyStats(CNodeStats &stats)
|
|||||||
}
|
}
|
||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
|
// requires LOCK(cs_vRecvMsg)
|
||||||
|
bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
|
||||||
|
{
|
||||||
|
while (nBytes > 0) {
|
||||||
|
|
||||||
|
// get current incomplete message, or create a new one
|
||||||
|
if (vRecvMsg.empty() ||
|
||||||
|
vRecvMsg.back().complete())
|
||||||
|
vRecvMsg.push_back(CNetMessage(SER_NETWORK, nRecvVersion));
|
||||||
|
|
||||||
|
CNetMessage& msg = vRecvMsg.back();
|
||||||
|
|
||||||
|
// absorb network data
|
||||||
|
int handled;
|
||||||
|
if (!msg.in_data)
|
||||||
|
handled = msg.readHeader(pch, nBytes);
|
||||||
|
else
|
||||||
|
handled = msg.readData(pch, nBytes);
|
||||||
|
|
||||||
|
if (handled < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pch += handled;
|
||||||
|
nBytes -= handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
|
||||||
|
{
|
||||||
|
// copy data to temporary parsing buffer
|
||||||
|
unsigned int nRemaining = 24 - nHdrPos;
|
||||||
|
unsigned int nCopy = std::min(nRemaining, nBytes);
|
||||||
|
|
||||||
|
memcpy(&hdrbuf[nHdrPos], pch, nCopy);
|
||||||
|
nHdrPos += nCopy;
|
||||||
|
|
||||||
|
// if header incomplete, exit
|
||||||
|
if (nHdrPos < 24)
|
||||||
|
return nCopy;
|
||||||
|
|
||||||
|
// deserialize to CMessageHeader
|
||||||
|
try {
|
||||||
|
hdrbuf >> hdr;
|
||||||
|
}
|
||||||
|
catch (std::exception &e) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reject messages larger than MAX_SIZE
|
||||||
|
if (hdr.nMessageSize > MAX_SIZE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// switch state to reading message data
|
||||||
|
in_data = true;
|
||||||
|
vRecv.resize(hdr.nMessageSize);
|
||||||
|
|
||||||
|
return nCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CNetMessage::readData(const char *pch, unsigned int nBytes)
|
||||||
|
{
|
||||||
|
unsigned int nRemaining = hdr.nMessageSize - nDataPos;
|
||||||
|
unsigned int nCopy = std::min(nRemaining, nBytes);
|
||||||
|
|
||||||
|
memcpy(&vRecv[nDataPos], pch, nCopy);
|
||||||
|
nDataPos += nCopy;
|
||||||
|
|
||||||
|
return nCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -637,6 +712,48 @@ void CNode::copyStats(CNodeStats &stats)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// requires LOCK(cs_vSend)
|
||||||
|
void SocketSendData(CNode *pnode)
|
||||||
|
{
|
||||||
|
std::deque<CSerializeData>::iterator it = pnode->vSendMsg.begin();
|
||||||
|
|
||||||
|
while (it != pnode->vSendMsg.end()) {
|
||||||
|
const CSerializeData &data = *it;
|
||||||
|
assert(data.size() > pnode->nSendOffset);
|
||||||
|
int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||||
|
if (nBytes > 0) {
|
||||||
|
pnode->nLastSend = GetTime();
|
||||||
|
pnode->nSendOffset += nBytes;
|
||||||
|
if (pnode->nSendOffset == data.size()) {
|
||||||
|
pnode->nSendOffset = 0;
|
||||||
|
pnode->nSendSize -= data.size();
|
||||||
|
it++;
|
||||||
|
} else {
|
||||||
|
// could not send full message; stop sending more
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nBytes < 0) {
|
||||||
|
// error
|
||||||
|
int nErr = WSAGetLastError();
|
||||||
|
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
|
||||||
|
{
|
||||||
|
printf("socket send error %d\n", nErr);
|
||||||
|
pnode->CloseSocketDisconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// couldn't send anything at all
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it == pnode->vSendMsg.end()) {
|
||||||
|
assert(pnode->nSendOffset == 0);
|
||||||
|
assert(pnode->nSendSize == 0);
|
||||||
|
}
|
||||||
|
pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
|
||||||
|
}
|
||||||
|
|
||||||
void ThreadSocketHandler(void* parg)
|
void ThreadSocketHandler(void* parg)
|
||||||
{
|
{
|
||||||
// Make this thread recognisable as the networking thread
|
// Make this thread recognisable as the networking thread
|
||||||
@ -676,7 +793,7 @@ void ThreadSocketHandler2(void* parg)
|
|||||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||||
{
|
{
|
||||||
if (pnode->fDisconnect ||
|
if (pnode->fDisconnect ||
|
||||||
(pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
|
(pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty()))
|
||||||
{
|
{
|
||||||
// remove from vNodes
|
// remove from vNodes
|
||||||
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
|
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
|
||||||
@ -708,7 +825,7 @@ void ThreadSocketHandler2(void* parg)
|
|||||||
TRY_LOCK(pnode->cs_vSend, lockSend);
|
TRY_LOCK(pnode->cs_vSend, lockSend);
|
||||||
if (lockSend)
|
if (lockSend)
|
||||||
{
|
{
|
||||||
TRY_LOCK(pnode->cs_vRecv, lockRecv);
|
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
|
||||||
if (lockRecv)
|
if (lockRecv)
|
||||||
{
|
{
|
||||||
TRY_LOCK(pnode->cs_inventory, lockInv);
|
TRY_LOCK(pnode->cs_inventory, lockInv);
|
||||||
@ -759,14 +876,18 @@ void ThreadSocketHandler2(void* parg)
|
|||||||
{
|
{
|
||||||
if (pnode->hSocket == INVALID_SOCKET)
|
if (pnode->hSocket == INVALID_SOCKET)
|
||||||
continue;
|
continue;
|
||||||
|
{
|
||||||
|
TRY_LOCK(pnode->cs_vSend, lockSend);
|
||||||
|
if (lockSend) {
|
||||||
|
// do not read, if draining write queue
|
||||||
|
if (!pnode->vSendMsg.empty())
|
||||||
|
FD_SET(pnode->hSocket, &fdsetSend);
|
||||||
|
else
|
||||||
FD_SET(pnode->hSocket, &fdsetRecv);
|
FD_SET(pnode->hSocket, &fdsetRecv);
|
||||||
FD_SET(pnode->hSocket, &fdsetError);
|
FD_SET(pnode->hSocket, &fdsetError);
|
||||||
hSocketMax = max(hSocketMax, pnode->hSocket);
|
hSocketMax = max(hSocketMax, pnode->hSocket);
|
||||||
have_fds = true;
|
have_fds = true;
|
||||||
{
|
}
|
||||||
TRY_LOCK(pnode->cs_vSend, lockSend);
|
|
||||||
if (lockSend && !pnode->vSend.empty())
|
|
||||||
FD_SET(pnode->hSocket, &fdsetSend);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -873,15 +994,12 @@ void ThreadSocketHandler2(void* parg)
|
|||||||
continue;
|
continue;
|
||||||
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
|
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
|
||||||
{
|
{
|
||||||
TRY_LOCK(pnode->cs_vRecv, lockRecv);
|
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
|
||||||
if (lockRecv)
|
if (lockRecv)
|
||||||
{
|
{
|
||||||
CDataStream& vRecv = pnode->vRecv;
|
if (pnode->GetTotalRecvSize() > ReceiveFloodSize()) {
|
||||||
unsigned int nPos = vRecv.size();
|
|
||||||
|
|
||||||
if (nPos > ReceiveBufferSize()) {
|
|
||||||
if (!pnode->fDisconnect)
|
if (!pnode->fDisconnect)
|
||||||
printf("socket recv flood control disconnect (%"PRIszu" bytes)\n", vRecv.size());
|
printf("socket recv flood control disconnect (%u bytes)\n", pnode->GetTotalRecvSize());
|
||||||
pnode->CloseSocketDisconnect();
|
pnode->CloseSocketDisconnect();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -890,8 +1008,8 @@ void ThreadSocketHandler2(void* parg)
|
|||||||
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
||||||
if (nBytes > 0)
|
if (nBytes > 0)
|
||||||
{
|
{
|
||||||
vRecv.resize(nPos + nBytes);
|
if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
|
||||||
memcpy(&vRecv[nPos], pchBuf, nBytes);
|
pnode->CloseSocketDisconnect();
|
||||||
pnode->nLastRecv = GetTime();
|
pnode->nLastRecv = GetTime();
|
||||||
}
|
}
|
||||||
else if (nBytes == 0)
|
else if (nBytes == 0)
|
||||||
@ -925,34 +1043,13 @@ void ThreadSocketHandler2(void* parg)
|
|||||||
{
|
{
|
||||||
TRY_LOCK(pnode->cs_vSend, lockSend);
|
TRY_LOCK(pnode->cs_vSend, lockSend);
|
||||||
if (lockSend)
|
if (lockSend)
|
||||||
{
|
SocketSendData(pnode);
|
||||||
CDataStream& vSend = pnode->vSend;
|
|
||||||
if (!vSend.empty())
|
|
||||||
{
|
|
||||||
int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
|
|
||||||
if (nBytes > 0)
|
|
||||||
{
|
|
||||||
vSend.erase(vSend.begin(), vSend.begin() + nBytes);
|
|
||||||
pnode->nLastSend = GetTime();
|
|
||||||
}
|
|
||||||
else if (nBytes < 0)
|
|
||||||
{
|
|
||||||
// error
|
|
||||||
int nErr = WSAGetLastError();
|
|
||||||
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
|
|
||||||
{
|
|
||||||
printf("socket send error %d\n", nErr);
|
|
||||||
pnode->CloseSocketDisconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Inactivity checking
|
// Inactivity checking
|
||||||
//
|
//
|
||||||
if (pnode->vSend.empty())
|
if (pnode->vSendMsg.empty())
|
||||||
pnode->nLastSendEmpty = GetTime();
|
pnode->nLastSendEmpty = GetTime();
|
||||||
if (GetTime() - pnode->nTimeConnected > 60)
|
if (GetTime() - pnode->nTimeConnected > 60)
|
||||||
{
|
{
|
||||||
@ -1691,11 +1788,15 @@ void ThreadMessageHandler2(void* parg)
|
|||||||
pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
|
pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
|
||||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||||
{
|
{
|
||||||
|
if (pnode->fDisconnect)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Receive messages
|
// Receive messages
|
||||||
{
|
{
|
||||||
TRY_LOCK(pnode->cs_vRecv, lockRecv);
|
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
|
||||||
if (lockRecv)
|
if (lockRecv)
|
||||||
ProcessMessages(pnode);
|
if (!ProcessMessages(pnode))
|
||||||
|
pnode->CloseSocketDisconnect();
|
||||||
}
|
}
|
||||||
if (fShutdown)
|
if (fShutdown)
|
||||||
return;
|
return;
|
||||||
|
137
src/net.h
137
src/net.h
@ -27,7 +27,7 @@ extern int nBestHeight;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
|
inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
|
||||||
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
|
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
|
||||||
|
|
||||||
void AddOneShot(std::string strDest);
|
void AddOneShot(std::string strDest);
|
||||||
@ -42,6 +42,7 @@ unsigned short GetListenPort();
|
|||||||
bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
|
bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
|
||||||
void StartNode(void* parg);
|
void StartNode(void* parg);
|
||||||
bool StopNode();
|
bool StopNode();
|
||||||
|
void SocketSendData(CNode *pnode);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -126,6 +127,44 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CNetMessage {
|
||||||
|
public:
|
||||||
|
bool in_data; // parsing header (false) or data (true)
|
||||||
|
|
||||||
|
CDataStream hdrbuf; // partially received header
|
||||||
|
CMessageHeader hdr; // complete header
|
||||||
|
unsigned int nHdrPos;
|
||||||
|
|
||||||
|
CDataStream vRecv; // received message data
|
||||||
|
unsigned int nDataPos;
|
||||||
|
|
||||||
|
CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) {
|
||||||
|
hdrbuf.resize(24);
|
||||||
|
in_data = false;
|
||||||
|
nHdrPos = 0;
|
||||||
|
nDataPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool complete() const
|
||||||
|
{
|
||||||
|
if (!in_data)
|
||||||
|
return false;
|
||||||
|
return (hdr.nMessageSize == nDataPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVersion(int nVersionIn)
|
||||||
|
{
|
||||||
|
hdrbuf.SetVersion(nVersionIn);
|
||||||
|
vRecv.SetVersion(nVersionIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
int readHeader(const char *pch, unsigned int nBytes);
|
||||||
|
int readData(const char *pch, unsigned int nBytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Information about a peer */
|
/** Information about a peer */
|
||||||
class CNode
|
class CNode
|
||||||
@ -134,16 +173,21 @@ public:
|
|||||||
// socket
|
// socket
|
||||||
uint64 nServices;
|
uint64 nServices;
|
||||||
SOCKET hSocket;
|
SOCKET hSocket;
|
||||||
CDataStream vSend;
|
CDataStream ssSend;
|
||||||
CDataStream vRecv;
|
size_t nSendSize; // total size of all vSendMsg entries
|
||||||
|
size_t nSendOffset; // offset inside the first vSendMsg already sent
|
||||||
|
std::deque<CSerializeData> vSendMsg;
|
||||||
CCriticalSection cs_vSend;
|
CCriticalSection cs_vSend;
|
||||||
CCriticalSection cs_vRecv;
|
|
||||||
|
std::deque<CInv> vRecvGetData;
|
||||||
|
std::deque<CNetMessage> vRecvMsg;
|
||||||
|
CCriticalSection cs_vRecvMsg;
|
||||||
|
int nRecvVersion;
|
||||||
|
|
||||||
int64 nLastSend;
|
int64 nLastSend;
|
||||||
int64 nLastRecv;
|
int64 nLastRecv;
|
||||||
int64 nLastSendEmpty;
|
int64 nLastSendEmpty;
|
||||||
int64 nTimeConnected;
|
int64 nTimeConnected;
|
||||||
int nHeaderStart;
|
|
||||||
unsigned int nMessageStart;
|
|
||||||
CAddress addr;
|
CAddress addr;
|
||||||
std::string addrName;
|
std::string addrName;
|
||||||
CService addrLocal;
|
CService addrLocal;
|
||||||
@ -191,16 +235,15 @@ public:
|
|||||||
CCriticalSection cs_inventory;
|
CCriticalSection cs_inventory;
|
||||||
std::multimap<int64, CInv> mapAskFor;
|
std::multimap<int64, CInv> mapAskFor;
|
||||||
|
|
||||||
CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
|
CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, MIN_PROTO_VERSION)
|
||||||
{
|
{
|
||||||
nServices = 0;
|
nServices = 0;
|
||||||
hSocket = hSocketIn;
|
hSocket = hSocketIn;
|
||||||
|
nRecvVersion = MIN_PROTO_VERSION;
|
||||||
nLastSend = 0;
|
nLastSend = 0;
|
||||||
nLastRecv = 0;
|
nLastRecv = 0;
|
||||||
nLastSendEmpty = GetTime();
|
nLastSendEmpty = GetTime();
|
||||||
nTimeConnected = GetTime();
|
nTimeConnected = GetTime();
|
||||||
nHeaderStart = -1;
|
|
||||||
nMessageStart = -1;
|
|
||||||
addr = addrIn;
|
addr = addrIn;
|
||||||
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
|
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
|
||||||
nVersion = 0;
|
nVersion = 0;
|
||||||
@ -213,6 +256,8 @@ public:
|
|||||||
fDisconnect = false;
|
fDisconnect = false;
|
||||||
nRefCount = 0;
|
nRefCount = 0;
|
||||||
nReleaseTime = 0;
|
nReleaseTime = 0;
|
||||||
|
nSendSize = 0;
|
||||||
|
nSendOffset = 0;
|
||||||
hashContinue = 0;
|
hashContinue = 0;
|
||||||
pindexLastGetBlocksBegin = 0;
|
pindexLastGetBlocksBegin = 0;
|
||||||
hashLastGetBlocksEnd = 0;
|
hashLastGetBlocksEnd = 0;
|
||||||
@ -250,6 +295,26 @@ public:
|
|||||||
return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
|
return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// requires LOCK(cs_vRecvMsg)
|
||||||
|
unsigned int GetTotalRecvSize()
|
||||||
|
{
|
||||||
|
unsigned int total = 0;
|
||||||
|
BOOST_FOREACH(const CNetMessage &msg, vRecvMsg)
|
||||||
|
total += msg.vRecv.size() + 24;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires LOCK(cs_vRecvMsg)
|
||||||
|
bool ReceiveMsgBytes(const char *pch, unsigned int nBytes);
|
||||||
|
|
||||||
|
// requires LOCK(cs_vRecvMsg)
|
||||||
|
void SetRecvVersion(int nVersionIn)
|
||||||
|
{
|
||||||
|
nRecvVersion = nVersionIn;
|
||||||
|
BOOST_FOREACH(CNetMessage &msg, vRecvMsg)
|
||||||
|
msg.SetVersion(nVersionIn);
|
||||||
|
}
|
||||||
|
|
||||||
CNode* AddRef(int64 nTimeout=0)
|
CNode* AddRef(int64 nTimeout=0)
|
||||||
{
|
{
|
||||||
if (nTimeout != 0)
|
if (nTimeout != 0)
|
||||||
@ -324,11 +389,8 @@ public:
|
|||||||
void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
|
void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
|
||||||
{
|
{
|
||||||
ENTER_CRITICAL_SECTION(cs_vSend);
|
ENTER_CRITICAL_SECTION(cs_vSend);
|
||||||
if (nHeaderStart != -1)
|
assert(ssSend.size() == 0);
|
||||||
AbortMessage();
|
ssSend << CMessageHeader(pszCommand, 0);
|
||||||
nHeaderStart = vSend.size();
|
|
||||||
vSend << CMessageHeader(pszCommand, 0);
|
|
||||||
nMessageStart = vSend.size();
|
|
||||||
if (fDebug)
|
if (fDebug)
|
||||||
printf("sending: %s ", pszCommand);
|
printf("sending: %s ", pszCommand);
|
||||||
}
|
}
|
||||||
@ -336,11 +398,8 @@ public:
|
|||||||
// TODO: Document the precondition of this function. Is cs_vSend locked?
|
// TODO: Document the precondition of this function. Is cs_vSend locked?
|
||||||
void AbortMessage() UNLOCK_FUNCTION(cs_vSend)
|
void AbortMessage() UNLOCK_FUNCTION(cs_vSend)
|
||||||
{
|
{
|
||||||
if (nHeaderStart < 0)
|
ssSend.clear();
|
||||||
return;
|
|
||||||
vSend.resize(nHeaderStart);
|
|
||||||
nHeaderStart = -1;
|
|
||||||
nMessageStart = -1;
|
|
||||||
LEAVE_CRITICAL_SECTION(cs_vSend);
|
LEAVE_CRITICAL_SECTION(cs_vSend);
|
||||||
|
|
||||||
if (fDebug)
|
if (fDebug)
|
||||||
@ -357,26 +416,32 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nHeaderStart < 0)
|
if (ssSend.size() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Set the size
|
// Set the size
|
||||||
unsigned int nSize = vSend.size() - nMessageStart;
|
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
|
||||||
memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize));
|
memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize));
|
||||||
|
|
||||||
// Set the checksum
|
// Set the checksum
|
||||||
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
|
uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
|
||||||
unsigned int nChecksum = 0;
|
unsigned int nChecksum = 0;
|
||||||
memcpy(&nChecksum, &hash, sizeof(nChecksum));
|
memcpy(&nChecksum, &hash, sizeof(nChecksum));
|
||||||
assert(nMessageStart - nHeaderStart >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
|
assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
|
||||||
memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::CHECKSUM_OFFSET, &nChecksum, sizeof(nChecksum));
|
memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum));
|
||||||
|
|
||||||
if (fDebug) {
|
if (fDebug) {
|
||||||
printf("(%d bytes)\n", nSize);
|
printf("(%d bytes)\n", nSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
nHeaderStart = -1;
|
std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
|
||||||
nMessageStart = -1;
|
ssSend.GetAndClear(*it);
|
||||||
|
nSendSize += (*it).size();
|
||||||
|
|
||||||
|
// If write queue empty, attempt "optimistic write"
|
||||||
|
if (it == vSendMsg.begin())
|
||||||
|
SocketSendData(this);
|
||||||
|
|
||||||
LEAVE_CRITICAL_SECTION(cs_vSend);
|
LEAVE_CRITICAL_SECTION(cs_vSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +468,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1;
|
ssSend << a1;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -419,7 +484,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2;
|
ssSend << a1 << a2;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -435,7 +500,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2 << a3;
|
ssSend << a1 << a2 << a3;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -451,7 +516,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2 << a3 << a4;
|
ssSend << a1 << a2 << a3 << a4;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -467,7 +532,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2 << a3 << a4 << a5;
|
ssSend << a1 << a2 << a3 << a4 << a5;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -483,7 +548,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2 << a3 << a4 << a5 << a6;
|
ssSend << a1 << a2 << a3 << a4 << a5 << a6;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -499,7 +564,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
|
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -515,7 +580,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
|
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -531,7 +596,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
BeginMessage(pszCommand);
|
BeginMessage(pszCommand);
|
||||||
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
|
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
|
||||||
EndMessage();
|
EndMessage();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
@ -56,7 +56,8 @@ class CMessageHeader
|
|||||||
CHECKSUM_SIZE=sizeof(int),
|
CHECKSUM_SIZE=sizeof(int),
|
||||||
|
|
||||||
MESSAGE_SIZE_OFFSET=MESSAGE_START_SIZE+COMMAND_SIZE,
|
MESSAGE_SIZE_OFFSET=MESSAGE_START_SIZE+COMMAND_SIZE,
|
||||||
CHECKSUM_OFFSET=MESSAGE_SIZE_OFFSET+MESSAGE_SIZE_SIZE
|
CHECKSUM_OFFSET=MESSAGE_SIZE_OFFSET+MESSAGE_SIZE_SIZE,
|
||||||
|
HEADER_SIZE=MESSAGE_START_SIZE+COMMAND_SIZE+MESSAGE_SIZE_SIZE+CHECKSUM_SIZE
|
||||||
};
|
};
|
||||||
char pchMessageStart[MESSAGE_START_SIZE];
|
char pchMessageStart[MESSAGE_START_SIZE];
|
||||||
char pchCommand[COMMAND_SIZE];
|
char pchCommand[COMMAND_SIZE];
|
||||||
|
@ -789,6 +789,7 @@ struct ser_streamplaceholder
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
|
||||||
|
|
||||||
/** Double ended buffer combining vector and stream-like interfaces.
|
/** Double ended buffer combining vector and stream-like interfaces.
|
||||||
*
|
*
|
||||||
@ -798,7 +799,7 @@ struct ser_streamplaceholder
|
|||||||
class CDataStream
|
class CDataStream
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
typedef std::vector<char, zero_after_free_allocator<char> > vector_type;
|
typedef CSerializeData vector_type;
|
||||||
vector_type vch;
|
vector_type vch;
|
||||||
unsigned int nReadPos;
|
unsigned int nReadPos;
|
||||||
short state;
|
short state;
|
||||||
@ -1095,6 +1096,11 @@ public:
|
|||||||
::Unserialize(*this, obj, nType, nVersion);
|
::Unserialize(*this, obj, nType, nVersion);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetAndClear(CSerializeData &data) {
|
||||||
|
vch.swap(data);
|
||||||
|
CSerializeData().swap(vch);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user