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