diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2018-04-11 14:23:04 +0200 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2018-04-11 14:23:58 +0200 |
commit | 7b6041d1a70cc160ab081adf666f77346420fbd7 (patch) | |
tree | edb2bd4018bfe4696b9b6fbe8d4a600cbb733127 | |
parent | 807d2ac1867cc0b8c3ada4203b61fa29f6035318 (diff) | |
parent | ece88fd26995350dfaa4675b4291605a20203527 (diff) |
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
-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 57e434faf1..e54c7483d2 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; @@ -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 */ |