diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2018-04-08 09:39:05 -0700 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2018-04-08 15:31:01 -0700 |
commit | ece88fd26995350dfaa4675b4291605a20203527 (patch) | |
tree | 580a594a66289796f73812d5a5f98c5a0d8d4476 | |
parent | 97785863e2faa4a6d4e1130e300011985df0858c (diff) |
Introduce BigEndian wrapper and use it for netaddress ports
-rw-r--r-- | src/netaddress.h | 10 | ||||
-rw-r--r-- | src/serialize.h | 48 |
2 files changed, 50 insertions, 8 deletions
diff --git a/src/netaddress.h b/src/netaddress.h index b3d1407f72..38f8709257 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -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)); } }; diff --git a/src/serialize.h b/src/serialize.h index e90b041cc2..2491879c36 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -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; @@ -411,6 +422,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: @@ -461,6 +506,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 */ |