| // Copyright 2018 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 <stddef.h> |
| #include <stdint.h> |
| |
| #include <limits> |
| #include <utility> |
| |
| #include "services/network/udp_socket.h" |
| |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| #include "net/base/net_errors.h" |
| #include "net/socket/udp_socket.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| #include "services/network/public/interfaces/udp_socket.mojom.h" |
| #include "services/network/udp_socket_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace network { |
| |
| namespace { |
| |
| class SocketWrapperTestImpl : public UDPSocket::SocketWrapper { |
| public: |
| SocketWrapperTestImpl() {} |
| ~SocketWrapperTestImpl() override {} |
| |
| int Open(net::AddressFamily address_family) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| int Connect(const net::IPEndPoint& remote_addr) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| int Bind(const net::IPEndPoint& local_addr) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| int SetSendBufferSize(uint32_t size) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| int SetReceiveBufferSize(uint32_t size) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| int SendTo(net::IOBuffer* buf, |
| int buf_len, |
| const net::IPEndPoint& dest_addr, |
| const net::CompletionCallback& callback) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| int Write(net::IOBuffer* buf, |
| int buf_len, |
| const net::CompletionCallback& callback) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| int RecvFrom(net::IOBuffer* buf, |
| int buf_len, |
| net::IPEndPoint* address, |
| const net::CompletionCallback& callback) override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| |
| int GetLocalAddress(net::IPEndPoint* address) const override { |
| NOTREACHED(); |
| return net::ERR_NOT_IMPLEMENTED; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SocketWrapperTestImpl); |
| }; |
| |
| net::IPEndPoint GetLocalHostWithAnyPort() { |
| return net::IPEndPoint(net::IPAddress(127, 0, 0, 1), 0); |
| } |
| |
| std::vector<uint8_t> CreateTestMessage(uint8_t initial, size_t size) { |
| std::vector<uint8_t> array(size); |
| for (size_t i = 0; i < size; ++i) |
| array[i] = static_cast<uint8_t>((i + initial) % 256); |
| return array; |
| } |
| |
| // A Mock UDPSocket that always returns net::ERR_IO_PENDING for SendTo()s. |
| class HangingUDPSocket : public SocketWrapperTestImpl { |
| public: |
| HangingUDPSocket() {} |
| |
| // SocketWrapperTestImpl implementation. |
| int Open(net::AddressFamily address_family) override { return net::OK; } |
| int Bind(const net::IPEndPoint& local_addr) override { return net::OK; } |
| int SendTo(net::IOBuffer* buf, |
| int buf_len, |
| const net::IPEndPoint& address, |
| const net::CompletionCallback& callback) override { |
| EXPECT_EQ(expected_data_, |
| std::vector<unsigned char>(buf->data(), buf->data() + buf_len)); |
| if (should_complete_requests_) |
| return net::OK; |
| pending_io_buffers_.push_back(buf); |
| pending_io_buffer_lengths_.push_back(buf_len); |
| pending_send_requests_.push_back(callback); |
| return net::ERR_IO_PENDING; |
| } |
| int GetLocalAddress(net::IPEndPoint* address) const override { |
| *address = GetLocalHostWithAnyPort(); |
| return net::OK; |
| } |
| |
| void set_expected_data(std::vector<uint8_t> expected_data) { |
| expected_data_ = expected_data; |
| } |
| |
| const std::vector<net::IOBuffer*>& pending_io_buffers() const { |
| return pending_io_buffers_; |
| } |
| |
| const std::vector<int>& pending_io_buffer_lengths() const { |
| return pending_io_buffer_lengths_; |
| } |
| |
| // Completes all pending requests. |
| void CompleteAllPendingRequests() { |
| should_complete_requests_ = true; |
| for (auto request : pending_send_requests_) { |
| request.Run(net::OK); |
| } |
| pending_send_requests_.clear(); |
| } |
| |
| private: |
| std::vector<uint8_t> expected_data_; |
| bool should_complete_requests_ = false; |
| std::vector<net::IOBuffer*> pending_io_buffers_; |
| std::vector<int> pending_io_buffer_lengths_; |
| std::vector<net::CompletionCallback> pending_send_requests_; |
| }; |
| |
| // A Mock UDPSocket that returns 0 byte read. |
| class ZeroByteReadUDPSocket : public SocketWrapperTestImpl { |
| public: |
| ZeroByteReadUDPSocket() {} |
| int Open(net::AddressFamily address_family) override { return net::OK; } |
| int Bind(const net::IPEndPoint& local_addr) override { return net::OK; } |
| int RecvFrom(net::IOBuffer* buf, |
| int buf_len, |
| net::IPEndPoint* address, |
| const net::CompletionCallback& callback) override { |
| *address = GetLocalHostWithAnyPort(); |
| return 0; |
| } |
| int GetLocalAddress(net::IPEndPoint* address) const override { |
| *address = GetLocalHostWithAnyPort(); |
| return net::OK; |
| } |
| }; |
| |
| } // namespace |
| |
| class UDPSocketTest : public testing::Test { |
| public: |
| UDPSocketTest() |
| : scoped_task_environment_( |
| base::test::ScopedTaskEnvironment::MainThreadType::IO) {} |
| ~UDPSocketTest() override {} |
| |
| void SetWrappedSocket( |
| UDPSocket* socket, |
| std::unique_ptr<UDPSocket::SocketWrapper> socket_wrapper) { |
| socket->wrapped_socket_ = std::move(socket_wrapper); |
| } |
| |
| uint32_t GetRemainingRecvSlots(UDPSocket* socket) { |
| return socket->remaining_recv_slots_; |
| } |
| |
| private: |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| |
| DISALLOW_COPY_AND_ASSIGN(UDPSocketTest); |
| }; |
| |
| TEST_F(UDPSocketTest, Settings) { |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| mojom::UDPSocketPtr socket_ptr; |
| UDPSocket impl(mojo::MakeRequest(&socket_ptr), |
| std::move(receiver_interface_ptr)); |
| net::IPEndPoint server_addr; |
| net::IPEndPoint any_port(GetLocalHostWithAnyPort()); |
| |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync(&socket_ptr, |
| any_port.GetFamily())); |
| net::IPEndPoint local_addr; |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync(&socket_ptr, any_port, |
| &local_addr)); |
| EXPECT_NE(local_addr.ToString(), any_port.ToString()); |
| EXPECT_EQ(net::OK, test::UDPSocketTestHelper::SetSendBufferSizeSync( |
| &socket_ptr, 1024)); |
| EXPECT_EQ(net::OK, test::UDPSocketTestHelper::SetReceiveBufferSizeSync( |
| &socket_ptr, 2048)); |
| } |
| |
| // Tests that Send() is used after Bind() is not supported. Send() should only |
| // be used after Connect(). |
| TEST_F(UDPSocketTest, TestSendWithBind) { |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| mojom::UDPSocketPtr socket_ptr; |
| UDPSocket impl(mojo::MakeRequest(&socket_ptr), |
| std::move(receiver_interface_ptr)); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| |
| // Bind() the socket. |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &socket_ptr, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &socket_ptr, server_addr, &server_addr)); |
| |
| // Connect() has not been used, so Send() is not supported. |
| std::vector<uint8_t> test_msg{1}; |
| int result = test::UDPSocketTestHelper::SendSync(&socket_ptr, test_msg); |
| EXPECT_EQ(net::ERR_UNEXPECTED, result); |
| } |
| |
| // Tests that when SendTo() is used after Connect() is not supported. SendTo() |
| // should only be used after Bind(). |
| TEST_F(UDPSocketTest, TestSendToWithConnect) { |
| // Create a server socket to listen for incoming datagrams. |
| test::UDPSocketReceiverImpl receiver; |
| mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver); |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr)); |
| |
| mojom::UDPSocketPtr server_socket; |
| UDPSocket impl(mojo::MakeRequest(&server_socket), |
| std::move(receiver_interface_ptr)); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &server_socket, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &server_socket, server_addr, &server_addr)); |
| |
| // Create a client socket to send datagrams. |
| mojom::UDPSocketReceiverPtr client_receiver_ptr; |
| mojom::UDPSocketPtr client_socket; |
| UDPSocket client_impl(mojo::MakeRequest(&client_socket), |
| std::move(client_receiver_ptr)); |
| net::IPEndPoint client_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &client_socket, client_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::ConnectSync( |
| &client_socket, server_addr, &client_addr)); |
| |
| std::vector<uint8_t> test_msg({1}); |
| int result = test::UDPSocketTestHelper::SendToSync(&client_socket, |
| server_addr, test_msg); |
| EXPECT_EQ(net::ERR_UNEXPECTED, result); |
| } |
| |
| // Tests that the sequence of calling Open(), Bind()/Connect() and setters is |
| // important. |
| TEST_F(UDPSocketTest, TestUnexpectedSequences) { |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| mojom::UDPSocketPtr socket_ptr; |
| UDPSocket impl(mojo::MakeRequest(&socket_ptr), |
| std::move(receiver_interface_ptr)); |
| net::IPEndPoint server_addr; |
| net::IPEndPoint any_port(GetLocalHostWithAnyPort()); |
| |
| // Before Open(), calling Connect() or Bind() will result in an error. |
| net::IPEndPoint local_addr; |
| ASSERT_EQ(net::ERR_UNEXPECTED, test::UDPSocketTestHelper::BindSync( |
| &socket_ptr, any_port, &local_addr)); |
| ASSERT_EQ(net::ERR_UNEXPECTED, test::UDPSocketTestHelper::ConnectSync( |
| &socket_ptr, any_port, &local_addr)); |
| |
| // Calling any Setters that depend on Open() should fail. |
| EXPECT_EQ( |
| net::ERR_UNEXPECTED, |
| test::UDPSocketTestHelper::SetSendBufferSizeSync(&socket_ptr, 1024)); |
| EXPECT_EQ( |
| net::ERR_UNEXPECTED, |
| test::UDPSocketTestHelper::SetReceiveBufferSizeSync(&socket_ptr, 2048)); |
| |
| // Now call Open(). |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync(&socket_ptr, |
| any_port.GetFamily())); |
| EXPECT_NE(local_addr.ToString(), any_port.ToString()); |
| |
| // It is illegal call Open() twice. |
| ASSERT_EQ(net::ERR_UNEXPECTED, test::UDPSocketTestHelper::OpenSync( |
| &socket_ptr, any_port.GetFamily())); |
| |
| // Now these Setters should work. |
| EXPECT_EQ(net::OK, test::UDPSocketTestHelper::SetSendBufferSizeSync( |
| &socket_ptr, 1024)); |
| EXPECT_EQ(net::OK, test::UDPSocketTestHelper::SetReceiveBufferSizeSync( |
| &socket_ptr, 2048)); |
| |
| // Now Bind() the socket. |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync(&socket_ptr, any_port, |
| &local_addr)); |
| |
| // Calling Connect() after Bind() should fail because they can't be both used. |
| ASSERT_EQ(net::ERR_SOCKET_IS_CONNECTED, |
| test::UDPSocketTestHelper::ConnectSync(&socket_ptr, any_port, |
| &local_addr)); |
| } |
| |
| // Tests that if the underlying socket implementation's Send() returned |
| // ERR_IO_PENDING, udp_socket.cc doesn't free the send buffer. |
| TEST_F(UDPSocketTest, TestBufferValid) { |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| mojom::UDPSocketPtr socket_ptr; |
| UDPSocket impl(mojo::MakeRequest(&socket_ptr), |
| std::move(receiver_interface_ptr)); |
| |
| HangingUDPSocket* socket_raw_ptr = new HangingUDPSocket(); |
| SetWrappedSocket(&impl, base::WrapUnique(socket_raw_ptr)); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &socket_ptr, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &socket_ptr, server_addr, &server_addr)); |
| const size_t kDatagramSize = 255; |
| std::vector<uint8_t> test_msg(CreateTestMessage(0, kDatagramSize)); |
| socket_raw_ptr->set_expected_data(test_msg); |
| base::RunLoop run_loop; |
| socket_ptr->SendTo(GetLocalHostWithAnyPort(), test_msg, |
| base::BindOnce( |
| [](base::RunLoop* run_loop, int result) { |
| EXPECT_EQ(net::OK, result); |
| run_loop->Quit(); |
| }, |
| base::Unretained(&run_loop))); |
| |
| socket_ptr.FlushForTesting(); |
| |
| ASSERT_EQ(1u, socket_raw_ptr->pending_io_buffers().size()); |
| ASSERT_EQ(1u, socket_raw_ptr->pending_io_buffer_lengths().size()); |
| // Make sure the caller of HangingUDPSocket doesn't destroy the send buffer, |
| // and that buffer still contains the exact same data. |
| net::IOBuffer* buf = socket_raw_ptr->pending_io_buffers()[0]; |
| int buf_len = socket_raw_ptr->pending_io_buffer_lengths()[0]; |
| EXPECT_EQ(test_msg, |
| std::vector<unsigned char>(buf->data(), buf->data() + buf_len)); |
| } |
| |
| // Test that exercises the queuing of send requests and makes sure |
| // ERR_INSUFFICIENT_RESOURCES is returned appropriately. |
| TEST_F(UDPSocketTest, TestInsufficientResources) { |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| mojom::UDPSocketPtr socket_ptr; |
| UDPSocket impl(mojo::MakeRequest(&socket_ptr), |
| std::move(receiver_interface_ptr)); |
| |
| HangingUDPSocket* socket_raw_ptr = new HangingUDPSocket(); |
| SetWrappedSocket(&impl, base::WrapUnique(socket_raw_ptr)); |
| |
| const size_t kQueueSize = UDPSocket::kMaxPendingSendRequests; |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &socket_ptr, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &socket_ptr, server_addr, &server_addr)); |
| const size_t kDatagramSize = 255; |
| std::vector<uint8_t> test_msg(CreateTestMessage(0, kDatagramSize)); |
| socket_raw_ptr->set_expected_data(test_msg); |
| // Send |kQueueSize| + 1 datagrams in a row, so the queue is filled up. |
| std::vector<std::unique_ptr<base::RunLoop>> run_loops; |
| for (size_t i = 0; i < kQueueSize + 1; ++i) { |
| run_loops.push_back(std::make_unique<base::RunLoop>()); |
| socket_ptr->SendTo(GetLocalHostWithAnyPort(), test_msg, |
| base::BindOnce( |
| [](base::RunLoop* run_loop, int result) { |
| EXPECT_EQ(net::OK, result); |
| run_loop->Quit(); |
| }, |
| base::Unretained(run_loops[i].get()))); |
| } |
| |
| // SendTo() beyond the queue size should fail. |
| EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES, |
| test::UDPSocketTestHelper::SendToSync( |
| &socket_ptr, GetLocalHostWithAnyPort(), test_msg)); |
| |
| // Complete all pending requests. Queued SendTo() should hear back. |
| socket_raw_ptr->CompleteAllPendingRequests(); |
| for (const auto& loop : run_loops) { |
| loop->Run(); |
| } |
| } |
| |
| TEST_F(UDPSocketTest, TestReceiveMoreOverflow) { |
| // Create a server socket to listen for incoming datagrams. |
| test::UDPSocketReceiverImpl receiver; |
| mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver); |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr)); |
| |
| mojom::UDPSocketPtr server_socket; |
| UDPSocket impl(mojo::MakeRequest(&server_socket), |
| std::move(receiver_interface_ptr)); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &server_socket, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &server_socket, server_addr, &server_addr)); |
| |
| server_socket->ReceiveMore(std::numeric_limits<uint32_t>::max()); |
| server_socket.FlushForTesting(); |
| EXPECT_EQ(std::numeric_limits<uint32_t>::max(), GetRemainingRecvSlots(&impl)); |
| server_socket->ReceiveMore(1); |
| server_socket.FlushForTesting(); |
| EXPECT_EQ(std::numeric_limits<uint32_t>::max(), GetRemainingRecvSlots(&impl)); |
| } |
| |
| TEST_F(UDPSocketTest, TestReadSend) { |
| // Create a server socket to listen for incoming datagrams. |
| test::UDPSocketReceiverImpl receiver; |
| mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver); |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr)); |
| |
| mojom::UDPSocketPtr server_socket; |
| UDPSocket impl(mojo::MakeRequest(&server_socket), |
| std::move(receiver_interface_ptr)); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &server_socket, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &server_socket, server_addr, &server_addr)); |
| |
| // Create a client socket to send datagrams. |
| mojom::UDPSocketReceiverPtr client_receiver_ptr; |
| mojom::UDPSocketPtr client_socket; |
| UDPSocket client_impl(mojo::MakeRequest(&client_socket), |
| std::move(client_receiver_ptr)); |
| net::IPEndPoint client_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &client_socket, client_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::ConnectSync( |
| &client_socket, server_addr, &client_addr)); |
| |
| const size_t kDatagramCount = 6; |
| const size_t kDatagramSize = 255; |
| server_socket->ReceiveMore(kDatagramCount); |
| |
| for (size_t i = 0; i < kDatagramCount; ++i) { |
| std::vector<uint8_t> test_msg( |
| CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize)); |
| int result = test::UDPSocketTestHelper::SendSync(&client_socket, test_msg); |
| EXPECT_EQ(net::OK, result); |
| } |
| |
| receiver.WaitForReceivedResults(kDatagramCount); |
| EXPECT_EQ(kDatagramCount, receiver.results().size()); |
| |
| int i = 0; |
| for (const auto& result : receiver.results()) { |
| EXPECT_EQ(net::OK, result.net_error); |
| EXPECT_EQ(result.src_addr, client_addr); |
| EXPECT_EQ(CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize), |
| result.data.value()); |
| i++; |
| } |
| // Tests that sending a message that is larger than the specified limit |
| // results in an early rejection. |
| std::vector<uint8_t> large_msg(64 * 1024, 1); |
| EXPECT_EQ(net::ERR_MSG_TOO_BIG, test::UDPSocketTestHelper::SendToSync( |
| &server_socket, client_addr, large_msg)); |
| } |
| |
| TEST_F(UDPSocketTest, TestReadSendTo) { |
| // Create a server socket to send data. |
| mojom::UDPSocketPtr server_socket; |
| mojom::UDPSocketReceiverPtr receiver_ptr; |
| UDPSocket impl(mojo::MakeRequest(&server_socket), std::move(receiver_ptr)); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &server_socket, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &server_socket, server_addr, &server_addr)); |
| |
| // Create a client socket to send datagrams. |
| test::UDPSocketReceiverImpl receiver; |
| mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver); |
| mojom::UDPSocketReceiverPtr client_receiver_ptr; |
| receiver_binding.Bind(mojo::MakeRequest(&client_receiver_ptr)); |
| |
| mojom::UDPSocketPtr client_socket; |
| UDPSocket client_impl(mojo::MakeRequest(&client_socket), |
| std::move(client_receiver_ptr)); |
| net::IPEndPoint client_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &client_socket, client_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::ConnectSync( |
| &client_socket, server_addr, &client_addr)); |
| |
| const size_t kDatagramCount = 6; |
| const size_t kDatagramSize = 255; |
| client_socket->ReceiveMore(kDatagramCount); |
| |
| for (size_t i = 0; i < kDatagramCount; ++i) { |
| std::vector<uint8_t> test_msg( |
| CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize)); |
| int result = test::UDPSocketTestHelper::SendToSync(&server_socket, |
| client_addr, test_msg); |
| EXPECT_EQ(net::OK, result); |
| } |
| |
| receiver.WaitForReceivedResults(kDatagramCount); |
| EXPECT_EQ(kDatagramCount, receiver.results().size()); |
| |
| int i = 0; |
| for (const auto& result : receiver.results()) { |
| EXPECT_EQ(net::OK, result.net_error); |
| EXPECT_FALSE(result.src_addr); |
| EXPECT_EQ(CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize), |
| result.data.value()); |
| i++; |
| } |
| |
| // Tests that sending a message that is larger than the specified limit |
| // results in an early rejection. |
| std::vector<uint8_t> large_msg(64 * 1024, 1); |
| EXPECT_EQ(net::ERR_MSG_TOO_BIG, test::UDPSocketTestHelper::SendToSync( |
| &server_socket, client_addr, large_msg)); |
| } |
| |
| // Make sure passing an invalid net::IPEndPoint will be detected by |
| // serialization/deserialization in mojo. |
| TEST_F(UDPSocketTest, TestSendToInvalidAddress) { |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| mojom::UDPSocketPtr server_socket; |
| UDPSocket impl(mojo::MakeRequest(&server_socket), |
| std::move(receiver_interface_ptr)); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &server_socket, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &server_socket, server_addr, &server_addr)); |
| |
| std::vector<uint8_t> test_msg{1}; |
| std::vector<uint8_t> invalid_ip_addr{127, 0, 0, 0, 1}; |
| net::IPAddress ip_address(invalid_ip_addr.data(), invalid_ip_addr.size()); |
| EXPECT_FALSE(ip_address.IsValid()); |
| net::IPEndPoint invalid_addr(ip_address, 53); |
| server_socket->SendTo(invalid_addr, test_msg, |
| base::BindOnce([](int result) {})); |
| // Make sure that the pipe is broken upon processing |invalid_addr|. |
| base::RunLoop run_loop; |
| server_socket.set_connection_error_handler( |
| base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); }, |
| base::Unretained(&run_loop))); |
| run_loop.Run(); |
| } |
| |
| // Tests that it is legal for UDPSocketReceiver::OnReceive() to be called with |
| // 0 byte payload. |
| TEST_F(UDPSocketTest, TestReadZeroByte) { |
| test::UDPSocketReceiverImpl receiver; |
| mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver); |
| mojom::UDPSocketReceiverPtr receiver_interface_ptr; |
| receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr)); |
| |
| mojom::UDPSocketPtr socket_ptr; |
| UDPSocket impl(mojo::MakeRequest(&socket_ptr), |
| std::move(receiver_interface_ptr)); |
| |
| SetWrappedSocket(&impl, std::make_unique<ZeroByteReadUDPSocket>()); |
| |
| net::IPEndPoint server_addr(GetLocalHostWithAnyPort()); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::OpenSync( |
| &socket_ptr, server_addr.GetFamily())); |
| ASSERT_EQ(net::OK, test::UDPSocketTestHelper::BindSync( |
| &socket_ptr, server_addr, &server_addr)); |
| |
| socket_ptr->ReceiveMore(1); |
| |
| receiver.WaitForReceivedResults(1); |
| ASSERT_EQ(1u, receiver.results().size()); |
| |
| auto result = receiver.results()[0]; |
| EXPECT_EQ(net::OK, result.net_error); |
| EXPECT_TRUE(result.data); |
| EXPECT_EQ(std::vector<uint8_t>(), result.data.value()); |
| } |
| |
| } // namespace network |