| // 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/udp/udp_client_socket.h" |
| #include "net/udp/udp_server_socket.h" |
| |
| #include "base/basictypes.h" |
| #include "base/bind.h" |
| #include "base/metrics/histogram.h" |
| #include "base/stl_util.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/ip_endpoint.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/net_log_unittest.h" |
| #include "net/base/net_test_suite.h" |
| #include "net/base/net_util.h" |
| #include "net/base/test_completion_callback.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/platform_test.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| class UDPSocketTest : public PlatformTest { |
| public: |
| UDPSocketTest() |
| : buffer_(new IOBufferWithSize(kMaxRead)) { |
| } |
| |
| // Blocks until data is read from the socket. |
| std::string RecvFromSocket(UDPServerSocket* socket) { |
| TestCompletionCallback callback; |
| |
| int rv = socket->RecvFrom(buffer_, kMaxRead, &recv_from_address_, |
| callback.callback()); |
| if (rv == ERR_IO_PENDING) |
| rv = callback.WaitForResult(); |
| if (rv < 0) |
| return ""; // error! |
| return std::string(buffer_->data(), rv); |
| } |
| |
| // Loop until |msg| has been written to the socket or until an |
| // error occurs. |
| // 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, std::string msg) { |
| return SendToSocket(socket, msg, recv_from_address_); |
| } |
| |
| int SendToSocket(UDPServerSocket* socket, |
| std::string msg, |
| const IPEndPoint& address) { |
| TestCompletionCallback callback; |
| |
| int length = msg.length(); |
| scoped_refptr<StringIOBuffer> io_buffer(new StringIOBuffer(msg)); |
| scoped_refptr<DrainableIOBuffer> buffer( |
| new DrainableIOBuffer(io_buffer, length)); |
| |
| int bytes_sent = 0; |
| while (buffer->BytesRemaining()) { |
| int rv = socket->SendTo(buffer, buffer->BytesRemaining(), |
| address, callback.callback()); |
| if (rv == ERR_IO_PENDING) |
| rv = callback.WaitForResult(); |
| if (rv <= 0) |
| return bytes_sent > 0 ? bytes_sent : rv; |
| bytes_sent += rv; |
| buffer->DidConsume(rv); |
| } |
| return bytes_sent; |
| } |
| |
| std::string ReadSocket(UDPClientSocket* socket) { |
| TestCompletionCallback callback; |
| |
| int rv = socket->Read(buffer_, kMaxRead, callback.callback()); |
| if (rv == ERR_IO_PENDING) |
| rv = callback.WaitForResult(); |
| if (rv < 0) |
| return ""; // error! |
| return std::string(buffer_->data(), rv); |
| } |
| |
| // Loop until |msg| has been written to the socket or until an |
| // error occurs. |
| int WriteSocket(UDPClientSocket* socket, std::string msg) { |
| TestCompletionCallback callback; |
| |
| int length = msg.length(); |
| scoped_refptr<StringIOBuffer> io_buffer(new StringIOBuffer(msg)); |
| scoped_refptr<DrainableIOBuffer> buffer( |
| new DrainableIOBuffer(io_buffer, length)); |
| |
| int bytes_sent = 0; |
| while (buffer->BytesRemaining()) { |
| int rv = socket->Write(buffer, buffer->BytesRemaining(), |
| callback.callback()); |
| if (rv == ERR_IO_PENDING) |
| rv = callback.WaitForResult(); |
| if (rv <= 0) |
| return bytes_sent > 0 ? bytes_sent : rv; |
| bytes_sent += rv; |
| buffer->DidConsume(rv); |
| } |
| return bytes_sent; |
| } |
| |
| protected: |
| static const int kMaxRead = 1024; |
| scoped_refptr<IOBufferWithSize> buffer_; |
| IPEndPoint recv_from_address_; |
| }; |
| |
| // Creates and address from an ip/port and returns it in |address|. |
| void CreateUDPAddress(std::string ip_str, int port, IPEndPoint* address) { |
| IPAddressNumber ip_number; |
| bool rv = ParseIPLiteralToNumber(ip_str, &ip_number); |
| if (!rv) |
| return; |
| *address = IPEndPoint(ip_number, port); |
| } |
| |
| TEST_F(UDPSocketTest, Connect) { |
| const int kPort = 9999; |
| std::string simple_message("hello world!"); |
| |
| // Setup the server to listen. |
| IPEndPoint bind_address; |
| CreateUDPAddress("127.0.0.1", kPort, &bind_address); |
| CapturingNetLog server_log; |
| scoped_ptr<UDPServerSocket> server( |
| new UDPServerSocket(&server_log, NetLog::Source())); |
| server->AllowAddressReuse(); |
| int rv = server->Listen(bind_address); |
| ASSERT_EQ(OK, rv); |
| |
| // Setup the client. |
| IPEndPoint server_address; |
| CreateUDPAddress("127.0.0.1", kPort, &server_address); |
| CapturingNetLog client_log; |
| scoped_ptr<UDPClientSocket> client( |
| new UDPClientSocket(DatagramSocket::DEFAULT_BIND, |
| RandIntCallback(), |
| &client_log, |
| NetLog::Source())); |
| rv = client->Connect(server_address); |
| EXPECT_EQ(OK, rv); |
| |
| // 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()); |
| DCHECK(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()); |
| DCHECK(simple_message == str); |
| |
| // Delete sockets so they log their final events. |
| server.reset(); |
| client.reset(); |
| |
| // Check the server's log. |
| CapturingNetLog::CapturedEntryList server_entries; |
| server_log.GetEntries(&server_entries); |
| EXPECT_EQ(4u, server_entries.size()); |
| EXPECT_TRUE(LogContainsBeginEvent( |
| server_entries, 0, NetLog::TYPE_SOCKET_ALIVE)); |
| EXPECT_TRUE(LogContainsEvent( |
| server_entries, 1, NetLog::TYPE_UDP_BYTES_RECEIVED, NetLog::PHASE_NONE)); |
| EXPECT_TRUE(LogContainsEvent( |
| server_entries, 2, NetLog::TYPE_UDP_BYTES_SENT, NetLog::PHASE_NONE)); |
| EXPECT_TRUE(LogContainsEndEvent( |
| server_entries, 3, NetLog::TYPE_SOCKET_ALIVE)); |
| |
| // Check the client's log. |
| CapturingNetLog::CapturedEntryList client_entries; |
| client_log.GetEntries(&client_entries); |
| EXPECT_EQ(6u, client_entries.size()); |
| EXPECT_TRUE(LogContainsBeginEvent( |
| client_entries, 0, NetLog::TYPE_SOCKET_ALIVE)); |
| EXPECT_TRUE(LogContainsBeginEvent( |
| client_entries, 1, NetLog::TYPE_UDP_CONNECT)); |
| EXPECT_TRUE(LogContainsEndEvent( |
| client_entries, 2, NetLog::TYPE_UDP_CONNECT)); |
| EXPECT_TRUE(LogContainsEvent( |
| client_entries, 3, NetLog::TYPE_UDP_BYTES_SENT, NetLog::PHASE_NONE)); |
| EXPECT_TRUE(LogContainsEvent( |
| client_entries, 4, NetLog::TYPE_UDP_BYTES_RECEIVED, NetLog::PHASE_NONE)); |
| EXPECT_TRUE(LogContainsEndEvent( |
| client_entries, 5, NetLog::TYPE_SOCKET_ALIVE)); |
| } |
| |
| #if defined(OS_MACOSX) |
| // UDPSocketPrivate_Broadcast is disabled for OSX because it requires |
| // root permissions on OSX 10.7+. |
| TEST_F(UDPSocketTest, DISABLED_Broadcast) { |
| #elif defined(OS_ANDROID) |
| // It is also disabled for Android because it is extremely flaky. |
| // The first call to SendToSocket returns -109 (Address not reachable) |
| // in some unpredictable cases. crbug.com/139144. |
| TEST_F(UDPSocketTest, DISABLED_Broadcast) { |
| #else |
| TEST_F(UDPSocketTest, Broadcast) { |
| #endif |
| const int kPort = 9999; |
| std::string first_message("first message"), second_message("second message"); |
| |
| IPEndPoint broadcast_address; |
| CreateUDPAddress("255.255.255.255", kPort, &broadcast_address); |
| IPEndPoint listen_address; |
| CreateUDPAddress("0.0.0.0", kPort, &listen_address); |
| |
| CapturingNetLog server1_log, server2_log; |
| scoped_ptr<UDPServerSocket> server1( |
| new UDPServerSocket(&server1_log, NetLog::Source())); |
| scoped_ptr<UDPServerSocket> server2( |
| new UDPServerSocket(&server2_log, NetLog::Source())); |
| server1->AllowAddressReuse(); |
| server1->AllowBroadcast(); |
| server2->AllowAddressReuse(); |
| server2->AllowBroadcast(); |
| |
| int rv = server1->Listen(listen_address); |
| EXPECT_EQ(OK, rv); |
| rv = server2->Listen(listen_address); |
| EXPECT_EQ(OK, rv); |
| |
| 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); |
| } |
| |
| // In this test, we verify that random binding logic works, which attempts |
| // to bind to a random port and returns if succeeds, otherwise retries for |
| // |kBindRetries| number of times. |
| |
| // To generate the scenario, we first create |kBindRetries| number of |
| // UDPClientSockets with default binding policy and connect to the same |
| // peer and save the used port numbers. Then we get rid of the last |
| // socket, making sure that the local port it was bound to is available. |
| // Finally, we create a socket with random binding policy, passing it a |
| // test PRNG that would serve used port numbers in the array, one after |
| // another. At the end, we make sure that the test socket was bound to the |
| // port that became available after deleting the last socket with default |
| // binding policy. |
| |
| // We do not test the randomness of bound ports, but that we are using |
| // passed in PRNG correctly, thus, it's the duty of PRNG to produce strong |
| // random numbers. |
| static const int kBindRetries = 10; |
| |
| class TestPrng { |
| public: |
| explicit TestPrng(const std::deque<int>& numbers) : numbers_(numbers) {} |
| int GetNext(int /* min */, int /* max */) { |
| DCHECK(!numbers_.empty()); |
| int rv = numbers_.front(); |
| numbers_.pop_front(); |
| return rv; |
| } |
| private: |
| std::deque<int> numbers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestPrng); |
| }; |
| |
| #if defined(OS_ANDROID) |
| // Disabled on Android for lack of 192.168.1.13. crbug.com/161245 |
| TEST_F(UDPSocketTest, DISABLED_ConnectRandomBind) { |
| #else |
| TEST_F(UDPSocketTest, ConnectRandomBind) { |
| #endif |
| std::vector<UDPClientSocket*> sockets; |
| IPEndPoint peer_address; |
| CreateUDPAddress("192.168.1.13", 53, &peer_address); |
| |
| // Create and connect sockets and save port numbers. |
| std::deque<int> used_ports; |
| for (int i = 0; i < kBindRetries; ++i) { |
| UDPClientSocket* socket = |
| new UDPClientSocket(DatagramSocket::DEFAULT_BIND, |
| RandIntCallback(), |
| NULL, |
| NetLog::Source()); |
| sockets.push_back(socket); |
| EXPECT_EQ(OK, socket->Connect(peer_address)); |
| |
| IPEndPoint client_address; |
| EXPECT_EQ(OK, socket->GetLocalAddress(&client_address)); |
| used_ports.push_back(client_address.port()); |
| } |
| |
| // Free the last socket, its local port is still in |used_ports|. |
| delete sockets.back(); |
| sockets.pop_back(); |
| |
| TestPrng test_prng(used_ports); |
| RandIntCallback rand_int_cb = |
| base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng)); |
| |
| // Create a socket with random binding policy and connect. |
| scoped_ptr<UDPClientSocket> test_socket( |
| new UDPClientSocket(DatagramSocket::RANDOM_BIND, |
| rand_int_cb, |
| NULL, |
| NetLog::Source())); |
| EXPECT_EQ(OK, test_socket->Connect(peer_address)); |
| |
| // Make sure that the last port number in the |used_ports| was used. |
| IPEndPoint client_address; |
| EXPECT_EQ(OK, test_socket->GetLocalAddress(&client_address)); |
| EXPECT_EQ(used_ports.back(), client_address.port()); |
| |
| STLDeleteElements(&sockets); |
| } |
| |
| // 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 int kPort1 = 9999; |
| const int kPort2 = 10000; |
| std::string simple_message("hello world!"); |
| std::string foreign_message("BAD MESSAGE TO GET!!"); |
| |
| // Setup the first server to listen. |
| IPEndPoint bind_address; |
| CreateUDPAddress("127.0.0.1", kPort1, &bind_address); |
| UDPServerSocket server1(NULL, NetLog::Source()); |
| server1.AllowAddressReuse(); |
| int rv = server1.Listen(bind_address); |
| ASSERT_EQ(OK, rv); |
| |
| // Setup the second server to listen. |
| CreateUDPAddress("127.0.0.1", kPort2, &bind_address); |
| UDPServerSocket server2(NULL, NetLog::Source()); |
| server2.AllowAddressReuse(); |
| rv = server2.Listen(bind_address); |
| ASSERT_EQ(OK, rv); |
| |
| // Setup the client, connected to server 1. |
| IPEndPoint server_address; |
| CreateUDPAddress("127.0.0.1", kPort1, &server_address); |
| UDPClientSocket client(DatagramSocket::DEFAULT_BIND, |
| RandIntCallback(), |
| NULL, |
| NetLog::Source()); |
| rv = client.Connect(server_address); |
| EXPECT_EQ(OK, rv); |
| |
| // 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); |
| DCHECK(simple_message == str); |
| |
| // Get the client's address. |
| IPEndPoint client_address; |
| rv = client.GetLocalAddress(&client_address); |
| EXPECT_EQ(OK, rv); |
| |
| // 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); |
| DCHECK(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) |
| // Addresses below are disabled on Android. See crbug.com/161248 |
| { "192.168.1.1", "127.0.0.1", false }, |
| { "2001:db8:0::42", "::1", true }, |
| #endif |
| }; |
| for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); i++) { |
| SCOPED_TRACE(std::string("Connecting from ") + tests[i].local_address + |
| std::string(" to ") + tests[i].remote_address); |
| |
| IPAddressNumber ip_number; |
| ParseIPLiteralToNumber(tests[i].remote_address, &ip_number); |
| IPEndPoint remote_address(ip_number, 80); |
| ParseIPLiteralToNumber(tests[i].local_address, &ip_number); |
| IPEndPoint local_address(ip_number, 80); |
| |
| UDPClientSocket client(DatagramSocket::DEFAULT_BIND, |
| RandIntCallback(), |
| NULL, |
| NetLog::Source()); |
| 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_EQ(OK, rv); |
| |
| // 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_EQ(OK, rv); |
| |
| EXPECT_EQ(remote_address, fetched_remote_address); |
| } |
| } |
| |
| TEST_F(UDPSocketTest, ServerGetLocalAddress) { |
| IPEndPoint bind_address; |
| CreateUDPAddress("127.0.0.1", 0, &bind_address); |
| UDPServerSocket server(NULL, NetLog::Source()); |
| int rv = server.Listen(bind_address); |
| EXPECT_EQ(OK, rv); |
| |
| 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; |
| CreateUDPAddress("127.0.0.1", 0, &bind_address); |
| UDPServerSocket server(NULL, NetLog::Source()); |
| int rv = server.Listen(bind_address); |
| EXPECT_EQ(OK, rv); |
| |
| IPEndPoint peer_address; |
| rv = server.GetPeerAddress(&peer_address); |
| EXPECT_EQ(rv, ERR_SOCKET_NOT_CONNECTED); |
| } |
| |
| // Close the socket while read is pending. |
| TEST_F(UDPSocketTest, CloseWithPendingRead) { |
| IPEndPoint bind_address; |
| CreateUDPAddress("127.0.0.1", 0, &bind_address); |
| UDPServerSocket server(NULL, NetLog::Source()); |
| int rv = server.Listen(bind_address); |
| EXPECT_EQ(OK, rv); |
| |
| TestCompletionCallback callback; |
| IPEndPoint from; |
| rv = server.RecvFrom(buffer_, kMaxRead, &from, callback.callback()); |
| EXPECT_EQ(rv, ERR_IO_PENDING); |
| |
| server.Close(); |
| |
| EXPECT_FALSE(callback.have_result()); |
| } |
| |
| } // namespace |
| |
| } // namespace net |