| // Copyright 2019 The Chromium 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 "net/third_party/quiche/src/quic/core/quic_udp_socket.h" |
| #include <sys/socket.h> |
| |
| #ifdef __APPLE__ |
| #include <TargetConditionals.h> |
| #endif |
| |
| #include "net/third_party/quiche/src/quic/core/quic_constants.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| // Used by ReadMultiplePackets tests. |
| struct ReadBuffers { |
| char control_buffer[512]; |
| char packet_buffer[1536]; |
| }; |
| |
| // Allows IPv6-specific testing. |
| struct TestParameters { |
| // If true, the test will only use IPv6. If false, IPv4 will be used if |
| // possible, with IPv6 used as a fallback. |
| bool force_ipv6; |
| // The value of ipv6_only to be used in QuicUdpSocketApi::Create calls. |
| bool ipv6_only; |
| }; |
| } // namespace |
| |
| class QuicUdpSocketTest : public QuicTestWithParam<TestParameters> { |
| protected: |
| void SetUp() override { |
| const TestParameters& parameters = GetParam(); |
| if (!parameters.force_ipv6) { |
| // Try creating AF_INET socket, if it fails because of unsupported address |
| // family then tests are being run under IPv6-only environment, initialize |
| // address family to use for running the test under as AF_INET6 otherwise |
| // initialize it as AF_INET. |
| address_family_ = AF_INET; |
| fd_client_ = |
| api_.Create(address_family_, |
| /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, |
| /*send_buffer_size =*/kDefaultSocketReceiveBuffer, |
| /*ipv6_only =*/parameters.ipv6_only); |
| } |
| if (fd_client_ == kQuicInvalidSocketFd) { |
| // Either AF_INET is unsupported, or force_ipv6 is true. |
| address_family_ = AF_INET6; |
| fd_client_ = |
| api_.Create(address_family_, |
| /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, |
| /*send_buffer_size =*/kDefaultSocketReceiveBuffer, |
| /*ipv6_only =*/parameters.ipv6_only); |
| } |
| ASSERT_NE(fd_client_, kQuicInvalidSocketFd); |
| |
| fd_server_ = |
| api_.Create(address_family_, |
| /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, |
| /*send_buffer_size =*/kDefaultSocketReceiveBuffer, |
| /*ipv6_only =*/parameters.ipv6_only); |
| ASSERT_NE(fd_server_, kQuicInvalidSocketFd); |
| |
| ASSERT_TRUE( |
| api_.Bind(fd_server_, QuicSocketAddress(Loopback(), /*port=*/0))); |
| |
| ASSERT_EQ(0, server_address_.FromSocket(fd_server_)); |
| |
| QUIC_LOG(INFO) << "Testing under IP" |
| << std::string((address_family_ == AF_INET) ? "v4" : "v6"); |
| } |
| |
| ~QuicUdpSocketTest() { |
| api_.Destroy(fd_client_); |
| api_.Destroy(fd_server_); |
| } |
| |
| QuicIpAddress Loopback() const { |
| return (address_family_ == AF_INET) ? QuicIpAddress::Loopback4() |
| : QuicIpAddress::Loopback6(); |
| } |
| |
| // Client sends the first |packet_size| bytes in |client_packet_buffer_| to |
| // server. |
| WriteResult SendPacketFromClient(size_t packet_size) { |
| EXPECT_LE(packet_size, sizeof(client_packet_buffer_)); |
| QuicUdpPacketInfo packet_info; |
| packet_info.SetPeerAddress(server_address_); |
| return api_.WritePacket(fd_client_, client_packet_buffer_, packet_size, |
| packet_info); |
| } |
| |
| WriteResult SendPacketFromClientWithTtl(size_t packet_size, int ttl) { |
| EXPECT_LE(packet_size, sizeof(client_packet_buffer_)); |
| QuicUdpPacketInfo packet_info; |
| packet_info.SetPeerAddress(server_address_); |
| packet_info.SetTtl(ttl); |
| return api_.WritePacket(fd_client_, client_packet_buffer_, packet_size, |
| packet_info); |
| } |
| |
| // Server waits for an incoming packet and reads it into |
| // |server_packet_buffer_|. |
| QuicUdpSocketApi::ReadPacketResult ReadPacketFromServer( |
| BitMask64 packet_info_interested) { |
| EXPECT_TRUE( |
| api_.WaitUntilReadable(fd_server_, QuicTime::Delta::FromSeconds(5))); |
| memset(server_packet_buffer_, 0, sizeof(server_packet_buffer_)); |
| QuicUdpSocketApi::ReadPacketResult result; |
| result.packet_buffer = {server_packet_buffer_, |
| sizeof(server_packet_buffer_)}; |
| result.control_buffer = {server_control_buffer_, |
| sizeof(server_control_buffer_)}; |
| api_.ReadPacket(fd_server_, packet_info_interested, &result); |
| return result; |
| } |
| |
| int ComparePacketBuffers(size_t packet_size) { |
| return memcmp(client_packet_buffer_, server_packet_buffer_, packet_size); |
| } |
| |
| bool VerifyBufferIsFilledWith(const char* buffer, |
| size_t buffer_length, |
| char c) { |
| for (size_t i = 0; i < buffer_length; ++i) { |
| if (buffer[i] != c) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| QuicUdpSocketApi api_; |
| QuicUdpSocketFd fd_client_ = kQuicInvalidSocketFd; |
| QuicUdpSocketFd fd_server_ = kQuicInvalidSocketFd; |
| QuicSocketAddress server_address_; |
| int address_family_; |
| char client_packet_buffer_[kEthernetMTU] = {0}; |
| char server_packet_buffer_[kDefaultMaxPacketSize] = {0}; |
| char server_control_buffer_[512] = {0}; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P( |
| PlatformIndependent, |
| QuicUdpSocketTest, |
| testing::Values(TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/false}, |
| TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/true}, |
| TestParameters{/*force_ipv6 =*/true, /*ipv6_only =*/true})); |
| |
| #ifndef TARGET_OS_IPHONE |
| // IPv6 on iOS is known to fail without ipv6_only, so should not be tested. |
| INSTANTIATE_TEST_SUITE_P(NonIos, |
| QuicUdpSocketTest, |
| testing::Values(TestParameters{/*force_ipv6 =*/true, |
| /*ipv6_only =*/false})); |
| #endif |
| |
| TEST_P(QuicUdpSocketTest, ReadPacketResultReset) { |
| QuicUdpSocketApi::ReadPacketResult result; |
| result.packet_info.SetDroppedPackets(100); |
| result.packet_buffer.buffer_len = 100; |
| result.ok = true; |
| |
| result.Reset(/*packet_buffer_length=*/200); |
| |
| EXPECT_FALSE(result.ok); |
| EXPECT_FALSE( |
| result.packet_info.HasValue(QuicUdpPacketInfoBit::DROPPED_PACKETS)); |
| EXPECT_EQ(200u, result.packet_buffer.buffer_len); |
| } |
| |
| TEST_P(QuicUdpSocketTest, ReadPacketOnly) { |
| const size_t kPacketSize = 512; |
| memset(client_packet_buffer_, '-', kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| |
| QuicUdpSocketApi::ReadPacketResult read_result = |
| ReadPacketFromServer(/*packet_info_interested=*/BitMask64()); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| } |
| |
| TEST_P(QuicUdpSocketTest, ReadTruncated) { |
| const size_t kPacketSize = kDefaultMaxPacketSize + 1; |
| memset(client_packet_buffer_, '*', kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| |
| QuicUdpSocketApi::ReadPacketResult read_result = |
| ReadPacketFromServer(/*packet_info_interested=*/BitMask64()); |
| ASSERT_FALSE(read_result.ok); |
| } |
| |
| TEST_P(QuicUdpSocketTest, ReadDroppedPackets) { |
| const size_t kPacketSize = kDefaultMaxPacketSize; |
| memset(client_packet_buffer_, '-', kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| |
| // Read the first packet without enabling DROPPED_PACKETS. |
| QuicUdpSocketApi::ReadPacketResult read_result = |
| ReadPacketFromServer(BitMask64(QuicUdpPacketInfoBit::DROPPED_PACKETS)); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| ASSERT_FALSE( |
| read_result.packet_info.HasValue(QuicUdpPacketInfoBit::DROPPED_PACKETS)); |
| |
| // Enable DROPPED_PACKETS and read the second packet. |
| if (!api_.EnableDroppedPacketCount(fd_server_)) { |
| QUIC_LOG(INFO) << "DROPPED_PACKETS is not supported"; |
| return; |
| } |
| read_result = |
| ReadPacketFromServer(BitMask64(QuicUdpPacketInfoBit::DROPPED_PACKETS)); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| if (read_result.packet_info.HasValue(QuicUdpPacketInfoBit::DROPPED_PACKETS)) { |
| EXPECT_EQ(0u, read_result.packet_info.dropped_packets()); |
| } |
| } |
| |
| TEST_P(QuicUdpSocketTest, ReadSelfIp) { |
| const QuicUdpPacketInfoBit self_ip_bit = |
| (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP |
| : QuicUdpPacketInfoBit::V6_SELF_IP; |
| |
| const size_t kPacketSize = 512; |
| memset(client_packet_buffer_, '&', kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| |
| QuicUdpSocketApi::ReadPacketResult read_result = |
| ReadPacketFromServer(BitMask64(self_ip_bit)); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| ASSERT_TRUE(read_result.packet_info.HasValue(self_ip_bit)); |
| EXPECT_EQ(Loopback(), (address_family_ == AF_INET) |
| ? read_result.packet_info.self_v4_ip() |
| : read_result.packet_info.self_v6_ip()); |
| } |
| |
| TEST_P(QuicUdpSocketTest, ReadReceiveTimestamp) { |
| const size_t kPacketSize = kDefaultMaxPacketSize; |
| memset(client_packet_buffer_, '-', kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| |
| // Read the first packet without enabling RECV_TIMESTAMP. |
| QuicUdpSocketApi::ReadPacketResult read_result = |
| ReadPacketFromServer(BitMask64(QuicUdpPacketInfoBit::RECV_TIMESTAMP)); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| ASSERT_FALSE( |
| read_result.packet_info.HasValue(QuicUdpPacketInfoBit::RECV_TIMESTAMP)); |
| |
| // Enable RECV_TIMESTAMP and read the second packet. |
| if (!api_.EnableReceiveTimestamp(fd_server_)) { |
| QUIC_LOG(INFO) << "RECV_TIMESTAMP is not supported"; |
| return; |
| } |
| read_result = |
| ReadPacketFromServer(BitMask64(QuicUdpPacketInfoBit::RECV_TIMESTAMP)); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| ASSERT_TRUE( |
| read_result.packet_info.HasValue(QuicUdpPacketInfoBit::RECV_TIMESTAMP)); |
| QuicWallTime recv_timestamp = read_result.packet_info.receive_timestamp(); |
| // 1577836800 is the unix seconds for 2020-01-01 |
| EXPECT_TRUE( |
| QuicWallTime::FromUNIXSeconds(1577836800).IsBefore(recv_timestamp)); |
| } |
| |
| TEST_P(QuicUdpSocketTest, Ttl) { |
| const size_t kPacketSize = 512; |
| memset(client_packet_buffer_, '$', kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClientWithTtl(kPacketSize, 13)); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClientWithTtl(kPacketSize, 13)); |
| |
| // Read the first packet without enabling ttl reporting. |
| QuicUdpSocketApi::ReadPacketResult read_result = |
| ReadPacketFromServer(BitMask64(QuicUdpPacketInfoBit::TTL)); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| ASSERT_FALSE(read_result.packet_info.HasValue(QuicUdpPacketInfoBit::TTL)); |
| |
| // Enable ttl reporting and read the second packet. |
| if (!((address_family_ == AF_INET) |
| ? api_.EnableReceiveTtlForV4(fd_server_) |
| : api_.EnableReceiveTtlForV6(fd_server_))) { |
| QUIC_LOG(INFO) << "TTL is not supported for address family " |
| << address_family_; |
| return; |
| } |
| |
| read_result = ReadPacketFromServer(BitMask64(QuicUdpPacketInfoBit::TTL)); |
| ASSERT_TRUE(read_result.ok); |
| ASSERT_EQ(kPacketSize, read_result.packet_buffer.buffer_len); |
| ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); |
| ASSERT_TRUE(read_result.packet_info.HasValue(QuicUdpPacketInfoBit::TTL)); |
| EXPECT_EQ(13, read_result.packet_info.ttl()); |
| } |
| |
| TEST_P(QuicUdpSocketTest, ReadMultiplePackets) { |
| const QuicUdpPacketInfoBit self_ip_bit = |
| (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP |
| : QuicUdpPacketInfoBit::V6_SELF_IP; |
| const size_t kPacketSize = kDefaultMaxPacketSize; |
| const size_t kNumPackets = 90; |
| for (size_t i = 0; i < kNumPackets; ++i) { |
| memset(client_packet_buffer_, ' ' + i, kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| } |
| |
| const size_t kNumPacketsPerRead = 16; |
| size_t total_packets_read = 0; |
| while (total_packets_read < kNumPackets) { |
| std::unique_ptr<ReadBuffers[]> read_buffers = |
| std::make_unique<ReadBuffers[]>(kNumPacketsPerRead); |
| QuicUdpSocketApi::ReadPacketResults results(kNumPacketsPerRead); |
| for (size_t i = 0; i < kNumPacketsPerRead; ++i) { |
| results[i].packet_buffer.buffer = read_buffers[i].packet_buffer; |
| results[i].packet_buffer.buffer_len = |
| sizeof(read_buffers[i].packet_buffer); |
| |
| results[i].control_buffer.buffer = read_buffers[i].control_buffer; |
| results[i].control_buffer.buffer_len = |
| sizeof(read_buffers[i].control_buffer); |
| } |
| size_t packets_read = |
| api_.ReadMultiplePackets(fd_server_, BitMask64(self_ip_bit), &results); |
| if (packets_read == 0) { |
| ASSERT_TRUE( |
| api_.WaitUntilReadable(fd_server_, QuicTime::Delta::FromSeconds(5))); |
| packets_read = api_.ReadMultiplePackets(fd_server_, |
| BitMask64(self_ip_bit), &results); |
| ASSERT_GT(packets_read, 0u); |
| } |
| |
| for (size_t i = 0; i < packets_read; ++i) { |
| const auto& result = results[i]; |
| ASSERT_TRUE(result.ok); |
| ASSERT_EQ(kPacketSize, result.packet_buffer.buffer_len); |
| ASSERT_TRUE(VerifyBufferIsFilledWith(result.packet_buffer.buffer, |
| result.packet_buffer.buffer_len, |
| ' ' + total_packets_read)); |
| ASSERT_TRUE(result.packet_info.HasValue(self_ip_bit)); |
| EXPECT_EQ(Loopback(), (address_family_ == AF_INET) |
| ? result.packet_info.self_v4_ip() |
| : result.packet_info.self_v6_ip()); |
| total_packets_read++; |
| } |
| } |
| } |
| |
| TEST_P(QuicUdpSocketTest, ReadMultiplePacketsSomeTruncated) { |
| const QuicUdpPacketInfoBit self_ip_bit = |
| (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP |
| : QuicUdpPacketInfoBit::V6_SELF_IP; |
| const size_t kPacketSize = kDefaultMaxPacketSize; |
| const size_t kNumPackets = 90; |
| for (size_t i = 0; i < kNumPackets; ++i) { |
| memset(client_packet_buffer_, ' ' + i, kPacketSize); |
| ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), |
| SendPacketFromClient(kPacketSize)); |
| } |
| |
| const size_t kNumPacketsPerRead = 16; |
| size_t total_packets_read = 0; // Including truncated packets. |
| while (total_packets_read < kNumPackets) { |
| std::unique_ptr<ReadBuffers[]> read_buffers = |
| std::make_unique<ReadBuffers[]>(kNumPacketsPerRead); |
| QuicUdpSocketApi::ReadPacketResults results(kNumPacketsPerRead); |
| // Use small packet buffer for all even-numbered packets and expect them to |
| // be truncated. |
| auto is_truncated = [total_packets_read](size_t i) { |
| return ((total_packets_read + i) % 2) == 1; |
| }; |
| |
| for (size_t i = 0; i < kNumPacketsPerRead; ++i) { |
| results[i].packet_buffer.buffer = read_buffers[i].packet_buffer; |
| results[i].packet_buffer.buffer_len = |
| is_truncated(i) ? kPacketSize - 1 |
| : sizeof(read_buffers[i].packet_buffer); |
| |
| results[i].control_buffer.buffer = read_buffers[i].control_buffer; |
| results[i].control_buffer.buffer_len = |
| sizeof(read_buffers[i].control_buffer); |
| } |
| size_t packets_read = |
| api_.ReadMultiplePackets(fd_server_, BitMask64(self_ip_bit), &results); |
| if (packets_read == 0) { |
| ASSERT_TRUE( |
| api_.WaitUntilReadable(fd_server_, QuicTime::Delta::FromSeconds(5))); |
| packets_read = api_.ReadMultiplePackets(fd_server_, |
| BitMask64(self_ip_bit), &results); |
| ASSERT_GT(packets_read, 0u); |
| } |
| |
| for (size_t i = 0; i < packets_read; ++i) { |
| const auto& result = results[i]; |
| if (is_truncated(i)) { |
| ASSERT_FALSE(result.ok); |
| } else { |
| ASSERT_TRUE(result.ok); |
| ASSERT_EQ(kPacketSize, result.packet_buffer.buffer_len); |
| ASSERT_TRUE(VerifyBufferIsFilledWith(result.packet_buffer.buffer, |
| result.packet_buffer.buffer_len, |
| ' ' + total_packets_read)); |
| ASSERT_TRUE(result.packet_info.HasValue(self_ip_bit)); |
| EXPECT_EQ(Loopback(), (address_family_ == AF_INET) |
| ? result.packet_info.self_v4_ip() |
| : result.packet_info.self_v6_ip()); |
| } |
| total_packets_read++; |
| } |
| } |
| } |
| |
| } // namespace test |
| } // namespace quic |