blob: 9c119fcabdf336cc163662828f674796583381c4 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "udp_serde.h"
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <gtest/gtest.h>
namespace {
constexpr uint16_t kPort = 80;
constexpr size_t kIPv4AddrLen = 4;
constexpr size_t kIPv6AddrLen = 16;
constexpr fidl::Array<uint8_t, kIPv4AddrLen> kIPv4Addr = {0x1, 0x2, 0x3, 0x4};
constexpr fidl::Array<uint8_t, kIPv6AddrLen> kIPv6Addr = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
} // namespace
class AddrKind {
public:
enum class Kind {
V4,
V6,
};
explicit AddrKind(enum Kind kind) : kind(kind) {}
enum Kind Kind() const { return kind; }
constexpr const char* AddrKindToString() const {
switch (kind) {
case Kind::V4:
return "V4";
case Kind::V6:
return "V6";
}
}
size_t AddrLen() const {
switch (kind) {
case Kind::V4:
return kIPv4AddrLen;
case Kind::V6:
return kIPv6AddrLen;
}
}
private:
enum Kind kind;
};
class UdpSerdeTest : public ::testing::TestWithParam<AddrKind> {};
TEST_P(UdpSerdeTest, SendSerializeThenDeserialize) {
fidl::Arena alloc;
fidl::WireTableBuilder<fuchsia_posix_socket::wire::SendMsgMeta> meta_builder =
fuchsia_posix_socket::wire::SendMsgMeta::Builder(alloc);
fuchsia_net::wire::SocketAddress socket_addr;
IpAddrType expected_addr_type;
const uint8_t* expected_addr;
switch (GetParam().Kind()) {
case AddrKind::Kind::V4: {
fuchsia_net::wire::Ipv4Address ipv4_addr;
ipv4_addr.addr = kIPv4Addr;
fuchsia_net::wire::Ipv4SocketAddress ipv4_socket_addr;
ipv4_socket_addr.address = ipv4_addr;
ipv4_socket_addr.port = kPort;
socket_addr = fuchsia_net::wire::SocketAddress::WithIpv4(alloc, ipv4_socket_addr);
expected_addr_type = IpAddrType::Ipv4;
expected_addr = kIPv4Addr.begin();
} break;
case AddrKind::Kind::V6: {
fuchsia_net::wire::Ipv6Address ipv6_addr;
ipv6_addr.addr = kIPv6Addr;
fuchsia_net::wire::Ipv6SocketAddress ipv6_socket_addr;
ipv6_socket_addr.address = ipv6_addr;
ipv6_socket_addr.port = kPort;
socket_addr = fuchsia_net::wire::SocketAddress::WithIpv6(alloc, ipv6_socket_addr);
expected_addr_type = IpAddrType::Ipv6;
expected_addr = kIPv6Addr.begin();
}
}
meta_builder.to(socket_addr);
uint8_t kBuf[kTxUdpPreludeSize];
fuchsia_posix_socket::wire::SendMsgMeta meta = meta_builder.Build();
ASSERT_TRUE(serialize_send_msg_meta(meta, cpp20::span<uint8_t>(kBuf, kTxUdpPreludeSize)));
Buffer in_buf = Buffer{
.buf = kBuf,
.buf_size = kTxUdpPreludeSize,
};
DeserializeSendMsgMetaResult res = deserialize_send_msg_meta(in_buf);
ASSERT_EQ(res.err, DeserializeSendMsgMetaErrorNone);
EXPECT_EQ(res.port, kPort);
EXPECT_EQ(res.to_addr.addr_type, expected_addr_type);
EXPECT_EQ(res.to_addr.addr_size, GetParam().AddrLen());
EXPECT_EQ(0, memcmp(res.to_addr.addr, expected_addr, GetParam().AddrLen()));
}
TEST_P(UdpSerdeTest, RecvSerializeThenDeserialize) {
const size_t addr_len = GetParam().AddrLen();
uint8_t addr[kIPv6AddrLen];
IpAddrType addr_type;
switch (GetParam().Kind()) {
case AddrKind::Kind::V4: {
addr_type = IpAddrType::Ipv4;
memcpy(addr, kIPv4Addr.begin(), addr_len);
} break;
case AddrKind::Kind::V6: {
addr_type = IpAddrType::Ipv6;
memcpy(addr, kIPv6Addr.begin(), addr_len);
}
}
const Buffer addr_buf = Buffer{
.buf = addr,
.buf_size = addr_len,
};
const CmsgSet cmsg_set = CmsgSet{
.has_ip_tos = true,
.ip_tos = 42,
.has_ip_ttl = true,
.ip_ttl = 43,
.has_ipv6_tclass = true,
.ipv6_tclass = 44,
.has_ipv6_hoplimit = true,
.ipv6_hoplimit = 45,
.has_timestamp_nanos = true,
.timestamp_nanos = 46,
};
uint8_t kBuf[kRxUdpPreludeSize];
const Buffer out_buf = Buffer{
.buf = kBuf,
.buf_size = kRxUdpPreludeSize,
};
constexpr size_t kPayloadSize = 41;
ASSERT_EQ(serialize_recv_msg_meta(
RecvMsgMeta{
.cmsg_set = cmsg_set,
.from_addr_type = addr_type,
.payload_size = kPayloadSize,
.port = kPort,
},
addr_buf, out_buf),
SerializeRecvMsgMetaErrorNone);
fidl::unstable::DecodedMessage<fuchsia_posix_socket::wire::RecvMsgMeta> decoded =
deserialize_recv_msg_meta(cpp20::span<uint8_t>(out_buf.buf, out_buf.buf_size));
ASSERT_TRUE(decoded.ok());
fuchsia_posix_socket::wire::RecvMsgMeta* recv_meta = decoded.PrimaryObject();
switch (GetParam().Kind()) {
case AddrKind::Kind::V4: {
EXPECT_EQ(recv_meta->from().Which(), fuchsia_net::wire::SocketAddress::Tag::kIpv4);
EXPECT_EQ(recv_meta->from().ipv4().port, kPort);
EXPECT_EQ(0, memcmp(recv_meta->from().ipv4().address.addr.begin(), kIPv4Addr.begin(),
kIPv4AddrLen));
} break;
case AddrKind::Kind::V6: {
EXPECT_EQ(recv_meta->from().Which(), fuchsia_net::wire::SocketAddress::Tag::kIpv6);
EXPECT_EQ(recv_meta->from().ipv6().port, kPort);
EXPECT_EQ(0, memcmp(recv_meta->from().ipv6().address.addr.begin(), kIPv6Addr.begin(),
kIPv6AddrLen));
}
}
EXPECT_EQ(recv_meta->control().network().ip().has_tos(), cmsg_set.has_ip_tos);
EXPECT_EQ(recv_meta->control().network().ip().tos(), cmsg_set.ip_tos);
EXPECT_EQ(recv_meta->control().network().ip().has_ttl(), cmsg_set.has_ip_ttl);
EXPECT_EQ(recv_meta->control().network().ip().ttl(), cmsg_set.ip_ttl);
EXPECT_EQ(recv_meta->control().network().ipv6().has_tclass(), cmsg_set.has_ipv6_tclass);
EXPECT_EQ(recv_meta->control().network().ipv6().tclass(), cmsg_set.ipv6_tclass);
EXPECT_EQ(recv_meta->control().network().ipv6().has_hoplimit(), cmsg_set.has_ipv6_hoplimit);
EXPECT_EQ(recv_meta->control().network().ipv6().hoplimit(), cmsg_set.ipv6_hoplimit);
EXPECT_EQ(recv_meta->control().network().socket().has_timestamp(), cmsg_set.has_timestamp_nanos);
EXPECT_EQ(recv_meta->control().network().socket().timestamp().nanoseconds(),
cmsg_set.timestamp_nanos);
EXPECT_EQ(recv_meta->payload_len(), kPayloadSize);
}
TEST_P(UdpSerdeTest, DeserializeRecvErrors) {
uint8_t kBuf[kRxUdpPreludeSize];
memset(kBuf, 0, kRxUdpPreludeSize);
// Buffer too short.
fidl::unstable::DecodedMessage<fuchsia_posix_socket::wire::RecvMsgMeta> buffer_too_short =
deserialize_recv_msg_meta(cpp20::span<uint8_t>(kBuf, 0));
EXPECT_FALSE(buffer_too_short.ok());
// Nonzero prelude.
memset(kBuf, 1, kRxUdpPreludeSize);
fidl::unstable::DecodedMessage<fuchsia_posix_socket::wire::RecvMsgMeta> nonzero_prelude =
deserialize_recv_msg_meta(cpp20::span<uint8_t>(kBuf, kRxUdpPreludeSize));
EXPECT_FALSE(nonzero_prelude.ok());
// Meta size too large.
memset(kBuf, 0, kRxUdpPreludeSize);
uint16_t meta_size = std::numeric_limits<uint16_t>::max();
memcpy(kBuf, &meta_size, sizeof(meta_size));
fidl::unstable::DecodedMessage<fuchsia_posix_socket::wire::RecvMsgMeta> meta_exceeds_buf =
deserialize_recv_msg_meta(cpp20::span<uint8_t>(kBuf, static_cast<uint64_t>(meta_size - 1)));
EXPECT_FALSE(meta_exceeds_buf.ok());
// Failed to decode.
memset(kBuf, 0, kRxUdpPreludeSize);
fidl::unstable::DecodedMessage<fuchsia_posix_socket::wire::RecvMsgMeta> failed_to_decode =
deserialize_recv_msg_meta(cpp20::span<uint8_t>(kBuf, kRxUdpPreludeSize));
EXPECT_FALSE(failed_to_decode.ok());
}
TEST_P(UdpSerdeTest, DeserializeSendErrors) {
// Null buffer.
DeserializeSendMsgMetaResult null_buffer = deserialize_send_msg_meta({
.buf = nullptr,
.buf_size = 0,
});
EXPECT_EQ(null_buffer.err, DeserializeSendMsgMetaErrorInputBufferNull);
uint8_t kBuf[kTxUdpPreludeSize];
// Buffer too short.
DeserializeSendMsgMetaResult buf_too_short = deserialize_send_msg_meta({
.buf = kBuf,
.buf_size = 0,
});
EXPECT_EQ(buf_too_short.err, DeserializeSendMsgMetaErrorInputBufferTooSmall);
// Nonzero prelude.
memset(kBuf, 1, kTxUdpPreludeSize);
DeserializeSendMsgMetaResult nonzero_prelude = deserialize_send_msg_meta({
.buf = kBuf,
.buf_size = kTxUdpPreludeSize,
});
EXPECT_EQ(nonzero_prelude.err, DeserializeSendMsgMetaErrorNonZeroPrelude);
// Meta size too large.
memset(kBuf, 0, kTxUdpPreludeSize);
uint16_t meta_size = std::numeric_limits<uint16_t>::max();
memcpy(kBuf, &meta_size, sizeof(meta_size));
DeserializeSendMsgMetaResult meta_exceeds_buf = deserialize_send_msg_meta({
.buf = kBuf,
.buf_size = static_cast<uint64_t>(meta_size - 1),
});
EXPECT_EQ(meta_exceeds_buf.err, DeserializeSendMsgMetaErrorInputBufferTooSmall);
// Failed to decode.
memset(kBuf, 0, kTxUdpPreludeSize);
DeserializeSendMsgMetaResult failed_to_decode = deserialize_send_msg_meta({
.buf = kBuf,
.buf_size = kTxUdpPreludeSize,
});
EXPECT_EQ(failed_to_decode.err, DeserializeSendMsgMetaErrorFailedToDecode);
}
TEST_P(UdpSerdeTest, SerializeSendErrors) {
fuchsia_posix_socket::wire::SendMsgMeta meta;
uint8_t kBuf[kTxUdpPreludeSize];
EXPECT_FALSE(serialize_send_msg_meta(meta, cpp20::span<uint8_t>(kBuf, 0)));
}
TEST_P(UdpSerdeTest, SerializeRecvErrors) {
const size_t addr_len = GetParam().AddrLen();
uint8_t addr[kIPv6AddrLen];
RecvMsgMeta meta = RecvMsgMeta();
switch (GetParam().Kind()) {
case AddrKind::Kind::V4: {
std::memmove(addr, kIPv4Addr.begin(), addr_len);
meta.from_addr_type = IpAddrType::Ipv4;
} break;
case AddrKind::Kind::V6: {
std::memmove(addr, kIPv6Addr.begin(), addr_len);
meta.from_addr_type = IpAddrType::Ipv6;
}
}
Buffer addr_buf = Buffer{
.buf = addr,
.buf_size = addr_len,
};
// Null buffer.
EXPECT_EQ(serialize_recv_msg_meta(meta, addr_buf,
{
.buf = nullptr,
.buf_size = 0,
}),
SerializeRecvMsgMetaErrorOutputBufferNull);
uint8_t kBuf[kTxUdpPreludeSize];
// Buffer too short.
EXPECT_EQ(serialize_recv_msg_meta(meta, addr_buf,
{
.buf = kBuf,
.buf_size = 0,
}),
SerializeRecvMsgMetaErrorOutputBufferTooSmall);
// Address too short.
EXPECT_EQ(serialize_recv_msg_meta(meta,
{
.buf = addr,
.buf_size = 0,
},
{
.buf = kBuf,
.buf_size = kTxUdpPreludeSize,
}),
SerializeRecvMsgMetaErrorFromAddrBufferTooSmall);
}
INSTANTIATE_TEST_SUITE_P(UdpSerdeTest, UdpSerdeTest,
::testing::Values(AddrKind::Kind::V4, AddrKind::Kind::V6),
[](const auto info) { return info.param.AddrKindToString(); });