net: add CVectorWriter and CNetMsgMaker
CVectorWriter is useful for overwriting or appending an existing byte vector. CNetMsgMaker is a shortcut for creating messages on-the-fly which are suitable for pushing to CConnman.
This commit is contained in:
parent
b7695c2275
commit
2ec935dcaa
5 changed files with 178 additions and 0 deletions
|
@ -111,6 +111,7 @@ BITCOIN_CORE_H = \
|
|||
net.h \
|
||||
netaddress.h \
|
||||
netbase.h \
|
||||
netmessagemaker.h \
|
||||
noui.h \
|
||||
policy/fees.h \
|
||||
policy/policy.h \
|
||||
|
|
14
src/net.h
14
src/net.h
|
@ -101,6 +101,20 @@ class CTransaction;
|
|||
class CNodeStats;
|
||||
class CClientUIInterface;
|
||||
|
||||
struct CSerializedNetMsg
|
||||
{
|
||||
CSerializedNetMsg() = default;
|
||||
CSerializedNetMsg(CSerializedNetMsg&&) = default;
|
||||
CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;
|
||||
// No copying, only moves.
|
||||
CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;
|
||||
CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
|
||||
|
||||
std::vector<unsigned char> data;
|
||||
std::string command;
|
||||
};
|
||||
|
||||
|
||||
class CConnman
|
||||
{
|
||||
public:
|
||||
|
|
36
src/netmessagemaker.h
Normal file
36
src/netmessagemaker.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2016 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_NETMESSAGEMAKER_H
|
||||
#define BITCOIN_NETMESSAGEMAKER_H
|
||||
|
||||
#include "net.h"
|
||||
#include "serialize.h"
|
||||
|
||||
class CNetMsgMaker
|
||||
{
|
||||
public:
|
||||
CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
|
||||
|
||||
template <typename... Args>
|
||||
CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args)
|
||||
{
|
||||
CSerializedNetMsg msg;
|
||||
msg.command = std::move(sCommand);
|
||||
CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
|
||||
return msg;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
CSerializedNetMsg Make(std::string sCommand, Args&&... args)
|
||||
{
|
||||
return Make(0, std::move(sCommand), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
const int nVersion;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_NETMESSAGEMAKER_H
|
|
@ -69,6 +69,75 @@ OverrideStream<S> WithOrVersion(S* s, int nVersionFlag)
|
|||
return OverrideStream<S>(s, s->GetType(), s->GetVersion() | nVersionFlag);
|
||||
}
|
||||
|
||||
/* Minimal stream for overwriting and/or appending to an existing byte vector
|
||||
*
|
||||
* The referenced vector will grow as necessary
|
||||
*/
|
||||
class CVectorWriter
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* @param[in] nTypeIn Serialization Type
|
||||
* @param[in] nVersionIn Serialization Version (including any flags)
|
||||
* @param[in] vchDataIn Referenced byte vector to overwrite/append
|
||||
* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
|
||||
* grow as necessary to max(index, vec.size()). So to append, use vec.size().
|
||||
*/
|
||||
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
|
||||
{
|
||||
if(nPos > vchData.size())
|
||||
vchData.resize(nPos);
|
||||
}
|
||||
/*
|
||||
* (other params same as above)
|
||||
* @param[in] args A list of items to serialize starting at nPos.
|
||||
*/
|
||||
template <typename... Args>
|
||||
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
|
||||
{
|
||||
::SerializeMany(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
void write(const char* pch, size_t nSize)
|
||||
{
|
||||
assert(nPos <= vchData.size());
|
||||
size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
|
||||
if (nOverwrite) {
|
||||
memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
|
||||
}
|
||||
if (nOverwrite < nSize) {
|
||||
vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
|
||||
}
|
||||
nPos += nSize;
|
||||
}
|
||||
template<typename T>
|
||||
CVectorWriter& operator<<(const T& obj)
|
||||
{
|
||||
// Serialize to this stream
|
||||
::Serialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
int GetVersion() const
|
||||
{
|
||||
return nVersion;
|
||||
}
|
||||
int GetType() const
|
||||
{
|
||||
return nType;
|
||||
}
|
||||
void seek(size_t nSize)
|
||||
{
|
||||
nPos += nSize;
|
||||
if(nPos > vchData.size())
|
||||
vchData.resize(nPos);
|
||||
}
|
||||
private:
|
||||
const int nType;
|
||||
const int nVersion;
|
||||
std::vector<unsigned char>& vchData;
|
||||
size_t nPos;
|
||||
};
|
||||
|
||||
/** Double ended buffer combining vector and stream-like interfaces.
|
||||
*
|
||||
* >> and << read and write unformatted data using the above serialization templates.
|
||||
|
|
|
@ -15,6 +15,64 @@ using namespace boost::assign; // bring 'operator+=()' into scope
|
|||
|
||||
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(streams_vector_writer)
|
||||
{
|
||||
unsigned char a(1);
|
||||
unsigned char b(2);
|
||||
unsigned char bytes[] = { 3, 4, 5, 6 };
|
||||
std::vector<unsigned char> vch;
|
||||
|
||||
// Each test runs twice. Serializing a second time at the same starting
|
||||
// point should yield the same results, even if the first test grew the
|
||||
// vector.
|
||||
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
|
||||
vch.clear();
|
||||
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
|
||||
vch.clear();
|
||||
|
||||
vch.resize(5, 0);
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
|
||||
vch.clear();
|
||||
|
||||
vch.resize(4, 0);
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
|
||||
vch.clear();
|
||||
|
||||
vch.resize(4, 0);
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
|
||||
vch.clear();
|
||||
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
|
||||
vch.clear();
|
||||
|
||||
vch.resize(4, 8);
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
|
||||
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
|
||||
BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
|
||||
vch.clear();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
|
||||
{
|
||||
std::vector<char> in;
|
||||
|
|
Loading…
Reference in a new issue