|  | // Copyright (c) 2012 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/socket/udp_socket.h" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "starboard/types.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/containers/circular_deque.h" | 
|  | #include "base/location.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/weak_ptr.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/single_thread_task_runner.h" | 
|  | #include "base/threading/thread_task_runner_handle.h" | 
|  | #include "build/build_config.h" | 
|  | #include "net/base/io_buffer.h" | 
|  | #include "net/base/ip_address.h" | 
|  | #include "net/base/ip_endpoint.h" | 
|  | #include "net/base/net_errors.h" | 
|  | #include "net/base/network_interfaces.h" | 
|  | #include "net/base/test_completion_callback.h" | 
|  | #include "net/log/net_log_event_type.h" | 
|  | #include "net/log/net_log_source.h" | 
|  | #include "net/log/test_net_log.h" | 
|  | #include "net/log/test_net_log_entry.h" | 
|  | #include "net/log/test_net_log_util.h" | 
|  | #include "net/socket/socket_test_util.h" | 
|  | #include "net/socket/udp_client_socket.h" | 
|  | #include "net/socket/udp_server_socket.h" | 
|  | #include "net/test/gtest_util.h" | 
|  | #include "net/test/test_with_scoped_task_environment.h" | 
|  | #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "testing/platform_test.h" | 
|  |  | 
|  | #if defined(OS_ANDROID) | 
|  | #include "base/android/build_info.h" | 
|  | #include "net/android/network_change_notifier_factory_android.h" | 
|  | #include "net/base/network_change_notifier.h" | 
|  | #endif | 
|  |  | 
|  | #if defined(OS_IOS) | 
|  | #include <TargetConditionals.h> | 
|  | #endif | 
|  |  | 
|  | using net::test::IsError; | 
|  | using net::test::IsOk; | 
|  | using testing::Not; | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Creates an address from ip address and port and writes it to |*address|. | 
|  | bool CreateUDPAddress(const std::string& ip_str, | 
|  | uint16_t port, | 
|  | IPEndPoint* address) { | 
|  | IPAddress ip_address; | 
|  | if (!ip_address.AssignFromIPLiteral(ip_str)) | 
|  | return false; | 
|  |  | 
|  | *address = IPEndPoint(ip_address, port); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | class UDPSocketTest : public PlatformTest, public WithScopedTaskEnvironment { | 
|  | public: | 
|  | UDPSocketTest() : buffer_(base::MakeRefCounted<IOBufferWithSize>(kMaxRead)) {} | 
|  |  | 
|  | // Blocks until data is read from the socket. | 
|  | std::string RecvFromSocket(UDPServerSocket* socket) { | 
|  | TestCompletionCallback callback; | 
|  |  | 
|  | int rv = socket->RecvFrom( | 
|  | buffer_.get(), kMaxRead, &recv_from_address_, callback.callback()); | 
|  | rv = callback.GetResult(rv); | 
|  | if (rv < 0) | 
|  | return std::string(); | 
|  | return std::string(buffer_->data(), rv); | 
|  | } | 
|  |  | 
|  | // Sends UDP packet. | 
|  | // If |address| is specified, then it is used for the destination | 
|  | // to send to. Otherwise, will send to the last socket this server | 
|  | // received from. | 
|  | int SendToSocket(UDPServerSocket* socket, const std::string& msg) { | 
|  | return SendToSocket(socket, msg, recv_from_address_); | 
|  | } | 
|  |  | 
|  | int SendToSocket(UDPServerSocket* socket, | 
|  | std::string msg, | 
|  | const IPEndPoint& address) { | 
|  | scoped_refptr<StringIOBuffer> io_buffer = | 
|  | base::MakeRefCounted<StringIOBuffer>(msg); | 
|  | TestCompletionCallback callback; | 
|  | int rv = socket->SendTo(io_buffer.get(), io_buffer->size(), address, | 
|  | callback.callback()); | 
|  | return callback.GetResult(rv); | 
|  | } | 
|  |  | 
|  | std::string ReadSocket(UDPClientSocket* socket) { | 
|  | TestCompletionCallback callback; | 
|  |  | 
|  | int rv = socket->Read(buffer_.get(), kMaxRead, callback.callback()); | 
|  | rv = callback.GetResult(rv); | 
|  | if (rv < 0) | 
|  | return std::string(); | 
|  | return std::string(buffer_->data(), rv); | 
|  | } | 
|  |  | 
|  | // Writes specified message to the socket. | 
|  | int WriteSocket(UDPClientSocket* socket, const std::string& msg) { | 
|  | scoped_refptr<StringIOBuffer> io_buffer = | 
|  | base::MakeRefCounted<StringIOBuffer>(msg); | 
|  | TestCompletionCallback callback; | 
|  | int rv = socket->Write(io_buffer.get(), io_buffer->size(), | 
|  | callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | return callback.GetResult(rv); | 
|  | } | 
|  |  | 
|  | void WriteSocketIgnoreResult(UDPClientSocket* socket, | 
|  | const std::string& msg) { | 
|  | WriteSocket(socket, msg); | 
|  | } | 
|  |  | 
|  | // And again for a bare socket | 
|  | int SendToSocket(UDPSocket* socket, | 
|  | std::string msg, | 
|  | const IPEndPoint& address) { | 
|  | scoped_refptr<StringIOBuffer> io_buffer = new StringIOBuffer(msg); | 
|  | TestCompletionCallback callback; | 
|  | int rv = socket->SendTo(io_buffer.get(), io_buffer->size(), address, | 
|  | callback.callback()); | 
|  | return callback.GetResult(rv); | 
|  | } | 
|  |  | 
|  | // Run unit test for a connection test. | 
|  | // |use_nonblocking_io| is used to switch between overlapped and non-blocking | 
|  | // IO on Windows. It has no effect in other ports. | 
|  | void ConnectTest(bool use_nonblocking_io); | 
|  |  | 
|  | protected: | 
|  | static const int kMaxRead = 1024; | 
|  | scoped_refptr<IOBufferWithSize> buffer_; | 
|  | IPEndPoint recv_from_address_; | 
|  | }; | 
|  |  | 
|  | const int UDPSocketTest::kMaxRead; | 
|  |  | 
|  | void ReadCompleteCallback(int* result_out, base::Closure callback, int result) { | 
|  | *result_out = result; | 
|  | callback.Run(); | 
|  | } | 
|  |  | 
|  | void UDPSocketTest::ConnectTest(bool use_nonblocking_io) { | 
|  | const uint16_t kPort = 9999; | 
|  | std::string simple_message("hello world!"); | 
|  |  | 
|  | // Setup the server to listen. | 
|  | IPEndPoint server_address(IPAddress::IPv4Localhost(), kPort); | 
|  | TestNetLog server_log; | 
|  | std::unique_ptr<UDPServerSocket> server( | 
|  | new UDPServerSocket(&server_log, NetLogSource())); | 
|  | if (use_nonblocking_io) | 
|  | server->UseNonBlockingIO(); | 
|  | server->AllowAddressReuse(); | 
|  | int rv = server->Listen(server_address); | 
|  | ASSERT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Setup the client. | 
|  | TestNetLog client_log; | 
|  | auto client = std::make_unique<UDPClientSocket>(DatagramSocket::DEFAULT_BIND, | 
|  | &client_log, NetLogSource()); | 
|  | if (use_nonblocking_io) | 
|  | client->UseNonBlockingIO(); | 
|  |  | 
|  | rv = client->Connect(server_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Client sends to the server. | 
|  | rv = WriteSocket(client.get(), simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Server waits for message. | 
|  | std::string str = RecvFromSocket(server.get()); | 
|  | EXPECT_EQ(simple_message, str); | 
|  |  | 
|  | // Server echoes reply. | 
|  | rv = SendToSocket(server.get(), simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Client waits for response. | 
|  | str = ReadSocket(client.get()); | 
|  | EXPECT_EQ(simple_message, str); | 
|  |  | 
|  | // Test asynchronous read. Server waits for message. | 
|  | base::RunLoop run_loop; | 
|  | int read_result = 0; | 
|  | rv = server->RecvFrom( | 
|  | buffer_.get(), kMaxRead, &recv_from_address_, | 
|  | base::Bind(&ReadCompleteCallback, &read_result, run_loop.QuitClosure())); | 
|  | EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); | 
|  |  | 
|  | // Client sends to the server. | 
|  | base::ThreadTaskRunnerHandle::Get()->PostTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&UDPSocketTest::WriteSocketIgnoreResult, | 
|  | base::Unretained(this), client.get(), simple_message)); | 
|  | run_loop.Run(); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(read_result)); | 
|  | EXPECT_EQ(simple_message, std::string(buffer_->data(), read_result)); | 
|  |  | 
|  | // Delete sockets so they log their final events. | 
|  | server.reset(); | 
|  | client.reset(); | 
|  |  | 
|  | // Check the server's log. | 
|  | TestNetLogEntry::List server_entries; | 
|  | server_log.GetEntries(&server_entries); | 
|  | EXPECT_EQ(5u, server_entries.size()); | 
|  | EXPECT_TRUE( | 
|  | LogContainsBeginEvent(server_entries, 0, NetLogEventType::SOCKET_ALIVE)); | 
|  | EXPECT_TRUE(LogContainsEvent(server_entries, 1, | 
|  | NetLogEventType::UDP_BYTES_RECEIVED, | 
|  | NetLogEventPhase::NONE)); | 
|  | EXPECT_TRUE(LogContainsEvent(server_entries, 2, | 
|  | NetLogEventType::UDP_BYTES_SENT, | 
|  | NetLogEventPhase::NONE)); | 
|  | EXPECT_TRUE(LogContainsEvent(server_entries, 3, | 
|  | NetLogEventType::UDP_BYTES_RECEIVED, | 
|  | NetLogEventPhase::NONE)); | 
|  | EXPECT_TRUE( | 
|  | LogContainsEndEvent(server_entries, 4, NetLogEventType::SOCKET_ALIVE)); | 
|  |  | 
|  | // Check the client's log. | 
|  | TestNetLogEntry::List client_entries; | 
|  | client_log.GetEntries(&client_entries); | 
|  | EXPECT_EQ(7u, client_entries.size()); | 
|  | EXPECT_TRUE( | 
|  | LogContainsBeginEvent(client_entries, 0, NetLogEventType::SOCKET_ALIVE)); | 
|  | EXPECT_TRUE( | 
|  | LogContainsBeginEvent(client_entries, 1, NetLogEventType::UDP_CONNECT)); | 
|  | EXPECT_TRUE( | 
|  | LogContainsEndEvent(client_entries, 2, NetLogEventType::UDP_CONNECT)); | 
|  | EXPECT_TRUE(LogContainsEvent(client_entries, 3, | 
|  | NetLogEventType::UDP_BYTES_SENT, | 
|  | NetLogEventPhase::NONE)); | 
|  | EXPECT_TRUE(LogContainsEvent(client_entries, 4, | 
|  | NetLogEventType::UDP_BYTES_RECEIVED, | 
|  | NetLogEventPhase::NONE)); | 
|  | EXPECT_TRUE(LogContainsEvent(client_entries, 5, | 
|  | NetLogEventType::UDP_BYTES_SENT, | 
|  | NetLogEventPhase::NONE)); | 
|  | EXPECT_TRUE( | 
|  | LogContainsEndEvent(client_entries, 6, NetLogEventType::SOCKET_ALIVE)); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, Connect) { | 
|  | // The variable |use_nonblocking_io| has no effect in non-Windows ports. | 
|  | ConnectTest(false); | 
|  | } | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | TEST_F(UDPSocketTest, ConnectNonBlocking) { | 
|  | ConnectTest(true); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | TEST_F(UDPSocketTest, PartialRecv) { | 
|  | UDPServerSocket server_socket(nullptr, NetLogSource()); | 
|  | ASSERT_THAT(server_socket.Listen(IPEndPoint(IPAddress::IPv4Localhost(), 0)), | 
|  | IsOk()); | 
|  | IPEndPoint server_address; | 
|  | ASSERT_THAT(server_socket.GetLocalAddress(&server_address), IsOk()); | 
|  |  | 
|  | UDPClientSocket client_socket(DatagramSocket::DEFAULT_BIND, nullptr, | 
|  | NetLogSource()); | 
|  | ASSERT_THAT(client_socket.Connect(server_address), IsOk()); | 
|  |  | 
|  | std::string test_packet("hello world!"); | 
|  | ASSERT_EQ(static_cast<int>(test_packet.size()), | 
|  | WriteSocket(&client_socket, test_packet)); | 
|  |  | 
|  | TestCompletionCallback recv_callback; | 
|  |  | 
|  | // Read just 2 bytes. Read() is expected to return the first 2 bytes from the | 
|  | // packet and discard the rest. | 
|  | const int kPartialReadSize = 2; | 
|  | scoped_refptr<IOBuffer> buffer = | 
|  | base::MakeRefCounted<IOBuffer>(kPartialReadSize); | 
|  | int rv = | 
|  | server_socket.RecvFrom(buffer.get(), kPartialReadSize, | 
|  | &recv_from_address_, recv_callback.callback()); | 
|  | rv = recv_callback.GetResult(rv); | 
|  |  | 
|  | EXPECT_EQ(rv, ERR_MSG_TOO_BIG); | 
|  |  | 
|  | // Send a different message again. | 
|  | std::string second_packet("Second packet"); | 
|  | ASSERT_EQ(static_cast<int>(second_packet.size()), | 
|  | WriteSocket(&client_socket, second_packet)); | 
|  |  | 
|  | // Read whole packet now. | 
|  | std::string received = RecvFromSocket(&server_socket); | 
|  | EXPECT_EQ(second_packet, received); | 
|  | } | 
|  |  | 
|  | #if defined(OS_MACOSX) || defined(OS_ANDROID) || defined(OS_FUCHSIA) | 
|  | // - MacOS: requires root permissions on OSX 10.7+. | 
|  | // - Android: devices attached to testbots don't have default network, so | 
|  | // broadcasting to 255.255.255.255 returns error -109 (Address not reachable). | 
|  | // crbug.com/139144. | 
|  | // - Fuchsia: TODO(fuchsia): broadcast support is not implemented yet. | 
|  | #define MAYBE_LocalBroadcast DISABLED_LocalBroadcast | 
|  | #else | 
|  | #define MAYBE_LocalBroadcast LocalBroadcast | 
|  | #endif | 
|  | TEST_F(UDPSocketTest, MAYBE_LocalBroadcast) { | 
|  | const uint16_t kPort = 9999; | 
|  | std::string first_message("first message"), second_message("second message"); | 
|  |  | 
|  | IPEndPoint broadcast_address; | 
|  | ASSERT_TRUE(CreateUDPAddress("127.255.255.255", kPort, &broadcast_address)); | 
|  | IPEndPoint listen_address; | 
|  | ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &listen_address)); | 
|  |  | 
|  | TestNetLog server1_log, server2_log; | 
|  | std::unique_ptr<UDPServerSocket> server1( | 
|  | new UDPServerSocket(&server1_log, NetLogSource())); | 
|  | std::unique_ptr<UDPServerSocket> server2( | 
|  | new UDPServerSocket(&server2_log, NetLogSource())); | 
|  | server1->AllowAddressReuse(); | 
|  | server1->AllowBroadcast(); | 
|  | server2->AllowAddressReuse(); | 
|  | server2->AllowBroadcast(); | 
|  |  | 
|  | int rv = server1->Listen(listen_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  | rv = server2->Listen(listen_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | rv = SendToSocket(server1.get(), first_message, broadcast_address); | 
|  | ASSERT_EQ(static_cast<int>(first_message.size()), rv); | 
|  | std::string str = RecvFromSocket(server1.get()); | 
|  | ASSERT_EQ(first_message, str); | 
|  | str = RecvFromSocket(server2.get()); | 
|  | ASSERT_EQ(first_message, str); | 
|  |  | 
|  | rv = SendToSocket(server2.get(), second_message, broadcast_address); | 
|  | ASSERT_EQ(static_cast<int>(second_message.size()), rv); | 
|  | str = RecvFromSocket(server1.get()); | 
|  | ASSERT_EQ(second_message, str); | 
|  | str = RecvFromSocket(server2.get()); | 
|  | ASSERT_EQ(second_message, str); | 
|  | } | 
|  |  | 
|  | // ConnectRandomBind verifies RANDOM_BIND is handled correctly. It connects | 
|  | // 1000 sockets and then verifies that the allocated port numbers satisfy the | 
|  | // following 2 conditions: | 
|  | //  1. Range from min port value to max is greater than 10000. | 
|  | //  2. There is at least one port in the 5 buckets in the [min, max] range. | 
|  | // | 
|  | // These conditions are not enough to verify that the port numbers are truly | 
|  | // random, but they are enough to protect from most common non-random port | 
|  | // allocation strategies (e.g. counter, pool of available ports, etc.) False | 
|  | // positive result is theoretically possible, but its probability is negligible. | 
|  | TEST_F(UDPSocketTest, ConnectRandomBind) { | 
|  | const int kIterations = 1000; | 
|  |  | 
|  | std::vector<int> used_ports; | 
|  | for (int i = 0; i < kIterations; ++i) { | 
|  | UDPClientSocket socket(DatagramSocket::RANDOM_BIND, nullptr, | 
|  | NetLogSource()); | 
|  | EXPECT_THAT(socket.Connect(IPEndPoint(IPAddress::IPv4Localhost(), 53)), | 
|  | IsOk()); | 
|  |  | 
|  | IPEndPoint client_address; | 
|  | EXPECT_THAT(socket.GetLocalAddress(&client_address), IsOk()); | 
|  | used_ports.push_back(client_address.port()); | 
|  | } | 
|  |  | 
|  | int min_port = *std::min_element(used_ports.begin(), used_ports.end()); | 
|  | int max_port = *std::max_element(used_ports.begin(), used_ports.end()); | 
|  | int range = max_port - min_port + 1; | 
|  |  | 
|  | // Verify that the range of ports used by the random port allocator is wider | 
|  | // than 10k. Assuming that socket implementation limits port range to 16k | 
|  | // ports (default on Fuchsia) probability of false negative is below | 
|  | // 10^-200. | 
|  | static int kMinRange = 10000; | 
|  | EXPECT_GT(range, kMinRange); | 
|  |  | 
|  | static int kBuckets = 5; | 
|  | std::vector<int> bucket_sizes(kBuckets, 0); | 
|  | for (int port : used_ports) { | 
|  | bucket_sizes[(port - min_port) * kBuckets / range] += 1; | 
|  | } | 
|  |  | 
|  | // Verify that there is at least one value in each bucket. Probability of | 
|  | // false negative is below (kBuckets * (1 - 1 / kBuckets) ^ kIterations), | 
|  | // which is less than 10^-96. | 
|  | for (int size : bucket_sizes) { | 
|  | EXPECT_GT(size, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | #if defined(OS_FUCHSIA) | 
|  | // Currently the test fails on Fuchsia because netstack allows to connect IPv4 | 
|  | // socket to IPv6 address. This issue is tracked by NET-596. | 
|  | #define MAYBE_ConnectFail DISABLED_ConnectFail | 
|  | #else | 
|  | #define MAYBE_ConnectFail ConnectFail | 
|  | #endif | 
|  | TEST_F(UDPSocketTest, MAYBE_ConnectFail) { | 
|  | UDPSocket socket(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  |  | 
|  | EXPECT_THAT(socket.Open(ADDRESS_FAMILY_IPV4), IsOk()); | 
|  |  | 
|  | // Connect to an IPv6 address should fail since the socket was created for | 
|  | // IPv4. | 
|  | EXPECT_THAT(socket.Connect(net::IPEndPoint(IPAddress::IPv6Localhost(), 53)), | 
|  | Not(IsOk())); | 
|  |  | 
|  | // Make sure that UDPSocket actually closed the socket. | 
|  | EXPECT_FALSE(socket.is_connected()); | 
|  | } | 
|  |  | 
|  | // In this test, we verify that connect() on a socket will have the effect | 
|  | // of filtering reads on this socket only to data read from the destination | 
|  | // we connected to. | 
|  | // | 
|  | // The purpose of this test is that some documentation indicates that connect | 
|  | // binds the client's sends to send to a particular server endpoint, but does | 
|  | // not bind the client's reads to only be from that endpoint, and that we need | 
|  | // to always use recvfrom() to disambiguate. | 
|  | TEST_F(UDPSocketTest, VerifyConnectBindsAddr) { | 
|  | const uint16_t kPort1 = 9999; | 
|  | const uint16_t kPort2 = 10000; | 
|  | std::string simple_message("hello world!"); | 
|  | std::string foreign_message("BAD MESSAGE TO GET!!"); | 
|  |  | 
|  | // Setup the first server to listen. | 
|  | IPEndPoint server1_address(IPAddress::IPv4Localhost(), kPort1); | 
|  | UDPServerSocket server1(nullptr, NetLogSource()); | 
|  | server1.AllowAddressReuse(); | 
|  | int rv = server1.Listen(server1_address); | 
|  | ASSERT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Setup the second server to listen. | 
|  | IPEndPoint server2_address(IPAddress::IPv4Localhost(), kPort2); | 
|  | UDPServerSocket server2(nullptr, NetLogSource()); | 
|  | server2.AllowAddressReuse(); | 
|  | rv = server2.Listen(server2_address); | 
|  | ASSERT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Setup the client, connected to server 1. | 
|  | UDPClientSocket client(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | rv = client.Connect(server1_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Client sends to server1. | 
|  | rv = WriteSocket(&client, simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Server1 waits for message. | 
|  | std::string str = RecvFromSocket(&server1); | 
|  | EXPECT_EQ(simple_message, str); | 
|  |  | 
|  | // Get the client's address. | 
|  | IPEndPoint client_address; | 
|  | rv = client.GetLocalAddress(&client_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Server2 sends reply. | 
|  | rv = SendToSocket(&server2, foreign_message, | 
|  | client_address); | 
|  | EXPECT_EQ(foreign_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Server1 sends reply. | 
|  | rv = SendToSocket(&server1, simple_message, | 
|  | client_address); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Client waits for response. | 
|  | str = ReadSocket(&client); | 
|  | EXPECT_EQ(simple_message, str); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) { | 
|  | struct TestData { | 
|  | std::string remote_address; | 
|  | std::string local_address; | 
|  | bool may_fail; | 
|  | } tests[] = { | 
|  | { "127.0.00.1", "127.0.0.1", false }, | 
|  | { "::1", "::1", true }, | 
|  | #if !defined(OS_ANDROID) && !defined(OS_IOS) | 
|  | // Addresses below are disabled on Android. See crbug.com/161248 | 
|  | // They are also disabled on iOS. See https://crbug.com/523225 | 
|  | { "192.168.1.1", "127.0.0.1", false }, | 
|  | { "2001:db8:0::42", "::1", true }, | 
|  | #endif | 
|  | }; | 
|  | for (size_t i = 0; i < arraysize(tests); i++) { | 
|  | SCOPED_TRACE(std::string("Connecting from ") +  tests[i].local_address + | 
|  | std::string(" to ") + tests[i].remote_address); | 
|  |  | 
|  | IPAddress ip_address; | 
|  | EXPECT_TRUE(ip_address.AssignFromIPLiteral(tests[i].remote_address)); | 
|  | IPEndPoint remote_address(ip_address, 80); | 
|  | EXPECT_TRUE(ip_address.AssignFromIPLiteral(tests[i].local_address)); | 
|  | IPEndPoint local_address(ip_address, 80); | 
|  |  | 
|  | UDPClientSocket client(DatagramSocket::DEFAULT_BIND, nullptr, | 
|  | NetLogSource()); | 
|  | int rv = client.Connect(remote_address); | 
|  | if (tests[i].may_fail && rv == ERR_ADDRESS_UNREACHABLE) { | 
|  | // Connect() may return ERR_ADDRESS_UNREACHABLE for IPv6 | 
|  | // addresses if IPv6 is not configured. | 
|  | continue; | 
|  | } | 
|  |  | 
|  | EXPECT_LE(ERR_IO_PENDING, rv); | 
|  |  | 
|  | IPEndPoint fetched_local_address; | 
|  | rv = client.GetLocalAddress(&fetched_local_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // TODO(mbelshe): figure out how to verify the IP and port. | 
|  | //                The port is dynamically generated by the udp stack. | 
|  | //                The IP is the real IP of the client, not necessarily | 
|  | //                loopback. | 
|  | //EXPECT_EQ(local_address.address(), fetched_local_address.address()); | 
|  |  | 
|  | IPEndPoint fetched_remote_address; | 
|  | rv = client.GetPeerAddress(&fetched_remote_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | EXPECT_EQ(remote_address, fetched_remote_address); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, ServerGetLocalAddress) { | 
|  | IPEndPoint bind_address(IPAddress::IPv4Localhost(), 0); | 
|  | UDPServerSocket server(NULL, NetLogSource()); | 
|  | int rv = server.Listen(bind_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | IPEndPoint local_address; | 
|  | rv = server.GetLocalAddress(&local_address); | 
|  | EXPECT_EQ(rv, 0); | 
|  |  | 
|  | // Verify that port was allocated. | 
|  | EXPECT_GT(local_address.port(), 0); | 
|  | EXPECT_EQ(local_address.address(), bind_address.address()); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, ServerGetPeerAddress) { | 
|  | IPEndPoint bind_address(IPAddress::IPv4Localhost(), 0); | 
|  | UDPServerSocket server(NULL, NetLogSource()); | 
|  | int rv = server.Listen(bind_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | IPEndPoint peer_address; | 
|  | rv = server.GetPeerAddress(&peer_address); | 
|  | EXPECT_EQ(rv, ERR_SOCKET_NOT_CONNECTED); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, ClientSetDoNotFragment) { | 
|  | for (std::string ip : {"127.0.0.1", "::1"}) { | 
|  | UDPClientSocket client(DatagramSocket::DEFAULT_BIND, nullptr, | 
|  | NetLogSource()); | 
|  | IPAddress ip_address; | 
|  | EXPECT_TRUE(ip_address.AssignFromIPLiteral(ip)); | 
|  | IPEndPoint remote_address(ip_address, 80); | 
|  | int rv = client.Connect(remote_address); | 
|  | // May fail on IPv6 is IPv6 is not configured. | 
|  | if (ip_address.IsIPv6() && rv == ERR_ADDRESS_UNREACHABLE) | 
|  | return; | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | #if defined(OS_MACOSX) | 
|  | EXPECT_EQ(ERR_NOT_IMPLEMENTED, client.SetDoNotFragment()); | 
|  | #else | 
|  | rv = client.SetDoNotFragment(); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, ServerSetDoNotFragment) { | 
|  | for (std::string ip : {"127.0.0.1", "::1"}) { | 
|  | IPEndPoint bind_address; | 
|  | ASSERT_TRUE(CreateUDPAddress(ip, 0, &bind_address)); | 
|  | UDPServerSocket server(nullptr, NetLogSource()); | 
|  | int rv = server.Listen(bind_address); | 
|  | // May fail on IPv6 is IPv6 is not configure | 
|  | if (bind_address.address().IsIPv6() && | 
|  | (rv == ERR_ADDRESS_INVALID || rv == ERR_ADDRESS_UNREACHABLE)) | 
|  | return; | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | #if defined(OS_MACOSX) | 
|  | EXPECT_EQ(ERR_NOT_IMPLEMENTED, server.SetDoNotFragment()); | 
|  | #else | 
|  | rv = server.SetDoNotFragment(); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | // Close the socket while read is pending. | 
|  | TEST_F(UDPSocketTest, CloseWithPendingRead) { | 
|  | IPEndPoint bind_address(IPAddress::IPv4Localhost(), 0); | 
|  | UDPServerSocket server(NULL, NetLogSource()); | 
|  | int rv = server.Listen(bind_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | TestCompletionCallback callback; | 
|  | IPEndPoint from; | 
|  | rv = server.RecvFrom(buffer_.get(), kMaxRead, &from, callback.callback()); | 
|  | EXPECT_EQ(rv, ERR_IO_PENDING); | 
|  |  | 
|  | server.Close(); | 
|  |  | 
|  | EXPECT_FALSE(callback.have_result()); | 
|  | } | 
|  |  | 
|  | #if defined(OS_ANDROID) | 
|  | // Some Android devices do not support multicast socket. | 
|  | // The ones supporting multicast need WifiManager.MulitcastLock to enable it. | 
|  | // http://goo.gl/jjAk9 | 
|  | #define MAYBE_JoinMulticastGroup DISABLED_JoinMulticastGroup | 
|  | #else | 
|  | #define MAYBE_JoinMulticastGroup JoinMulticastGroup | 
|  | #endif  // defined(OS_ANDROID) | 
|  |  | 
|  | TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) { | 
|  | const uint16_t kPort = 9999; | 
|  | const char kGroup[] = "237.132.100.17"; | 
|  |  | 
|  | IPEndPoint bind_address; | 
|  | ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &bind_address)); | 
|  | IPAddress group_ip; | 
|  | EXPECT_TRUE(group_ip.AssignFromIPLiteral(kGroup)); | 
|  |  | 
|  | UDPSocket socket(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | EXPECT_THAT(socket.Open(bind_address.GetFamily()), IsOk()); | 
|  |  | 
|  | #if defined(OS_FUCHSIA) | 
|  | // Fuchsia currently doesn't support automatic interface selection for | 
|  | // multicast, so interface index needs to be set explicitly. | 
|  | // See https://fuchsia.atlassian.net/browse/NET-195 . | 
|  | NetworkInterfaceList interfaces; | 
|  | ASSERT_TRUE(GetNetworkList(&interfaces, 0)); | 
|  | ASSERT_FALSE(interfaces.empty()); | 
|  | EXPECT_THAT(socket.SetMulticastInterface(interfaces[0].interface_index), | 
|  | IsOk()); | 
|  | #endif  // defined(OS_FUCHSIA) | 
|  |  | 
|  | EXPECT_THAT(socket.Bind(bind_address), IsOk()); | 
|  | EXPECT_THAT(socket.JoinGroup(group_ip), IsOk()); | 
|  | // Joining group multiple times. | 
|  | EXPECT_NE(OK, socket.JoinGroup(group_ip)); | 
|  | EXPECT_THAT(socket.LeaveGroup(group_ip), IsOk()); | 
|  | // Leaving group multiple times. | 
|  | EXPECT_NE(OK, socket.LeaveGroup(group_ip)); | 
|  |  | 
|  | socket.Close(); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, MulticastOptions) { | 
|  | const uint16_t kPort = 9999; | 
|  | IPEndPoint bind_address; | 
|  | ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &bind_address)); | 
|  |  | 
|  | UDPSocket socket(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | // Before binding. | 
|  | EXPECT_THAT(socket.SetMulticastLoopbackMode(false), IsOk()); | 
|  | EXPECT_THAT(socket.SetMulticastLoopbackMode(true), IsOk()); | 
|  | EXPECT_THAT(socket.SetMulticastTimeToLive(0), IsOk()); | 
|  | EXPECT_THAT(socket.SetMulticastTimeToLive(3), IsOk()); | 
|  | EXPECT_NE(OK, socket.SetMulticastTimeToLive(-1)); | 
|  | EXPECT_THAT(socket.SetMulticastInterface(0), IsOk()); | 
|  |  | 
|  | EXPECT_THAT(socket.Open(bind_address.GetFamily()), IsOk()); | 
|  | EXPECT_THAT(socket.Bind(bind_address), IsOk()); | 
|  |  | 
|  | EXPECT_NE(OK, socket.SetMulticastLoopbackMode(false)); | 
|  | EXPECT_NE(OK, socket.SetMulticastTimeToLive(0)); | 
|  | EXPECT_NE(OK, socket.SetMulticastInterface(0)); | 
|  |  | 
|  | socket.Close(); | 
|  | } | 
|  |  | 
|  | // Checking that DSCP bits are set correctly is difficult, | 
|  | // but let's check that the code doesn't crash at least. | 
|  | TEST_F(UDPSocketTest, SetDSCP) { | 
|  | // Setup the server to listen. | 
|  | IPEndPoint bind_address; | 
|  | UDPSocket client(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | // We need a real IP, but we won't actually send anything to it. | 
|  | ASSERT_TRUE(CreateUDPAddress("8.8.8.8", 9999, &bind_address)); | 
|  | int rv = client.Open(bind_address.GetFamily()); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | rv = client.Connect(bind_address); | 
|  | if (rv != OK) { | 
|  | // Let's try localhost then. | 
|  | bind_address = IPEndPoint(IPAddress::IPv4Localhost(), 9999); | 
|  | rv = client.Connect(bind_address); | 
|  | } | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | client.SetDiffServCodePoint(DSCP_NO_CHANGE); | 
|  | client.SetDiffServCodePoint(DSCP_AF41); | 
|  | client.SetDiffServCodePoint(DSCP_DEFAULT); | 
|  | client.SetDiffServCodePoint(DSCP_CS2); | 
|  | client.SetDiffServCodePoint(DSCP_NO_CHANGE); | 
|  | client.SetDiffServCodePoint(DSCP_DEFAULT); | 
|  | client.Close(); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, TestBindToNetwork) { | 
|  | UDPSocket socket(DatagramSocket::RANDOM_BIND, nullptr, NetLogSource()); | 
|  | #if defined(OS_ANDROID) | 
|  | NetworkChangeNotifierFactoryAndroid ncn_factory; | 
|  | NetworkChangeNotifier::DisableForTest ncn_disable_for_test; | 
|  | std::unique_ptr<NetworkChangeNotifier> ncn(ncn_factory.CreateInstance()); | 
|  | #endif | 
|  | ASSERT_EQ(OK, socket.Open(ADDRESS_FAMILY_IPV4)); | 
|  | // Test unsuccessful binding, by attempting to bind to a bogus NetworkHandle. | 
|  | int rv = socket.BindToNetwork(65536); | 
|  | #if !defined(OS_ANDROID) | 
|  | EXPECT_EQ(ERR_NOT_IMPLEMENTED, rv); | 
|  | #else | 
|  | if (base::android::BuildInfo::GetInstance()->sdk_int() < | 
|  | base::android::SDK_VERSION_LOLLIPOP) { | 
|  | EXPECT_EQ(ERR_NOT_IMPLEMENTED, rv); | 
|  | } else if (base::android::BuildInfo::GetInstance()->sdk_int() >= | 
|  | base::android::SDK_VERSION_LOLLIPOP && | 
|  | base::android::BuildInfo::GetInstance()->sdk_int() < | 
|  | base::android::SDK_VERSION_MARSHMALLOW) { | 
|  | // On Lollipop, we assume if the user has a NetworkHandle that they must | 
|  | // have gotten it from a legitimate source, so if binding to the network | 
|  | // fails it's assumed to be because the network went away so | 
|  | // ERR_NETWORK_CHANGED is returned. In this test the network never existed | 
|  | // anyhow.  ConnectivityService.MAX_NET_ID is 65535, so 65536 won't be used. | 
|  | EXPECT_EQ(ERR_NETWORK_CHANGED, rv); | 
|  | } else if (base::android::BuildInfo::GetInstance()->sdk_int() >= | 
|  | base::android::SDK_VERSION_MARSHMALLOW) { | 
|  | // On Marshmallow and newer releases, the NetworkHandle is munged by | 
|  | // Network.getNetworkHandle() and 65536 isn't munged so it's rejected. | 
|  | EXPECT_EQ(ERR_INVALID_ARGUMENT, rv); | 
|  | } | 
|  |  | 
|  | if (base::android::BuildInfo::GetInstance()->sdk_int() >= | 
|  | base::android::SDK_VERSION_LOLLIPOP) { | 
|  | EXPECT_EQ( | 
|  | ERR_INVALID_ARGUMENT, | 
|  | socket.BindToNetwork(NetworkChangeNotifier::kInvalidNetworkHandle)); | 
|  |  | 
|  | // Test successful binding, if possible. | 
|  | EXPECT_TRUE(NetworkChangeNotifier::AreNetworkHandlesSupported()); | 
|  | NetworkChangeNotifier::NetworkHandle network_handle = | 
|  | NetworkChangeNotifier::GetDefaultNetwork(); | 
|  | if (network_handle != NetworkChangeNotifier::kInvalidNetworkHandle) { | 
|  | EXPECT_EQ(OK, socket.BindToNetwork(network_handle)); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const HANDLE kFakeHandle = (HANDLE)19; | 
|  | const QOS_FLOWID kFakeFlowId1 = (QOS_FLOWID)27; | 
|  | const QOS_FLOWID kFakeFlowId2 = (QOS_FLOWID)38; | 
|  |  | 
|  | class TestUDPSocketWin : public UDPSocketWin { | 
|  | public: | 
|  | TestUDPSocketWin(QwaveAPI& qos, | 
|  | DatagramSocket::BindType bind_type, | 
|  | net::NetLog* net_log, | 
|  | const net::NetLogSource& source) | 
|  | : UDPSocketWin(bind_type, net_log, source), qos_(qos) {} | 
|  |  | 
|  | // Overriding GetQwaveAPI causes the test class to use the injected mock | 
|  | // QwaveAPI instance instead of the singleton.  Ensure close is called in the | 
|  | // child destructor before our mock CloseHandle is uninstalled. | 
|  | ~TestUDPSocketWin() override { UDPSocketWin::Close(); } | 
|  |  | 
|  | QwaveAPI& GetQwaveAPI() override { return qos_; } | 
|  |  | 
|  | private: | 
|  | QwaveAPI& qos_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(TestUDPSocketWin); | 
|  | }; | 
|  |  | 
|  | class MockQwaveAPI : public QwaveAPI { | 
|  | public: | 
|  | bool qwave_supported() const override { return true; } | 
|  | MOCK_METHOD2(CreateHandle, BOOL(PQOS_VERSION version, PHANDLE handle)); | 
|  | MOCK_METHOD1(CloseHandle, BOOL(HANDLE handle)); | 
|  |  | 
|  | MOCK_METHOD6(AddSocketToFlow, | 
|  | BOOL(HANDLE handle, | 
|  | SOCKET socket, | 
|  | PSOCKADDR addr, | 
|  | QOS_TRAFFIC_TYPE traffic_type, | 
|  | DWORD flags, | 
|  | PQOS_FLOWID flow_id)); | 
|  |  | 
|  | MOCK_METHOD4( | 
|  | RemoveSocketFromFlow, | 
|  | BOOL(HANDLE handle, SOCKET socket, QOS_FLOWID flow_id, DWORD reserved)); | 
|  | MOCK_METHOD7(SetFlow, | 
|  | BOOL(HANDLE handle, | 
|  | QOS_FLOWID flow_id, | 
|  | QOS_SET_FLOW op, | 
|  | ULONG size, | 
|  | PVOID data, | 
|  | DWORD reserved, | 
|  | LPOVERLAPPED overlapped)); | 
|  | }; | 
|  |  | 
|  | std::unique_ptr<UDPSocket> OpenedDscpTestClient(QwaveAPI& qos, | 
|  | IPEndPoint bind_address) { | 
|  | auto client = std::make_unique<TestUDPSocketWin>( | 
|  | qos, DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | int rv = client->Open(bind_address.GetFamily()); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | return client; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<UDPSocket> ConnectedDscpTestClient(QwaveAPI& qos) { | 
|  | IPEndPoint bind_address; | 
|  | // We need a real IP, but we won't actually send anything to it. | 
|  | EXPECT_TRUE(CreateUDPAddress("8.8.8.8", 9999, &bind_address)); | 
|  | auto client = OpenedDscpTestClient(qos, bind_address); | 
|  | EXPECT_THAT(client->Connect(bind_address), IsOk()); | 
|  | return client; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<UDPSocket> UnconnectedDscpTestClient(QwaveAPI& qos) { | 
|  | IPEndPoint bind_address; | 
|  | EXPECT_TRUE(CreateUDPAddress("0.0.0.0", 9999, &bind_address)); | 
|  | auto client = OpenedDscpTestClient(qos, bind_address); | 
|  | EXPECT_THAT(client->Bind(bind_address), IsOk()); | 
|  | return client; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | using ::testing::_; | 
|  | using ::testing::Return; | 
|  | using ::testing::SetArgPointee; | 
|  |  | 
|  | TEST_F(UDPSocketTest, SetDSCPNoopIfPassedNoChange) { | 
|  | MockQwaveAPI qos; | 
|  | std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); | 
|  | EXPECT_THAT(client->SetDiffServCodePoint(DSCP_NO_CHANGE), IsOk()); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, SetDSCPFailsIfQOSHandleCanNotBeCreated) { | 
|  | MockQwaveAPI qos; | 
|  | EXPECT_CALL(qos, CreateHandle(_, _)).WillOnce(Return(false)); | 
|  | std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); | 
|  |  | 
|  | EXPECT_EQ(ERR_NOT_IMPLEMENTED, client->SetDiffServCodePoint(DSCP_AF41)); | 
|  | } | 
|  |  | 
|  | MATCHER_P(DscpPointee, dscp, "") { | 
|  | return *(DWORD*)arg == (DWORD)dscp; | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, SetDSCPCallsQwaveFunctions) { | 
|  | MockQwaveAPI qos; | 
|  | std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); | 
|  |  | 
|  | EXPECT_CALL(qos, CreateHandle(_, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true))); | 
|  | // AddSocketToFlow also sets flow_id, but we don't use that here | 
|  | EXPECT_CALL(qos, AddSocketToFlow(_, _, _, QOSTrafficTypeAudioVideo, _, _)) | 
|  | .WillOnce(Return(true)); | 
|  | EXPECT_CALL(qos, SetFlow(_, _, QOSSetOutgoingDSCPValue, _, | 
|  | DscpPointee(DSCP_AF41), _, _)); | 
|  | EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk()); | 
|  | EXPECT_CALL(qos, CloseHandle(kFakeHandle)); | 
|  | } | 
|  |  | 
|  | TEST_F(UDPSocketTest, SecondSetDSCPCallsQwaveFunctions) { | 
|  | MockQwaveAPI qos; | 
|  | std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); | 
|  |  | 
|  | EXPECT_CALL(qos, CreateHandle(_, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true))); | 
|  |  | 
|  | EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); | 
|  | EXPECT_CALL(qos, SetFlow(_, _, _, _, _, _, _)); | 
|  | EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk()); | 
|  |  | 
|  | // New dscp value should reset the flow. | 
|  | EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _)); | 
|  | EXPECT_CALL(qos, AddSocketToFlow(_, _, _, QOSTrafficTypeBestEffort, _, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId2), Return(true))); | 
|  | EXPECT_CALL(qos, SetFlow(_, _, QOSSetOutgoingDSCPValue, _, | 
|  | DscpPointee(DSCP_DEFAULT), _, _)); | 
|  | EXPECT_THAT(client->SetDiffServCodePoint(DSCP_DEFAULT), IsOk()); | 
|  |  | 
|  | // Called from DscpManager destructor. | 
|  | EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _)); | 
|  | EXPECT_CALL(qos, CloseHandle(kFakeHandle)); | 
|  | } | 
|  |  | 
|  | // TODO(zstein): Mocking out DscpManager might be simpler here | 
|  | // (just verify that DscpManager::Set and DscpManager::PrepareForSend are | 
|  | // called). | 
|  | TEST_F(UDPSocketTest, SendToCallsQwaveApis) { | 
|  | MockQwaveAPI qos; | 
|  | std::unique_ptr<UDPSocket> client = UnconnectedDscpTestClient(qos); | 
|  |  | 
|  | EXPECT_CALL(qos, CreateHandle(_, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true))); | 
|  | EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk()); | 
|  |  | 
|  | EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); | 
|  | EXPECT_CALL(qos, SetFlow(_, _, _, _, _, _, _)); | 
|  |  | 
|  | std::string simple_message("hello world"); | 
|  | IPEndPoint server_address(IPAddress::IPv4Localhost(), 9438); | 
|  | int rv = SendToSocket(client.get(), simple_message, server_address); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // TODO(zstein): Move to second test case (Qwave APIs called once per address) | 
|  | rv = SendToSocket(client.get(), simple_message, server_address); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // TODO(zstein): Move to third test case (Qwave APIs called for each | 
|  | // destination address). | 
|  | EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _)).WillOnce(Return(true)); | 
|  | IPEndPoint server_address2(IPAddress::IPv4Localhost(), 9439); | 
|  |  | 
|  | rv = SendToSocket(client.get(), simple_message, server_address2); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Called from DscpManager destructor. | 
|  | EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _)); | 
|  | EXPECT_CALL(qos, CloseHandle(kFakeHandle)); | 
|  | } | 
|  |  | 
|  | class DscpManagerTest : public testing::Test { | 
|  | protected: | 
|  | DscpManagerTest() : dscp_manager_(qos_, INVALID_SOCKET, (HANDLE)0) { | 
|  | CreateUDPAddress("1.2.3.4", 9001, &address1_); | 
|  | CreateUDPAddress("1234:5678:90ab:cdef:1234:5678:90ab:cdef", 9002, | 
|  | &address2_); | 
|  | } | 
|  |  | 
|  | MockQwaveAPI qos_; | 
|  | DscpManager dscp_manager_; | 
|  |  | 
|  | IPEndPoint address1_; | 
|  | IPEndPoint address2_; | 
|  | }; | 
|  |  | 
|  | TEST_F(DscpManagerTest, PrepareForSendIsNoopIfNoSet) { | 
|  | dscp_manager_.PrepareForSend(address1_); | 
|  | } | 
|  |  | 
|  | TEST_F(DscpManagerTest, PrepareForSendCallsQwaveApisAfterSet) { | 
|  | dscp_manager_.Set(DSCP_CS2); | 
|  |  | 
|  | // AddSocketToFlow should be called for each address. | 
|  | EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))) | 
|  | .WillOnce(Return(true)); | 
|  | // SetFlow should only be called when the flow is first created. | 
|  | EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); | 
|  | dscp_manager_.PrepareForSend(address1_); | 
|  | EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)).Times(0); | 
|  | dscp_manager_.PrepareForSend(address2_); | 
|  |  | 
|  | // Called from DscpManager destructor. | 
|  | EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, _, _)); | 
|  | } | 
|  |  | 
|  | TEST_F(DscpManagerTest, PrepareForSendCallsQwaveApisOncePerAddress) { | 
|  | dscp_manager_.Set(DSCP_CS2); | 
|  |  | 
|  | EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); | 
|  | EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); | 
|  | dscp_manager_.PrepareForSend(address1_); | 
|  | EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)).Times(0); | 
|  | EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)).Times(0); | 
|  | dscp_manager_.PrepareForSend(address1_); | 
|  |  | 
|  | // Called from DscpManager destructor. | 
|  | EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, _, _)); | 
|  | } | 
|  |  | 
|  | TEST_F(DscpManagerTest, SetDestroysExistingFlowAndResetsPrepareState) { | 
|  | dscp_manager_.Set(DSCP_CS2); | 
|  | EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); | 
|  | EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); | 
|  | dscp_manager_.PrepareForSend(address1_); | 
|  |  | 
|  | // Calling Set should destroy the existing flow. | 
|  | // TODO(zstein): Verify that RemoveSocketFromFlow with no address | 
|  | // destroys the flow for all destinations. | 
|  | EXPECT_CALL(qos_, RemoveSocketFromFlow(_, NULL, kFakeFlowId1, _)); | 
|  | dscp_manager_.Set(DSCP_CS5); | 
|  |  | 
|  | EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) | 
|  | .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId2), Return(true))); | 
|  | EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); | 
|  | dscp_manager_.PrepareForSend(address1_); | 
|  |  | 
|  | // Called from DscpManager destructor. | 
|  | EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, kFakeFlowId2, _)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | TEST_F(UDPSocketTest, ReadWithSocketOptimization) { | 
|  | const uint16_t kPort = 10000; | 
|  | std::string simple_message("hello world!"); | 
|  |  | 
|  | // Setup the server to listen. | 
|  | IPEndPoint server_address(IPAddress::IPv4Localhost(), kPort); | 
|  | UDPServerSocket server(NULL, NetLogSource()); | 
|  | server.AllowAddressReuse(); | 
|  | int rv = server.Listen(server_address); | 
|  | ASSERT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Setup the client, enable experimental optimization and connected to the | 
|  | // server. | 
|  | UDPClientSocket client(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | client.EnableRecvOptimization(); | 
|  | rv = client.Connect(server_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Get the client's address. | 
|  | IPEndPoint client_address; | 
|  | rv = client.GetLocalAddress(&client_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Server sends the message to the client. | 
|  | rv = SendToSocket(&server, simple_message, client_address); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Client receives the message. | 
|  | std::string str = ReadSocket(&client); | 
|  | EXPECT_EQ(simple_message, str); | 
|  |  | 
|  | server.Close(); | 
|  | client.Close(); | 
|  | } | 
|  |  | 
|  | // Tests that read from a socket correctly returns | 
|  | // |ERR_MSG_TOO_BIG| when the buffer is too small and | 
|  | // returns the actual message when it fits the buffer. | 
|  | // For the optimized path, the buffer size should be at least | 
|  | // 1 byte greater than the message. | 
|  | TEST_F(UDPSocketTest, ReadWithSocketOptimizationTruncation) { | 
|  | const uint16_t kPort = 10000; | 
|  | std::string too_long_message(kMaxRead + 1, 'A'); | 
|  | std::string right_length_message(kMaxRead - 1, 'B'); | 
|  | std::string exact_length_message(kMaxRead, 'C'); | 
|  |  | 
|  | // Setup the server to listen. | 
|  | IPEndPoint server_address(IPAddress::IPv4Localhost(), kPort); | 
|  | UDPServerSocket server(NULL, NetLogSource()); | 
|  | server.AllowAddressReuse(); | 
|  | int rv = server.Listen(server_address); | 
|  | ASSERT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Setup the client, enable experimental optimization and connected to the | 
|  | // server. | 
|  | UDPClientSocket client(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | client.EnableRecvOptimization(); | 
|  | rv = client.Connect(server_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Get the client's address. | 
|  | IPEndPoint client_address; | 
|  | rv = client.GetLocalAddress(&client_address); | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  |  | 
|  | // Send messages to the client. | 
|  | rv = SendToSocket(&server, too_long_message, client_address); | 
|  | EXPECT_EQ(too_long_message.length(), static_cast<size_t>(rv)); | 
|  | rv = SendToSocket(&server, right_length_message, client_address); | 
|  | EXPECT_EQ(right_length_message.length(), static_cast<size_t>(rv)); | 
|  | rv = SendToSocket(&server, exact_length_message, client_address); | 
|  | EXPECT_EQ(exact_length_message.length(), static_cast<size_t>(rv)); | 
|  |  | 
|  | // Client receives the messages. | 
|  |  | 
|  | // 1. The first message is |too_long_message|. Its size exceeds the buffer. | 
|  | // In that case, the client is expected to get |ERR_MSG_TOO_BIG| when the | 
|  | // data is read. | 
|  | TestCompletionCallback callback; | 
|  | rv = client.Read(buffer_.get(), kMaxRead, callback.callback()); | 
|  | rv = callback.GetResult(rv); | 
|  | EXPECT_EQ(ERR_MSG_TOO_BIG, rv); | 
|  |  | 
|  | // 2. The second message is |right_length_message|. Its size is | 
|  | // one byte smaller than the size of the buffer. In that case, the client | 
|  | // is expected to read the whole message successfully. | 
|  | rv = client.Read(buffer_.get(), kMaxRead, callback.callback()); | 
|  | rv = callback.GetResult(rv); | 
|  | EXPECT_EQ(static_cast<int>(right_length_message.length()), rv); | 
|  | EXPECT_EQ(right_length_message, std::string(buffer_->data(), rv)); | 
|  |  | 
|  | // 3. The third message is |exact_length_message|. Its size is equal to | 
|  | // the read buffer size. In that case, the client expects to get | 
|  | // |ERR_MSG_TOO_BIG| when the socket is read. Internally, the optimized | 
|  | // path uses read() system call that requires one extra byte to detect | 
|  | // truncated messages; therefore, messages that fill the buffer exactly | 
|  | // are considered truncated. | 
|  | // The optimization is only enabled on POSIX platforms. On Windows, | 
|  | // the optimization is turned off; therefore, the client | 
|  | // should be able to read the whole message without encountering | 
|  | // |ERR_MSG_TOO_BIG|. | 
|  | rv = client.Read(buffer_.get(), kMaxRead, callback.callback()); | 
|  | rv = callback.GetResult(rv); | 
|  | #if defined(OS_POSIX) | 
|  | EXPECT_EQ(ERR_MSG_TOO_BIG, rv); | 
|  | #else | 
|  | EXPECT_EQ(static_cast<int>(exact_length_message.length()), rv); | 
|  | EXPECT_EQ(exact_length_message, std::string(buffer_->data(), rv)); | 
|  | #endif | 
|  | server.Close(); | 
|  | client.Close(); | 
|  | } | 
|  |  | 
|  | // On Android, where socket tagging is supported, verify that UDPSocket::Tag | 
|  | // works as expected. | 
|  | #if defined(OS_ANDROID) | 
|  | TEST_F(UDPSocketTest, Tag) { | 
|  | UDPServerSocket server(nullptr, NetLogSource()); | 
|  | ASSERT_THAT(server.Listen(IPEndPoint(IPAddress::IPv4Localhost(), 0)), IsOk()); | 
|  | IPEndPoint server_address; | 
|  | ASSERT_THAT(server.GetLocalAddress(&server_address), IsOk()); | 
|  |  | 
|  | UDPClientSocket client(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); | 
|  | ASSERT_THAT(client.Connect(server_address), IsOk()); | 
|  |  | 
|  | // Verify UDP packets are tagged and counted properly. | 
|  | int32_t tag_val1 = 0x12345678; | 
|  | uint64_t old_traffic = GetTaggedBytes(tag_val1); | 
|  | SocketTag tag1(SocketTag::UNSET_UID, tag_val1); | 
|  | client.ApplySocketTag(tag1); | 
|  | // Client sends to the server. | 
|  | std::string simple_message("hello world!"); | 
|  | int rv = WriteSocket(&client, simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  | // Server waits for message. | 
|  | std::string str = RecvFromSocket(&server); | 
|  | EXPECT_EQ(simple_message, str); | 
|  | // Server echoes reply. | 
|  | rv = SendToSocket(&server, simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  | // Client waits for response. | 
|  | str = ReadSocket(&client); | 
|  | EXPECT_EQ(simple_message, str); | 
|  | EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); | 
|  |  | 
|  | // Verify socket can be retagged with a new value and the current process's | 
|  | // UID. | 
|  | int32_t tag_val2 = 0x87654321; | 
|  | old_traffic = GetTaggedBytes(tag_val2); | 
|  | SocketTag tag2(getuid(), tag_val2); | 
|  | client.ApplySocketTag(tag2); | 
|  | // Client sends to the server. | 
|  | rv = WriteSocket(&client, simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  | // Server waits for message. | 
|  | str = RecvFromSocket(&server); | 
|  | EXPECT_EQ(simple_message, str); | 
|  | // Server echoes reply. | 
|  | rv = SendToSocket(&server, simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  | // Client waits for response. | 
|  | str = ReadSocket(&client); | 
|  | EXPECT_EQ(simple_message, str); | 
|  | EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); | 
|  |  | 
|  | // Verify socket can be retagged with a new value and the current process's | 
|  | // UID. | 
|  | old_traffic = GetTaggedBytes(tag_val1); | 
|  | client.ApplySocketTag(tag1); | 
|  | // Client sends to the server. | 
|  | rv = WriteSocket(&client, simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  | // Server waits for message. | 
|  | str = RecvFromSocket(&server); | 
|  | EXPECT_EQ(simple_message, str); | 
|  | // Server echoes reply. | 
|  | rv = SendToSocket(&server, simple_message); | 
|  | EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); | 
|  | // Client waits for response. | 
|  | str = ReadSocket(&client); | 
|  | EXPECT_EQ(simple_message, str); | 
|  | EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | }  // namespace net |