AK: Add Endian.h header to replace NetworkOrdered.h.

This commit is contained in:
asynts 2020-08-25 15:11:15 +02:00 committed by Andreas Kling
parent ecf6cbbd02
commit 10c6f062b3
Notes: sideshowbarker 2024-07-19 03:10:52 +09:00
20 changed files with 195 additions and 106 deletions

114
AK/Endian.h Normal file
View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2020, the SerenityOS developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/Platform.h>
namespace AK {
template<typename T>
ALWAYS_INLINE T convert_between_host_and_little_endian(T value)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return value;
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
if constexpr (sizeof(T) == 8)
return __builtin_bswap64(value);
if constexpr (sizeof(T) == 4)
return __builtin_bswap32(value);
if constexpr (sizeof(T) == 2)
return __builtin_bswap16(value);
if constexpr (sizeof(T) == 1)
return value;
#endif
}
template<typename T>
ALWAYS_INLINE T convert_between_host_and_big_endian(T value)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
if constexpr (sizeof(T) == 8)
return __builtin_bswap64(value);
if constexpr (sizeof(T) == 4)
return __builtin_bswap32(value);
if constexpr (sizeof(T) == 2)
return __builtin_bswap16(value);
if constexpr (sizeof(T) == 1)
return value;
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return value;
#endif
}
template<typename T>
ALWAYS_INLINE T convert_between_host_and_network_endian(T value)
{
return convert_between_host_and_big_endian(value);
}
template<typename T>
class [[gnu::packed]] LittleEndian
{
public:
LittleEndian() { }
LittleEndian(T value)
: m_value(convert_between_host_and_little_endian(value))
{
}
operator T() const { return convert_between_host_and_little_endian(m_value); }
private:
T m_value { 0 };
};
template<typename T>
class [[gnu::packed]] BigEndian
{
public:
BigEndian() { }
BigEndian(T value)
: m_value(convert_between_host_and_big_endian(value))
{
}
operator T() const { return convert_between_host_and_big_endian(m_value); }
private:
T m_value { 0 };
};
template<typename T>
using NetworkOrdered = BigEndian<T>;
}
using AK::BigEndian;
using AK::LittleEndian;
using AK::NetworkOrdered;

View file

@ -26,8 +26,8 @@
#pragma once
#include <AK/Endian.h>
#include <AK/LogStream.h>
#include <AK/NetworkOrdered.h>
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/StringView.h>
@ -106,7 +106,6 @@ public:
return {};
}
if (a > 255 || b > 255 || c > 255 || d > 255)
return {};
return IPv4Address((u8)a, (u8)b, (u8)c, (u8)d);

View file

@ -1,46 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/Platform.h>
#include <AK/Types.h>
template<typename T>
class [[gnu::packed]] NetworkOrdered
{
public:
NetworkOrdered() {}
NetworkOrdered(const T& host_value)
: m_network_value(convert_between_host_and_network(host_value))
{
}
operator T() const { return convert_between_host_and_network(m_network_value); }
private:
T m_network_value { 0 };
};

View file

@ -37,17 +37,17 @@
#define ARCH(arch) (defined(AK_ARCH_##arch) && AK_ARCH_##arch)
#ifdef ALWAYS_INLINE
#undef ALWAYS_INLINE
# undef ALWAYS_INLINE
#endif
#define ALWAYS_INLINE [[gnu::always_inline]] inline
#ifdef NEVER_INLINE
#undef NEVER_INLINE
# undef NEVER_INLINE
#endif
#define NEVER_INLINE [[gnu::noinline]]
#ifdef FLATTEN
#undef FLATTEN
# undef FLATTEN
#endif
#define FLATTEN [[gnu::flatten]]
@ -71,33 +71,16 @@ inline int open_with_path_length(const char* path, size_t path_length, int optio
}
#endif
template<typename T>
ALWAYS_INLINE T convert_between_host_and_network(T value)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
if constexpr (sizeof(T) == 8)
return __builtin_bswap64(value);
if constexpr (sizeof(T) == 4)
return __builtin_bswap32(value);
if constexpr (sizeof(T) == 2)
return __builtin_bswap16(value);
if constexpr (sizeof(T) == 1)
return value;
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return value;
#endif
}
ALWAYS_INLINE int count_trailing_zeroes_32(unsigned int val)
{
#if defined(__GNUC__) || defined(__clang__)
return __builtin_ctz(val);
return __builtin_ctz(val);
#else
for (u8 i = 0; i < 32; ++i) {
if ((val >> i) & 1) {
return i;
}
for (u8 i = 0; i < 32; ++i) {
if ((val >> i) & 1) {
return i;
}
return 0;
}
return 0;
#endif
}

View file

@ -28,6 +28,7 @@
#include <AK/ByteBuffer.h>
#include <AK/Concepts.h>
#include <AK/Endian.h>
#include <AK/Forward.h>
#include <AK/MemMem.h>
#include <AK/Span.h>
@ -74,6 +75,35 @@ class DuplexStream
, public OutputStream {
};
template<typename T>
InputStream& operator>>(InputStream& stream, LittleEndian<T>& value)
{
T temporary;
stream >> temporary;
value = temporary;
return stream;
}
template<typename T>
InputStream& operator<<(InputStream& stream, LittleEndian<T> value)
{
stream << static_cast<T>(value);
return stream;
}
template<typename T>
InputStream& operator>>(InputStream& stream, BigEndian<T>& value)
{
T temporary;
stream >> temporary;
value = temporary;
return stream;
}
template<typename T>
InputStream& operator<<(InputStream& stream, BigEndian<T> value)
{
stream << static_cast<T>(value);
return stream;
}
#if defined(__cpp_concepts) && !defined(__COVERITY__)
template<Concepts::Integral Integral>
#else

View file

@ -26,8 +26,8 @@
#pragma once
#include <AK/Endian.h>
#include <AK/MACAddress.h>
#include <AK/NetworkOrdered.h>
#include <Kernel/Net/EtherType.h>
#include <Kernel/Net/IPv4.h>

View file

@ -26,16 +26,16 @@
#pragma once
#include <AK/Endian.h>
#include <AK/MACAddress.h>
#include <AK/NetworkOrdered.h>
#pragma GCC diagnostic ignored "-Warray-bounds"
class [[gnu::packed]] EthernetFrameHeader
{
public:
EthernetFrameHeader() {}
~EthernetFrameHeader() {}
EthernetFrameHeader() { }
~EthernetFrameHeader() { }
MACAddress destination() const { return m_destination; }
void set_destination(const MACAddress& address) { m_destination = address; }

View file

@ -27,8 +27,8 @@
#pragma once
#include <AK/Assertions.h>
#include <AK/Endian.h>
#include <AK/IPv4Address.h>
#include <AK/NetworkOrdered.h>
#include <AK/String.h>
#include <AK/Types.h>
@ -131,7 +131,7 @@ inline NetworkOrdered<u16> internet_checksum(const void* ptr, size_t count)
u32 checksum = 0;
auto* w = (const u16*)ptr;
while (count > 1) {
checksum += convert_between_host_and_network(*w++);
checksum += AK::convert_between_host_and_network_endian(*w++);
if (checksum & 0x80000000)
checksum = (checksum & 0xffff) | (checksum >> 16);
count -= 2;

View file

@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/Endian.h>
#include <AK/Types.h>
#include <LibCrypto/Hash/SHA1.h>
@ -39,7 +40,7 @@ inline void SHA1::transform(const u8* data)
{
u32 blocks[80];
for (size_t i = 0; i < 16; ++i)
blocks[i] = convert_between_host_and_network(((const u32*)data)[i]);
blocks[i] = AK::convert_between_host_and_network_endian(((const u32*)data)[i]);
// w[i] = (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) leftrotate 1
for (size_t i = 16; i < Rounds; ++i)

View file

@ -25,9 +25,9 @@
*/
#include "PBMLoader.h"
#include <AK/Endian.h>
#include <AK/LexicalPath.h>
#include <AK/MappedFile.h>
#include <AK/NetworkOrdered.h>
#include <AK/StringBuilder.h>
#include <string.h>

View file

@ -25,9 +25,9 @@
*/
#include "PGMLoader.h"
#include <AK/Endian.h>
#include <AK/LexicalPath.h>
#include <AK/MappedFile.h>
#include <AK/NetworkOrdered.h>
#include <AK/StringBuilder.h>
#include <string.h>

View file

@ -25,9 +25,9 @@
*/
#include <AK/ByteBuffer.h>
#include <AK/Endian.h>
#include <AK/LexicalPath.h>
#include <AK/MappedFile.h>
#include <AK/NetworkOrdered.h>
#include <LibCore/puff.h>
#include <LibGfx/PNGLoader.h>
#include <fcntl.h>

View file

@ -25,9 +25,9 @@
*/
#include "PPMLoader.h"
#include <AK/Endian.h>
#include <AK/LexicalPath.h>
#include <AK/MappedFile.h>
#include <AK/NetworkOrdered.h>
#include <AK/StringBuilder.h>
#include <string.h>

View file

@ -24,7 +24,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/Endian.h>
#include <AK/Random.h>
#include <LibCore/Timer.h>
#include <LibCrypto/ASN1/DER.h>
#include <LibCrypto/PK/Code/EMSA_PSS.h>
@ -70,7 +72,7 @@ ssize_t TLSv12::handle_hello(const ByteBuffer& buffer, WritePacketStage& write_p
dbg() << "not enough data for version";
return (i8)Error::NeedMoreData;
}
auto version = (Version)convert_between_host_and_network(*(const u16*)buffer.offset_pointer(res));
auto version = (Version)AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(res));
res += 2;
if (!supports_version(version))
@ -101,7 +103,7 @@ ssize_t TLSv12::handle_hello(const ByteBuffer& buffer, WritePacketStage& write_p
dbg() << "not enough data for cipher suite listing";
return (i8)Error::NeedMoreData;
}
auto cipher = (CipherSuite)convert_between_host_and_network(*(const u16*)buffer.offset_pointer(res));
auto cipher = (CipherSuite)AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(res));
res += 2;
if (!supports_cipher(cipher)) {
m_context.cipher = CipherSuite::Invalid;
@ -140,9 +142,9 @@ ssize_t TLSv12::handle_hello(const ByteBuffer& buffer, WritePacketStage& write_p
}
while ((ssize_t)buffer.size() - res >= 4) {
auto extension_type = (HandshakeExtension)convert_between_host_and_network(*(const u16*)buffer.offset_pointer(res));
auto extension_type = (HandshakeExtension)AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(res));
res += 2;
u16 extension_length = convert_between_host_and_network(*(const u16*)buffer.offset_pointer(res));
u16 extension_length = AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(res));
res += 2;
#ifdef TLS_DEBUG
@ -156,7 +158,7 @@ ssize_t TLSv12::handle_hello(const ByteBuffer& buffer, WritePacketStage& write_p
// SNI
if (extension_type == HandshakeExtension::ServerName) {
u16 sni_host_length = convert_between_host_and_network(*(const u16*)buffer.offset_pointer(res + 3));
u16 sni_host_length = AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(res + 3));
if (buffer.size() - res - 5 < sni_host_length) {
dbg() << "Not enough data for sni " << (buffer.size() - res - 5) << " < " << sni_host_length;
return (i8)Error::NeedMoreData;
@ -168,7 +170,7 @@ ssize_t TLSv12::handle_hello(const ByteBuffer& buffer, WritePacketStage& write_p
}
} else if (extension_type == HandshakeExtension::ApplicationLayerProtocolNegotiation && m_context.alpn.size()) {
if (buffer.size() - res > 2) {
auto alpn_length = convert_between_host_and_network(*(const u16*)buffer.offset_pointer(res));
auto alpn_length = AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(res));
if (alpn_length && alpn_length <= extension_length - 2) {
const u8* alpn = buffer.offset_pointer(res + 2);
size_t alpn_position = 0;
@ -267,7 +269,7 @@ void TLSv12::build_random(PacketBuilder& builder)
dbg() << "Server mode not supported";
return;
} else {
*(u16*)random_bytes = convert_between_host_and_network((u16)Version::V12);
*(u16*)random_bytes = AK::convert_between_host_and_network_endian((u16)Version::V12);
}
m_context.premaster_key = ByteBuffer::copy(random_bytes, bytes);

View file

@ -24,6 +24,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/Endian.h>
#include <LibCore/Timer.h>
#include <LibCrypto/ASN1/DER.h>
#include <LibCrypto/PK/Code/EMSA_PSS.h>
@ -56,7 +58,7 @@ void TLSv12::write_packet(ByteBuffer& packet)
void TLSv12::update_packet(ByteBuffer& packet)
{
u32 header_size = 5;
*(u16*)packet.offset_pointer(3) = convert_between_host_and_network((u16)(packet.size() - header_size));
*(u16*)packet.offset_pointer(3) = AK::convert_between_host_and_network_endian((u16)(packet.size() - header_size));
if (packet[0] != (u8)MessageType::ChangeCipher) {
if (packet[0] == (u8)MessageType::Handshake && packet.size() > header_size) {
@ -120,7 +122,7 @@ void TLSv12::update_packet(ByteBuffer& packet)
// store the correct ciphertext length into the packet
u16 ct_length = (u16)ct.size() - header_size;
*(u16*)ct.offset_pointer(header_size - 2) = convert_between_host_and_network(ct_length);
*(u16*)ct.offset_pointer(header_size - 2) = AK::convert_between_host_and_network_endian(ct_length);
// replace the packet with the ciphertext
packet = ct;
@ -137,7 +139,7 @@ void TLSv12::update_hash(const ByteBuffer& message)
ByteBuffer TLSv12::hmac_message(const ReadonlyBytes& buf, const Optional<ReadonlyBytes> buf2, size_t mac_length, bool local)
{
u64 sequence_number = convert_between_host_and_network(local ? m_context.local_sequence_number : m_context.remote_sequence_number);
u64 sequence_number = AK::convert_between_host_and_network_endian(local ? m_context.local_sequence_number : m_context.remote_sequence_number);
ensure_hmac(mac_length, local);
auto& hmac = local ? *m_hmac_local : *m_hmac_remote;
#ifdef TLS_DEBUG
@ -185,7 +187,7 @@ ssize_t TLSv12::handle_message(const ByteBuffer& buffer)
#endif
buffer_position += 2;
auto length = convert_between_host_and_network(*(const u16*)buffer.offset_pointer(buffer_position));
auto length = AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(buffer_position));
#ifdef TLS_DEBUG
dbg() << "record length: " << length << " at offset: " << buffer_position;
#endif
@ -238,7 +240,7 @@ ssize_t TLSv12::handle_message(const ByteBuffer& buffer)
const u8* message_hmac = decrypted_span.offset(length);
u8 temp_buf[5];
memcpy(temp_buf, buffer.offset_pointer(0), 3);
*(u16*)(temp_buf + 3) = convert_between_host_and_network(length);
*(u16*)(temp_buf + 3) = AK::convert_between_host_and_network_endian(length);
auto hmac = hmac_message({ temp_buf, 5 }, decrypted_span.slice(0, length), mac_size);
auto message_mac = ByteBuffer::wrap(const_cast<u8*>(message_hmac), mac_size);
if (hmac != message_mac) {

View file

@ -27,6 +27,7 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/Endian.h>
#include <AK/Types.h>
namespace TLS {
@ -57,12 +58,12 @@ public:
m_packet_data = ByteBuffer::create_uninitialized(size_hint + 16);
m_current_length = 5;
m_packet_data[0] = (u8)type;
*(u16*)m_packet_data.offset_pointer(1) = convert_between_host_and_network((u16)version);
*(u16*)m_packet_data.offset_pointer(1) = AK::convert_between_host_and_network_endian((u16)version);
}
inline void append(u16 value)
{
value = convert_between_host_and_network(value);
value = AK::convert_between_host_and_network_endian(value);
append((const u8*)&value, sizeof(value));
}
inline void append(u8 value)
@ -115,4 +116,5 @@ private:
ByteBuffer m_packet_data;
size_t m_current_length;
};
}

View file

@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/Endian.h>
#include <LibCore/DateTime.h>
#include <LibCore/Timer.h>
#include <LibCrypto/ASN1/DER.h>
@ -539,7 +540,7 @@ void TLSv12::consume(const ByteBuffer& record)
dbg() << "message buffer length " << buffer_length;
#endif
while (buffer_length >= 5) {
auto length = convert_between_host_and_network(*(u16*)m_context.message_buffer.offset_pointer(index + size_offset)) + header_size;
auto length = AK::convert_between_host_and_network_endian(*(u16*)m_context.message_buffer.offset_pointer(index + size_offset)) + header_size;
if (length > buffer_length) {
#ifdef TLS_DEBUG
dbg() << "Need more data: " << length << " | " << buffer_length;

View file

@ -28,10 +28,10 @@
#include <AK/Assertions.h>
#include <AK/ByteBuffer.h>
#include <AK/Endian.h>
#include <AK/HashMap.h>
#include <AK/IPv4Address.h>
#include <AK/MACAddress.h>
#include <AK/NetworkOrdered.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
#include <AK/Traits.h>
@ -126,14 +126,14 @@ enum class DHCPMessageType : u8 {
DHCPRelease,
};
template <>
template<>
struct AK::Traits<DHCPOption> : public AK::GenericTraits<DHCPOption> {
static constexpr bool is_trivial() { return true; }
static unsigned hash(DHCPOption u) { return int_hash((u8)u); }
};
struct ParsedDHCPv4Options {
template <typename T>
template<typename T>
Optional<const T> get(DHCPOption option_name) const
{
auto option = options.get(option_name);
@ -146,7 +146,7 @@ struct ParsedDHCPv4Options {
return *(const T*)value.value;
}
template <typename T>
template<typename T>
Vector<T> get_many(DHCPOption option_name, size_t max_number) const
{
Vector<T> values;

View file

@ -26,6 +26,7 @@
#include "DHCPv4Client.h"
#include <AK/ByteBuffer.h>
#include <AK/Endian.h>
#include <AK/Function.h>
#include <LibCore/SocketAddress.h>
#include <LibCore/Timer.h>
@ -163,7 +164,7 @@ void DHCPv4Client::handle_ack(const DHCPv4Packet& packet, const ParsedDHCPv4Opti
transaction->has_ip = true;
auto& interface = transaction->interface;
auto new_ip = packet.yiaddr();
auto lease_time = convert_between_host_and_network(options.get<u32>(DHCPOption::IPAddressLeaseTime).value_or(transaction->offered_lease_time));
auto lease_time = AK::convert_between_host_and_network_endian(options.get<u32>(DHCPOption::IPAddressLeaseTime).value_or(transaction->offered_lease_time));
// set a timer for the duration of the lease, we shall renew if needed
Core::Timer::create_single_shot(
lease_time * 1000,

View file

@ -26,7 +26,7 @@
#pragma once
#include <AK/NetworkOrdered.h>
#include <AK/Endian.h>
#include <AK/Types.h>
class [[gnu::packed]] DNSPacket