Skip to content

Commit b79e416

Browse files
theuniFuzzbawls
authored andcommitted
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 63c51d3 commit b79e416

File tree

6 files changed

+195
-0
lines changed

6 files changed

+195
-0
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ BITCOIN_CORE_H = \
212212
net.h \
213213
netaddress.h \
214214
netbase.h \
215+
netmessagemaker.h \
215216
noui.h \
216217
policy/fees.h \
217218
policy/policy.h \

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ BITCOIN_TESTS =\
8888
test/sigopcount_tests.cpp \
8989
test/skiplist_tests.cpp \
9090
test/sync_tests.cpp \
91+
test/streams_tests.cpp \
9192
test/timedata_tests.cpp \
9293
test/torcontrol_tests.cpp \
9394
test/transaction_tests.cpp \

src/net.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,20 @@ class CTransaction;
106106
class CNodeStats;
107107
class CClientUIInterface;
108108

109+
struct CSerializedNetMsg
110+
{
111+
CSerializedNetMsg() = default;
112+
CSerializedNetMsg(CSerializedNetMsg&&) = default;
113+
CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;
114+
// No copying, only moves.
115+
CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;
116+
CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
117+
118+
std::vector<unsigned char> data;
119+
std::string command;
120+
};
121+
122+
109123
class CConnman
110124
{
111125
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
@@ -296,6 +296,75 @@ class CBaseDataStream
296296
}
297297
};
298298

299+
/* Minimal stream for overwriting and/or appending to an existing byte vector
300+
*
301+
* The referenced vector will grow as necessary
302+
*/
303+
class CVectorWriter
304+
{
305+
public:
306+
307+
/*
308+
* @param[in] nTypeIn Serialization Type
309+
* @param[in] nVersionIn Serialization Version (including any flags)
310+
* @param[in] vchDataIn Referenced byte vector to overwrite/append
311+
* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
312+
* grow as necessary to max(index, vec.size()). So to append, use vec.size().
313+
*/
314+
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
315+
{
316+
if(nPos > vchData.size())
317+
vchData.resize(nPos);
318+
}
319+
/*
320+
* (other params same as above)
321+
* @param[in] args A list of items to serialize starting at nPos.
322+
*/
323+
template <typename... Args>
324+
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
325+
{
326+
::SerializeMany(*this, std::forward<Args>(args)...);
327+
}
328+
void write(const char* pch, size_t nSize)
329+
{
330+
assert(nPos <= vchData.size());
331+
size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
332+
if (nOverwrite) {
333+
memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
334+
}
335+
if (nOverwrite < nSize) {
336+
vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
337+
}
338+
nPos += nSize;
339+
}
340+
template<typename T>
341+
CVectorWriter& operator<<(const T& obj)
342+
{
343+
// Serialize to this stream
344+
::Serialize(*this, obj);
345+
return (*this);
346+
}
347+
int GetVersion() const
348+
{
349+
return nVersion;
350+
}
351+
int GetType() const
352+
{
353+
return nType;
354+
}
355+
void seek(size_t nSize)
356+
{
357+
nPos += nSize;
358+
if(nPos > vchData.size())
359+
vchData.resize(nPos);
360+
}
361+
private:
362+
const int nType;
363+
const int nVersion;
364+
std::vector<unsigned char>& vchData;
365+
size_t nPos;
366+
};
367+
299368
class CDataStream : public CBaseDataStream<CSerializeData>
300369
{
301370
public:

src/test/streams_tests.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright (c) 2012-2015 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include "streams.h"
6+
#include "test/test_pivx.h"
7+
8+
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
9+
#include <boost/assert.hpp>
10+
#include <boost/test/unit_test.hpp>
11+
12+
using namespace boost::assign; // bring 'operator+=()' into scope
13+
14+
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
15+
16+
BOOST_AUTO_TEST_CASE(streams_vector_writer)
17+
{
18+
unsigned char a(1);
19+
unsigned char b(2);
20+
unsigned char bytes[] = { 3, 4, 5, 6 };
21+
std::vector<unsigned char> vch;
22+
23+
// Each test runs twice. Serializing a second time at the same starting
24+
// point should yield the same results, even if the first test grew the
25+
// vector.
26+
27+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
28+
BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
29+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
30+
BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
31+
vch.clear();
32+
33+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
34+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
35+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
36+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
37+
vch.clear();
38+
39+
vch.resize(5, 0);
40+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
41+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 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+
vch.clear();
45+
46+
vch.resize(4, 0);
47+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
48+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
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+
vch.clear();
52+
53+
vch.resize(4, 0);
54+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
55+
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
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+
vch.clear();
59+
60+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
61+
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
62+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
63+
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
64+
vch.clear();
65+
66+
vch.resize(4, 8);
67+
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
68+
BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
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+
vch.clear();
72+
}
73+
74+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)