1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "extensions/browser/api/socket/udp_socket.h" 6 7#include <string> 8 9#include "base/memory/scoped_ptr.h" 10#include "base/message_loop/message_loop.h" 11#include "base/test/test_timeouts.h" 12#include "chrome/test/base/browser_with_test_window_test.h" 13#include "net/base/io_buffer.h" 14#include "testing/gtest/include/gtest/gtest.h" 15 16namespace extensions { 17 18// UDPSocketUnitTest exists solely to make it easier to pass a specific 19// gtest_filter argument during development. 20class UDPSocketUnitTest : public BrowserWithTestWindowTest { 21}; 22 23static void OnConnected(int result) { 24 EXPECT_EQ(0, result); 25} 26 27static void OnCompleted(int bytes_read, 28 scoped_refptr<net::IOBuffer> io_buffer, 29 const std::string& address, 30 int port) { 31 // Do nothing; don't care. 32} 33 34static const char test_message[] = "$$TESTMESSAGETESTMESSAGETESTMESSAGETEST$$"; 35static const int test_message_length = ARRAYSIZE_UNSAFE(test_message); 36 37static void OnSendCompleted(int result) { 38 EXPECT_EQ(test_message_length, result); 39} 40 41TEST(UDPSocketUnitTest, TestUDPSocketRecvFrom) { 42 base::MessageLoopForIO io_loop; // For RecvFrom to do its threaded work. 43 UDPSocket socket("abcdefghijklmnopqrst"); 44 45 // Confirm that we can call two RecvFroms in quick succession without 46 // triggering crbug.com/146606. 47 socket.Connect("127.0.0.1", 40000, base::Bind(&OnConnected)); 48 socket.RecvFrom(4096, base::Bind(&OnCompleted)); 49 socket.RecvFrom(4096, base::Bind(&OnCompleted)); 50} 51 52TEST(UDPSocketUnitTest, TestUDPMulticastJoinGroup) { 53 const char* kGroup = "237.132.100.17"; 54 UDPSocket src("abcdefghijklmnopqrst"); 55 UDPSocket dest("abcdefghijklmnopqrst"); 56 57 EXPECT_EQ(0, dest.Bind("0.0.0.0", 13333)); 58 EXPECT_EQ(0, dest.JoinGroup(kGroup)); 59 std::vector<std::string> groups = dest.GetJoinedGroups(); 60 EXPECT_EQ(static_cast<size_t>(1), groups.size()); 61 EXPECT_EQ(kGroup, *groups.begin()); 62 EXPECT_NE(0, dest.LeaveGroup("237.132.100.13")); 63 EXPECT_EQ(0, dest.LeaveGroup(kGroup)); 64 groups = dest.GetJoinedGroups(); 65 EXPECT_EQ(static_cast<size_t>(0), groups.size()); 66} 67 68TEST(UDPSocketUnitTest, TestUDPMulticastTimeToLive) { 69 const char* kGroup = "237.132.100.17"; 70 UDPSocket socket("abcdefghijklmnopqrst"); 71 EXPECT_NE(0, socket.SetMulticastTimeToLive(-1)); // Negative TTL shall fail. 72 EXPECT_EQ(0, socket.SetMulticastTimeToLive(3)); 73 socket.Connect(kGroup, 13333, base::Bind(&OnConnected)); 74} 75 76TEST(UDPSocketUnitTest, TestUDPMulticastLoopbackMode) { 77 const char* kGroup = "237.132.100.17"; 78 UDPSocket socket("abcdefghijklmnopqrst"); 79 EXPECT_EQ(0, socket.SetMulticastLoopbackMode(false)); 80 socket.Connect(kGroup, 13333, base::Bind(&OnConnected)); 81} 82 83static void QuitMessageLoop() { 84 base::MessageLoopForIO::current()->QuitNow(); 85} 86 87// Send a test multicast packet every second. 88// Once the target socket received the packet, the message loop will exit. 89static void SendMulticastPacket(UDPSocket* src, int result) { 90 if (result == 0) { 91 scoped_refptr<net::IOBuffer> data = new net::WrappedIOBuffer(test_message); 92 src->Write(data, test_message_length, base::Bind(&OnSendCompleted)); 93 base::MessageLoopForIO::current()->PostDelayedTask(FROM_HERE, 94 base::Bind(&SendMulticastPacket, src, result), 95 base::TimeDelta::FromSeconds(1)); 96 } else { 97 QuitMessageLoop(); 98 FAIL() << "Failed to connect to multicast address. Error code: " << result; 99 } 100} 101 102static void OnMulticastReadCompleted(bool *packet_received, 103 int count, 104 scoped_refptr<net::IOBuffer> io_buffer) { 105 EXPECT_EQ(test_message_length, count); 106 EXPECT_EQ(0, strncmp(io_buffer->data(), test_message, test_message_length)); 107 *packet_received = true; 108 QuitMessageLoop(); 109} 110 111TEST(UDPSocketUnitTest, TestUDPMulticastRecv) { 112 const int kPort = 9999; 113 const char* const kGroup = "237.132.100.17"; 114 bool packet_received = false; 115 base::MessageLoopForIO io_loop; // For Read to do its threaded work. 116 UDPSocket dest("abcdefghijklmnopqrst"); 117 UDPSocket src("abcdefghijklmnopqrst"); 118 119 // Receiver 120 EXPECT_EQ(0, dest.Bind("0.0.0.0", kPort)); 121 EXPECT_EQ(0, dest.JoinGroup(kGroup)); 122 dest.Read(1024, base::Bind(&OnMulticastReadCompleted, &packet_received)); 123 124 // Sender 125 EXPECT_EQ(0, src.SetMulticastTimeToLive(0)); 126 src.Connect(kGroup, kPort, base::Bind(&SendMulticastPacket, &src)); 127 128 // If not received within the test action timeout, quit the message loop. 129 io_loop.PostDelayedTask(FROM_HERE, 130 base::Bind(&QuitMessageLoop), 131 TestTimeouts::action_timeout()); 132 133 io_loop.Run(); 134 135 EXPECT_TRUE(packet_received) << "Failed to receive from multicast address"; 136} 137 138} // namespace extensions 139