#include <array>
#include <cstdint>
#include <type_traits>
#include <vector>
#include <arpa/inet.h>
uint8_t NetworkToHost(uint8_t inValue) { return inValue; }
uint16_t NetworkToHost(uint16_t inValue) { return ntohs(inValue); }
uint32_t NetworkToHost(uint32_t inValue) { return ntohl(inValue); }
uint8_t HostToNetwork(uint8_t inValue) { return inValue; }
uint16_t HostToNetwork(uint16_t inValue) { return htons(inValue); }
uint32_t HostToNetwork(uint32_t inValue) { return htonl(inValue); }
/**
* @brief The NetEncoded class wraps a network-encoded value.
* Can be constructed from a host-encoded value using the "NetEncode" factory function.
* This class meets pod requirements and can be used to represent fields in packet headers.
*/
template<typename T>
class NetEncoded
{
public:
T hostValue() const
{
return NetworkToHost(_value);
}
T netValue() const
{
return _value;
}
friend bool operator<(const NetEncoded & lhs, const NetEncoded & rhs)
{
return lhs._value < rhs._value;
}
friend bool operator==(const NetEncoded & lhs, const NetEncoded & rhs)
{
return lhs._value == rhs._value;
}
friend bool operator!=(const NetEncoded & lhs, const NetEncoded & rhs)
{
return lhs._value != rhs._value;
}
T _value;
};
/**
* @brief Net16 holds a 16-bit network-encoded value.
*/
typedef NetEncoded<uint16_t> Net16;
static_assert(std::is_pod<Net16>::value, "Net16 is not a pod!");
static_assert(sizeof(Net16) == sizeof(uint16_t), "Net16 does not have correct size!");
/**
* @brief Net32 holds a 32-bit network-encoded value.
*/
typedef NetEncoded<uint32_t> Net32;
/**
* @brief NetEncode overload for creating Net16 from uint16_t
*/
inline Net16 NetEncode(uint16_t value)
{
return { HostToNetwork(value) };
}
/**
* @brief NetEncode overload for creating Net32 from uint32_t
*/
inline Net32 NetEncode(uint32_t value)
{
return { HostToNetwork(value) };
}
/**
* @brief NetEncode overload for creating Net16 from a 2-byte object.
* @param An 16-bit object with host-encoding that is explictly convertible to uint16_t.
*/
template<typename T>
inline Net16 NetEncode(T inValue, typename std::enable_if<sizeof(T) == sizeof(uint16_t)>::type * = 0)
{
return NetEncode(static_cast<uint16_t>(inValue));
}
/**
* @brief NetEncode overload for creating Net32 from a 4-byte object.
* @param An 32-bit object with host-encoding that is explictly convertible to uint32_t.
*/
template<typename T>
inline Net32 NetEncode(T inValue, typename std::enable_if<sizeof(T) == sizeof(uint32_t)>::type * = 0)
{
return NetEncode(static_cast<uint32_t>(inValue));
}
enum class EtherType : uint16_t
{
ARP = 0x0806,
IPv4 = 0x0800,
VLAN = 0x8100,
IPv6 = 0x86DD
};
typedef std::array<uint8_t, 6> MACAddress;
struct EthernetHeader
{
MACAddress destination;
MACAddress source;
Net16 etherType;
};
template<typename T>
inline const T & Decode(const uint8_t * bytes)
{
// TODO: Fix potential strict-aliasing problems.
return *reinterpret_cast<const T *>(bytes);
}
int main()
{
std::vector<uint8_t> data(30);
auto ethernetHeader = Decode<EthernetHeader>(data.data());
auto etherType = static_cast<EtherType>(ethernetHeader.etherType.hostValue());
}