Skip to content

Commit

Permalink
Fix byte order issue (big endian/little endian)
Browse files Browse the repository at this point in the history
  • Loading branch information
uchenily committed Jun 8, 2024
1 parent 9871a69 commit 458a38d
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 22 deletions.
4 changes: 2 additions & 2 deletions examples/tcp_channel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class Channel {
1024};
BufferedWriter buffered_writer_{io::OwnedWriteHalf<TcpStream>{nullptr},
1024};
// LengthDelimitedCodec<BufferedReader, BufferedWriter> codec_{};
FixedLength32Codec codec_;
LengthDelimitedCodec codec_{};
// FixedLength32Codec codec_;
};

} // namespace example
5 changes: 4 additions & 1 deletion examples/websocket_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ async def client():
async with websockets.connect('ws://localhost:8000') as channel:
for i in range(64):
# 发送消息
message = f"message {i} transmitted via websocket"
# message = f"message {i} transmitted via websocket"
# message = "a"*100000 # (payload len 64bits)
# message = "b"*1024 # (payload len 16bits)
message = "c"*64 # (payload len 7bits)
await channel.send(message)

# 接收消息
Expand Down
5 changes: 4 additions & 1 deletion uvio/codec/fixed_length.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "uvio/codec/base.hpp"
#include "uvio/net/endian.hpp"

namespace uvio::codec {
class FixedLength32Codec : public Codec<FixedLength32Codec> {
Expand Down Expand Up @@ -51,14 +52,16 @@ class FixedLength32Codec : public Codec<FixedLength32Codec> {
}
value |= static_cast<uint32_t>(bytes[0] & 0xFF) << (i * 8);
}
value = net::ntohl(value);
co_return value;
}

template <typename Writer>
auto encode_length(uint32_t value, Writer &writer) -> Task<Result<void>> {
std::array<char, 1> bytes{};
value = net::htonl(value);
for (int i = 0; i < fixed_length_bytes; ++i) {
bytes[0] = (value & 0xFF) | 0x00;
bytes[0] = static_cast<char>((value & 0xFF) | 0x00);
if (auto ret = co_await writer.write(bytes); !ret) {
co_return unexpected{ret.error()};
}
Expand Down
3 changes: 3 additions & 0 deletions uvio/codec/length_delimited.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "uvio/codec/base.hpp"
#include "uvio/net/endian.hpp"

namespace uvio::codec {
class LengthDelimitedCodec : public Codec<LengthDelimitedCodec> {
Expand Down Expand Up @@ -77,6 +78,7 @@ class LengthDelimitedCodec : public Codec<LengthDelimitedCodec> {
}
value |= static_cast<uint64_t>(bytes[0] & 0x7F) << (i * 7);
if ((bytes[0] & 0x80) == 0) {
value = net::ntohll(value);
co_return value;
}
}
Expand All @@ -87,6 +89,7 @@ class LengthDelimitedCodec : public Codec<LengthDelimitedCodec> {
auto encode_length(uint64_t value, Writer &writer) -> Task<Result<void>> {
// Encodes value in varint format and writes the result by writer
std::array<char, 1> bytes;
value = net::htonll(value);
do {
bytes[0] = (value & 0x7F) | (((value >> 7) == 0) ? 0x00 : 0x80);
if (auto ret = co_await writer.write(bytes); !ret) {
Expand Down
37 changes: 19 additions & 18 deletions uvio/codec/websocket.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "uvio/codec/base.hpp"
#include "uvio/net/endian.hpp"
#include "uvio/net/websocket/websocket_protocol.hpp"

namespace uvio::codec {
Expand All @@ -25,18 +26,20 @@ class WebsocketCodec : public Codec<WebsocketCodec> {
LOG_DEBUG("pre: {}", length);
if (length == 126) {
co_await reader.read_exact(buf);
length = buf[0] << 8 | buf[1];
length = buf[1] << 8 | buf[0];
length = net::ntohs(length);
} else if (length == 127) {
co_await reader.read_exact(
{reinterpret_cast<char *>(buf8.data()), buf8.size()});
length = static_cast<uint64_t>(buf[0])
length = static_cast<uint64_t>(buf8[0])
| static_cast<uint64_t>(buf8[1]) << 8
| static_cast<uint64_t>(buf8[2]) << 16
| static_cast<uint64_t>(buf8[3]) << 24
| static_cast<uint64_t>(buf8[4]) << 32
| static_cast<uint64_t>(buf8[5]) << 40
| static_cast<uint64_t>(buf8[6]) << 48
| static_cast<uint64_t>(buf8[7]) << 56;
length = net::ntohll(length);
}
LOG_DEBUG("payload length: {}", length);

Expand All @@ -62,26 +65,24 @@ class WebsocketCodec : public Codec<WebsocketCodec> {
auto length = frame.payload_length();
if (length < 126) {
buf[1] |= length;
co_await writer.write(
std::span<char, 2>{reinterpret_cast<char *>(buf.data()), 2});
co_await writer.write({reinterpret_cast<char *>(buf.data()), 2});
} else if (length < 65536) {
length = net::htons(length);
buf[1] |= 126;
buf[2] = length | 0xFF;
buf[3] = (length >> 8) | 0xFF;
buf[4] = (length >> 16) | 0xFF;
buf[5] = (length >> 24) | 0xFF;
co_await writer.write(
std::span<char, 6>{reinterpret_cast<char *>(buf.data()), 6});
buf[2] = (length >> 0) & 0xFF;
buf[3] = (length >> 8) & 0xFF;
co_await writer.write({reinterpret_cast<char *>(buf.data()), 4});
} else {
length = net::htonll(length);
buf[1] |= 127;
buf[2] = length | 0xFF;
buf[3] = (length >> 8) | 0xFF;
buf[4] = (length >> 16) | 0xFF;
buf[5] = (length >> 24) | 0xFF;
buf[6] = (length >> 32) | 0xFF;
buf[7] = (length >> 40) | 0xFF;
buf[8] = (length >> 48) | 0xFF;
buf[9] = (length >> 56) | 0xFF;
buf[2] = (length >> 0) & 0xFF;
buf[3] = (length >> 8) & 0xFF;
buf[4] = (length >> 16) & 0xFF;
buf[5] = (length >> 24) & 0xFF;
buf[6] = (length >> 32) & 0xFF;
buf[7] = (length >> 40) & 0xFF;
buf[8] = (length >> 48) & 0xFF;
buf[9] = (length >> 56) & 0xFF;
co_await writer.write(
{reinterpret_cast<char *>(buf.data()), buf.size()});
}
Expand Down
49 changes: 49 additions & 0 deletions uvio/net/endian.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include <string>

namespace uvio::net {

#if __BYTE_ORDER == __LITTLE_ENDIAN
static inline auto htonll(uint64_t x) -> uint64_t {
return __bswap_64(x);
}
static inline auto ntohll(uint64_t x) -> uint64_t {
return __bswap_64(x);
}
static inline auto htonl(uint32_t x) -> uint32_t {
return __bswap_32(x);
}
static inline auto ntohl(uint32_t x) -> uint32_t {
return __bswap_32(x);
}
static inline auto htons(uint16_t x) -> uint16_t {
return __bswap_16(x);
}
static inline auto ntohs(uint16_t x) -> uint16_t {
return __bswap_16(x);
}
#elif __BYTE_ORDER == __BIG_ENDIAN
static inline auto htonll(uint64_t x) -> uint64_t {
return x;
}
static inline auto ntohll(uint64_t x) -> uint64_t {
return x;
}
static inline auto htonl(uint32_t x) -> uint32_t {
return x;
}
static inline auto ntohl(uint32_t x) -> uint32_t {
return x;
}
static inline auto htons(uint16_t x) -> uint16_t {
return x;
}
static inline auto ntohs(uint16_t x) -> uint16_t {
return x;
}
#else
#error "__BYTE_ORDER not defined!"
#endif

} // namespace uvio::net

0 comments on commit 458a38d

Please sign in to comment.