Skip to content

Commit 2ec935d

Browse files
committed
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.
1 parent b7695c2 commit 2ec935d

File tree

5 files changed

+178
-0
lines changed

5 files changed

+178
-0
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ BITCOIN_CORE_H = \
111111
net.h \
112112
netaddress.h \
113113
netbase.h \
114+
netmessagemaker.h \
114115
noui.h \
115116
policy/fees.h \
116117
policy/policy.h \

src/net.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,20 @@ class CTransaction;
101101
class CNodeStats;
102102
class CClientUIInterface;
103103

104+
struct CSerializedNetMsg
105+
{
106+
CSerializedNetMsg() = default;
107+
CSerializedNetMsg(CSerializedNetMsg&&) = default;
108+
CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;
109+
// No copying, only moves.
110+
CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;
111+
CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
112+
113+
std::vector<unsigned char> data;
114+
std::string command;
115+
};
116+
117+
104118
class CConnman
105119
{
106120
public:

src/netmessagemaker.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2016 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#ifndef BITCOIN_NETMESSAGEMAKER_H
7+
#define BITCOIN_NETMESSAGEMAKER_H
8+
9+
#include "net.h"
10+
#include "serialize.h"
11+
12+
class CNetMsgMaker
13+
{
14+
public:
15+
CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
16+
17+
template <typename... Args>
18+
CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args)
19+
{
20+
CSerializedNetMsg msg;
21+
msg.command = std::move(sCommand);
22+
CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
23+
return msg;
24+
}
25+
26+
template <typename... Args>
27+
CSerializedNetMsg Make(std::string sCommand, Args&&... args)
28+
{
29+
return Make(0, std::move(sCommand), std::forward<Args>(args)...);
30+
}
31+
32+
private:
33+
const int nVersion;
34+
};
35+
36+
#endif // BITCOIN_NETMESSAGEMAKER_H

src/streams.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,75 @@ OverrideStream<S> WithOrVersion(S* s, int nVersionFlag)
6969
return OverrideStream<S>(s, s->GetType(), s->GetVersion() | nVersionFlag);
7070
}
7171

72+
/* Minimal stream for overwriting and/or appending to an existing byte vector
73+
*
74+
* The referenced vector will grow as necessary
75+
*/
76+
class CVectorWriter
77+
{
78+
public:
79+
80+
/*
81+
* @param[in] nTypeIn Serialization Type
82+
* @param[in] nVersionIn Serialization Version (including any flags)
83+
* @param[in] vchDataIn Referenced byte vector to overwrite/append
84+
* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
85+
* grow as necessary to max(index, vec.size()). So to append, use vec.size().
86+
*/
87+
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
88+
{
89+
if(nPos > vchData.size())
90+
vchData.resize(nPos);
91+
}
92+
/*
93+
* (other params same as above)
94+
* @param[in] args A list of items to serialize starting at nPos.
95+
*/
96+
template <typename... Args>
97+
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
98+
{
99+
::SerializeMany(*this, std::forward<Args>(args)...);
100+
}
101+
void write(const char* pch, size_t nSize)
102+
{
103+
assert(nPos <= vchData.size());
104+
size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
105+
if (nOverwrite) {
106+
memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
107+
}
108+
if (nOverwrite < nSize) {
109+
vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
110+
}
111+
nPos += nSize;
112+
}
113+
template<typename T>
114+
CVectorWriter& operator<<(const T& obj)
115+
{
116+
// Serialize to this stream
117+
::Serialize(*this, obj);
118+
return (*this);
119+
}
120+
int GetVersion() const
121+
{
122+
return nVersion;
123+
}
124+
int GetType() const
125+
{
126+
return nType;
127+
}
128+
void seek(size_t nSize)
129+
{
130+
nPos += nSize;
131+
if(nPos > vchData.size())
132+
vchData.resize(nPos);
133+
}
134+
private:
135+
const int nType;
136+
const int nVersion;
137+
std::vector<unsigned char>& vchData;
138+
size_t nPos;
139+
};
140+
72141
/** Double ended buffer combining vector and stream-like interfaces.
73142
*
74143
* >> and << read and write unformatted data using the above serialization templates.

src/test/streams_tests.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,64 @@ using namespace boost::assign; // bring 'operator+=()' into scope
1515

1616
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
1717

18+
BOOST_AUTO_TEST_CASE(streams_vector_writer)
19+
{
20+
unsigned char a(1);
21+
unsigned char b(2);
22+
unsigned char bytes[] = { 3, 4, 5, 6 };
23+
std::vector<unsigned char> vch;
24+
25+
// Each test runs twice. Serializing a second time at the same starting
26+
// point should yield the same results, even if the first test grew the
27+
// vector.
28+
29+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
30+
BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
31+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
32+
BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
33+
vch.clear();
34+
35+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
36+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
37+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
38+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
39+
vch.clear();
40+
41+
vch.resize(5, 0);
42+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
43+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
44+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
45+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
46+
vch.clear();
47+
48+
vch.resize(4, 0);
49+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
50+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
51+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
52+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
53+
vch.clear();
54+
55+
vch.resize(4, 0);
56+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
57+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
58+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
59+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
60+
vch.clear();
61+
62+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
63+
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
64+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
65+
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
66+
vch.clear();
67+
68+
vch.resize(4, 8);
69+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
70+
BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
71+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
72+
BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
73+
vch.clear();
74+
}
75+
1876
BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
1977
{
2078
std::vector<char> in;

0 commit comments

Comments
 (0)