Merge #12916: Introduce BigEndian wrapper and use it for netaddress ports

ece88fd Introduce BigEndian wrapper and use it for netaddress ports (Pieter Wuille)

Pull request description:

  This is another small improvement taken from #10785.

  Instead of manually converting from/to BE format in the `CService` serializer, provide a generic way in serialize.h to serialize BE data (only 16 bits for now).

Tree-SHA512: bd67cf7eed465dad08551fb62f659e755e0691e4597a9f59d285d2b79975b50e5710d35a34a185b5ad232e1deda9a4946615f9132b1ed7d96ed8087f73ace66b
This commit is contained in:
Wladimir J. van der Laan 2018-04-11 14:23:04 +02:00
commit 7b6041d1a7
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
2 changed files with 50 additions and 8 deletions

View File

@ -141,7 +141,7 @@ class CSubNet
class CService : public CNetAddr
{
protected:
unsigned short port; // host order
uint16_t port; // host order
public:
CService();
@ -168,13 +168,7 @@ class CService : public CNetAddr
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(ip);
// TODO: introduce native support for BE serialization in serialize.h
unsigned short portN = htons(port);
READWRITE(Span<unsigned char>((unsigned char*)&portN, 2));
if (ser_action.ForRead()) {
port = ntohs(portN);
}
READWRITE(WrapBigEndian(port));
}
};

View File

@ -79,6 +79,11 @@ template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)
obj = htole16(obj);
s.write((char*)&obj, 2);
}
template<typename Stream> inline void ser_writedata16be(Stream &s, uint16_t obj)
{
obj = htobe16(obj);
s.write((char*)&obj, 2);
}
template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
{
obj = htole32(obj);
@ -101,6 +106,12 @@ template<typename Stream> inline uint16_t ser_readdata16(Stream &s)
s.read((char*)&obj, 2);
return le16toh(obj);
}
template<typename Stream> inline uint16_t ser_readdata16be(Stream &s)
{
uint16_t obj;
s.read((char*)&obj, 2);
return be16toh(obj);
}
template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
{
uint32_t obj;
@ -416,6 +427,40 @@ public:
}
};
/** Serialization wrapper class for big-endian integers.
*
* Use this wrapper around integer types that are stored in memory in native
* byte order, but serialized in big endian notation. This is only intended
* to implement serializers that are compatible with existing formats, and
* its use is not recommended for new data structures.
*
* Only 16-bit types are supported for now.
*/
template<typename I>
class BigEndian
{
protected:
I& m_val;
public:
explicit BigEndian(I& val) : m_val(val)
{
static_assert(std::is_unsigned<I>::value, "BigEndian type must be unsigned integer");
static_assert(sizeof(I) == 2 && std::numeric_limits<I>::min() == 0 && std::numeric_limits<I>::max() == std::numeric_limits<uint16_t>::max(), "Unsupported BigEndian size");
}
template<typename Stream>
void Serialize(Stream& s) const
{
ser_writedata16be(s, m_val);
}
template<typename Stream>
void Unserialize(Stream& s)
{
m_val = ser_readdata16be(s);
}
};
class CCompactSize
{
protected:
@ -466,6 +511,9 @@ public:
template<VarIntMode Mode=VarIntMode::DEFAULT, typename I>
CVarInt<Mode, I> WrapVarInt(I& n) { return CVarInt<Mode, I>{n}; }
template<typename I>
BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
/**
* Forward declarations
*/