1// Copyright (c) 2010 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 "net/base/listen_socket_unittest.h"
6
7#include <fcntl.h>
8#include <sys/types.h>
9
10#include "base/eintr_wrapper.h"
11#include "net/base/net_util.h"
12#include "testing/platform_test.h"
13
14const int ListenSocketTester::kTestPort = 9999;
15
16static const int kReadBufSize = 1024;
17static const char kHelloWorld[] = "HELLO, WORLD";
18static const int kMaxQueueSize = 20;
19static const char kLoopback[] = "127.0.0.1";
20static const int kDefaultTimeoutMs = 5000;
21
22ListenSocketTester::ListenSocketTester()
23    : thread_(NULL),
24      loop_(NULL),
25      server_(NULL),
26      connection_(NULL),
27      cv_(&lock_) {
28}
29
30void ListenSocketTester::SetUp() {
31  base::Thread::Options options;
32  options.message_loop_type = MessageLoop::TYPE_IO;
33  thread_.reset(new base::Thread("socketio_test"));
34  thread_->StartWithOptions(options);
35  loop_ = reinterpret_cast<MessageLoopForIO*>(thread_->message_loop());
36
37  loop_->PostTask(FROM_HERE, NewRunnableMethod(
38      this, &ListenSocketTester::Listen));
39
40  // verify Listen succeeded
41  NextAction();
42  ASSERT_FALSE(server_ == NULL);
43  ASSERT_EQ(ACTION_LISTEN, last_action_.type());
44
45  // verify the connect/accept and setup test_socket_
46  test_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
47  ASSERT_NE(INVALID_SOCKET, test_socket_);
48  struct sockaddr_in client;
49  client.sin_family = AF_INET;
50  client.sin_addr.s_addr = inet_addr(kLoopback);
51  client.sin_port = htons(kTestPort);
52  int ret = HANDLE_EINTR(
53      connect(test_socket_, reinterpret_cast<sockaddr*>(&client),
54              sizeof(client)));
55  ASSERT_NE(ret, SOCKET_ERROR);
56
57  NextAction();
58  ASSERT_EQ(ACTION_ACCEPT, last_action_.type());
59}
60
61void ListenSocketTester::TearDown() {
62#if defined(OS_WIN)
63  ASSERT_EQ(0, closesocket(test_socket_));
64#elif defined(OS_POSIX)
65  ASSERT_EQ(0, HANDLE_EINTR(close(test_socket_)));
66#endif
67  NextAction();
68  ASSERT_EQ(ACTION_CLOSE, last_action_.type());
69
70  loop_->PostTask(FROM_HERE, NewRunnableMethod(
71      this, &ListenSocketTester::Shutdown));
72  NextAction();
73  ASSERT_EQ(ACTION_SHUTDOWN, last_action_.type());
74
75  thread_.reset();
76  loop_ = NULL;
77}
78
79void ListenSocketTester::ReportAction(const ListenSocketTestAction& action) {
80  base::AutoLock locked(lock_);
81  queue_.push_back(action);
82  cv_.Broadcast();
83}
84
85void ListenSocketTester::NextAction() {
86  base::AutoLock locked(lock_);
87  while (queue_.empty())
88    cv_.Wait();
89  last_action_ = queue_.front();
90  queue_.pop_front();
91}
92
93int ListenSocketTester::ClearTestSocket() {
94  char buf[kReadBufSize];
95  int len_ret = 0;
96  do {
97    int len = HANDLE_EINTR(recv(test_socket_, buf, kReadBufSize, 0));
98    if (len == SOCKET_ERROR || len == 0) {
99      break;
100    } else {
101      len_ret += len;
102    }
103  } while (true);
104  return len_ret;
105}
106
107void ListenSocketTester::Shutdown() {
108  connection_->Release();
109  connection_ = NULL;
110  server_->Release();
111  server_ = NULL;
112  ReportAction(ListenSocketTestAction(ACTION_SHUTDOWN));
113}
114
115void ListenSocketTester::Listen() {
116  server_ = DoListen();
117  if (server_) {
118    server_->AddRef();
119    ReportAction(ListenSocketTestAction(ACTION_LISTEN));
120  }
121}
122
123void ListenSocketTester::SendFromTester() {
124  connection_->Send(kHelloWorld);
125  ReportAction(ListenSocketTestAction(ACTION_SEND));
126}
127
128void ListenSocketTester::TestClientSend() {
129  ASSERT_TRUE(Send(test_socket_, kHelloWorld));
130  NextAction();
131  ASSERT_EQ(ACTION_READ, last_action_.type());
132  ASSERT_EQ(last_action_.data(), kHelloWorld);
133}
134
135void ListenSocketTester::TestClientSendLong() {
136  size_t hello_len = strlen(kHelloWorld);
137  std::string long_string;
138  size_t long_len = 0;
139  for (int i = 0; i < 200; i++) {
140    long_string += kHelloWorld;
141    long_len += hello_len;
142  }
143  ASSERT_TRUE(Send(test_socket_, long_string));
144  size_t read_len = 0;
145  while (read_len < long_len) {
146    NextAction();
147    ASSERT_EQ(ACTION_READ, last_action_.type());
148    std::string last_data = last_action_.data();
149    size_t len = last_data.length();
150    if (long_string.compare(read_len, len, last_data)) {
151      ASSERT_EQ(long_string.compare(read_len, len, last_data), 0);
152    }
153    read_len += last_data.length();
154  }
155  ASSERT_EQ(read_len, long_len);
156}
157
158void ListenSocketTester::TestServerSend() {
159  loop_->PostTask(FROM_HERE, NewRunnableMethod(
160      this, &ListenSocketTester::SendFromTester));
161  NextAction();
162  ASSERT_EQ(ACTION_SEND, last_action_.type());
163  const int buf_len = 200;
164  char buf[buf_len+1];
165  unsigned recv_len = 0;
166  while (recv_len < strlen(kHelloWorld)) {
167    int r = HANDLE_EINTR(recv(test_socket_, buf, buf_len, 0));
168    ASSERT_GE(r, 0);
169    recv_len += static_cast<unsigned>(r);
170    if (!r)
171      break;
172  }
173  buf[recv_len] = 0;
174  ASSERT_STREQ(buf, kHelloWorld);
175}
176
177bool ListenSocketTester::Send(SOCKET sock, const std::string& str) {
178  int len = static_cast<int>(str.length());
179  int send_len = HANDLE_EINTR(send(sock, str.data(), len, 0));
180  if (send_len == SOCKET_ERROR) {
181    LOG(ERROR) << "send failed: " << errno;
182    return false;
183  } else if (send_len != len) {
184    return false;
185  }
186  return true;
187}
188
189void ListenSocketTester::DidAccept(ListenSocket *server,
190                                   ListenSocket *connection) {
191  connection_ = connection;
192  connection_->AddRef();
193  ReportAction(ListenSocketTestAction(ACTION_ACCEPT));
194}
195
196void ListenSocketTester::DidRead(ListenSocket *connection,
197                                 const char* data,
198                                 int len) {
199  std::string str(data, len);
200  ReportAction(ListenSocketTestAction(ACTION_READ, str));
201}
202
203void ListenSocketTester::DidClose(ListenSocket *sock) {
204  ReportAction(ListenSocketTestAction(ACTION_CLOSE));
205}
206
207ListenSocketTester::~ListenSocketTester() {}
208
209ListenSocket* ListenSocketTester::DoListen() {
210  return ListenSocket::Listen(kLoopback, kTestPort, this);
211}
212
213
214class ListenSocketTest: public PlatformTest {
215 public:
216  ListenSocketTest() {
217    tester_ = NULL;
218  }
219
220  virtual void SetUp() {
221    PlatformTest::SetUp();
222    tester_ = new ListenSocketTester();
223    tester_->SetUp();
224  }
225
226  virtual void TearDown() {
227    PlatformTest::TearDown();
228    tester_->TearDown();
229    tester_ = NULL;
230  }
231
232  scoped_refptr<ListenSocketTester> tester_;
233};
234
235TEST_F(ListenSocketTest, ClientSend) {
236  tester_->TestClientSend();
237}
238
239TEST_F(ListenSocketTest, ClientSendLong) {
240  tester_->TestClientSendLong();
241}
242
243TEST_F(ListenSocketTest, ServerSend) {
244  tester_->TestServerSend();
245}
246