Skip to content

Commit ece88fd

Browse files
committed
Introduce BigEndian wrapper and use it for netaddress ports
1 parent 9778586 commit ece88fd

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

src/netaddress.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class CSubNet
141141
class CService : public CNetAddr
142142
{
143143
protected:
144-
unsigned short port; // host order
144+
uint16_t port; // host order
145145

146146
public:
147147
CService();
@@ -168,13 +168,7 @@ class CService : public CNetAddr
168168
template <typename Stream, typename Operation>
169169
inline void SerializationOp(Stream& s, Operation ser_action) {
170170
READWRITE(ip);
171-
172-
// TODO: introduce native support for BE serialization in serialize.h
173-
unsigned short portN = htons(port);
174-
READWRITE(Span<unsigned char>((unsigned char*)&portN, 2));
175-
if (ser_action.ForRead()) {
176-
port = ntohs(portN);
177-
}
171+
READWRITE(WrapBigEndian(port));
178172
}
179173
};
180174

src/serialize.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)
7979
obj = htole16(obj);
8080
s.write((char*)&obj, 2);
8181
}
82+
template<typename Stream> inline void ser_writedata16be(Stream &s, uint16_t obj)
83+
{
84+
obj = htobe16(obj);
85+
s.write((char*)&obj, 2);
86+
}
8287
template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
8388
{
8489
obj = htole32(obj);
@@ -101,6 +106,12 @@ template<typename Stream> inline uint16_t ser_readdata16(Stream &s)
101106
s.read((char*)&obj, 2);
102107
return le16toh(obj);
103108
}
109+
template<typename Stream> inline uint16_t ser_readdata16be(Stream &s)
110+
{
111+
uint16_t obj;
112+
s.read((char*)&obj, 2);
113+
return be16toh(obj);
114+
}
104115
template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
105116
{
106117
uint32_t obj;
@@ -411,6 +422,40 @@ class CVarInt
411422
}
412423
};
413424

425+
/** Serialization wrapper class for big-endian integers.
426+
*
427+
* Use this wrapper around integer types that are stored in memory in native
428+
* byte order, but serialized in big endian notation. This is only intended
429+
* to implement serializers that are compatible with existing formats, and
430+
* its use is not recommended for new data structures.
431+
*
432+
* Only 16-bit types are supported for now.
433+
*/
434+
template<typename I>
435+
class BigEndian
436+
{
437+
protected:
438+
I& m_val;
439+
public:
440+
explicit BigEndian(I& val) : m_val(val)
441+
{
442+
static_assert(std::is_unsigned<I>::value, "BigEndian type must be unsigned integer");
443+
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");
444+
}
445+
446+
template<typename Stream>
447+
void Serialize(Stream& s) const
448+
{
449+
ser_writedata16be(s, m_val);
450+
}
451+
452+
template<typename Stream>
453+
void Unserialize(Stream& s)
454+
{
455+
m_val = ser_readdata16be(s);
456+
}
457+
};
458+
414459
class CCompactSize
415460
{
416461
protected:
@@ -461,6 +506,9 @@ class LimitedString
461506
template<VarIntMode Mode=VarIntMode::DEFAULT, typename I>
462507
CVarInt<Mode, I> WrapVarInt(I& n) { return CVarInt<Mode, I>{n}; }
463508

509+
template<typename I>
510+
BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
511+
464512
/**
465513
* Forward declarations
466514
*/

0 commit comments

Comments
 (0)