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.
5 #include "net/socket/tcp_listen_socket_unittest.h"
10 #include "base/bind.h"
11 #include "base/posix/eintr_wrapper.h"
12 #include "base/sys_byteorder.h"
13 #include "net/base/ip_endpoint.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/net_util.h"
16 #include "net/socket/socket_descriptor.h"
17 #include "testing/platform_test.h"
21 const int kReadBufSize = 1024;
22 const char kHelloWorld[] = "HELLO, WORLD";
23 const char kLoopback[] = "127.0.0.1";
25 TCPListenSocketTester::TCPListenSocketTester()
30 void TCPListenSocketTester::SetUp() {
31 base::Thread::Options options;
32 options.message_loop_type = base::MessageLoop::TYPE_IO;
33 thread_.reset(new base::Thread("socketio_test"));
34 thread_->StartWithOptions(options);
35 loop_ = reinterpret_cast<base::MessageLoopForIO*>(thread_->message_loop());
37 loop_->PostTask(FROM_HERE, base::Bind(
38 &TCPListenSocketTester::Listen, this));
40 // verify Listen succeeded
42 ASSERT_FALSE(server_.get() == NULL);
43 ASSERT_EQ(ACTION_LISTEN, last_action_.type());
45 int server_port = GetServerPort();
46 ASSERT_GT(server_port, 0);
48 // verify the connect/accept and setup test_socket_
49 test_socket_ = CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
50 ASSERT_NE(kInvalidSocket, test_socket_);
51 struct sockaddr_in client;
52 client.sin_family = AF_INET;
53 client.sin_addr.s_addr = inet_addr(kLoopback);
54 client.sin_port = base::HostToNet16(server_port);
55 int ret = HANDLE_EINTR(
56 connect(test_socket_, reinterpret_cast<sockaddr*>(&client),
59 // The connect() call may be interrupted by a signal. When connect()
60 // is retried on EINTR, it fails with EISCONN.
61 if (ret == StreamListenSocket::kSocketError)
62 ASSERT_EQ(EISCONN, errno);
64 // Don't have signals.
65 ASSERT_NE(StreamListenSocket::kSocketError, ret);
69 ASSERT_EQ(ACTION_ACCEPT, last_action_.type());
72 void TCPListenSocketTester::TearDown() {
74 ASSERT_EQ(0, closesocket(test_socket_));
75 #elif defined(OS_POSIX)
76 ASSERT_EQ(0, HANDLE_EINTR(close(test_socket_)));
79 ASSERT_EQ(ACTION_CLOSE, last_action_.type());
81 loop_->PostTask(FROM_HERE, base::Bind(
82 &TCPListenSocketTester::Shutdown, this));
84 ASSERT_EQ(ACTION_SHUTDOWN, last_action_.type());
90 void TCPListenSocketTester::ReportAction(
91 const TCPListenSocketTestAction& action) {
92 base::AutoLock locked(lock_);
93 queue_.push_back(action);
97 void TCPListenSocketTester::NextAction() {
98 base::AutoLock locked(lock_);
99 while (queue_.empty())
101 last_action_ = queue_.front();
105 int TCPListenSocketTester::ClearTestSocket() {
106 char buf[kReadBufSize];
109 int len = HANDLE_EINTR(recv(test_socket_, buf, kReadBufSize, 0));
110 if (len == StreamListenSocket::kSocketError || len == 0) {
119 void TCPListenSocketTester::Shutdown() {
122 ReportAction(TCPListenSocketTestAction(ACTION_SHUTDOWN));
125 void TCPListenSocketTester::Listen() {
126 server_ = DoListen();
127 ASSERT_TRUE(server_.get());
129 // The server's port will be needed to open the client socket.
130 IPEndPoint local_address;
131 ASSERT_EQ(OK, server_->GetLocalAddress(&local_address));
132 SetServerPort(local_address.port());
134 ReportAction(TCPListenSocketTestAction(ACTION_LISTEN));
137 void TCPListenSocketTester::SendFromTester() {
138 connection_->Send(kHelloWorld);
139 ReportAction(TCPListenSocketTestAction(ACTION_SEND));
142 void TCPListenSocketTester::TestClientSend() {
143 ASSERT_TRUE(Send(test_socket_, kHelloWorld));
145 ASSERT_EQ(ACTION_READ, last_action_.type());
146 ASSERT_EQ(last_action_.data(), kHelloWorld);
149 void TCPListenSocketTester::TestClientSendLong() {
150 size_t hello_len = strlen(kHelloWorld);
151 std::string long_string;
153 for (int i = 0; i < 200; i++) {
154 long_string += kHelloWorld;
155 long_len += hello_len;
157 ASSERT_TRUE(Send(test_socket_, long_string));
159 while (read_len < long_len) {
161 ASSERT_EQ(ACTION_READ, last_action_.type());
162 std::string last_data = last_action_.data();
163 size_t len = last_data.length();
164 if (long_string.compare(read_len, len, last_data)) {
165 ASSERT_EQ(long_string.compare(read_len, len, last_data), 0);
167 read_len += last_data.length();
169 ASSERT_EQ(read_len, long_len);
172 void TCPListenSocketTester::TestServerSend() {
173 loop_->PostTask(FROM_HERE, base::Bind(
174 &TCPListenSocketTester::SendFromTester, this));
176 ASSERT_EQ(ACTION_SEND, last_action_.type());
177 const int buf_len = 200;
179 unsigned recv_len = 0;
180 while (recv_len < strlen(kHelloWorld)) {
181 int r = HANDLE_EINTR(recv(test_socket_,
182 buf + recv_len, buf_len - recv_len, 0));
184 recv_len += static_cast<unsigned>(r);
189 ASSERT_STREQ(kHelloWorld, buf);
192 void TCPListenSocketTester::TestServerSendMultiple() {
193 // Send enough data to exceed the socket receive window. 20kb is probably a
195 int send_count = (1024*20) / (sizeof(kHelloWorld)-1);
197 // Send multiple writes. Since no reading is occurring the data should be
198 // buffered in TCPListenSocket.
199 for (int i = 0; i < send_count; ++i) {
200 loop_->PostTask(FROM_HERE, base::Bind(
201 &TCPListenSocketTester::SendFromTester, this));
203 ASSERT_EQ(ACTION_SEND, last_action_.type());
206 // Make multiple reads. All of the data should eventually be returned.
207 char buf[sizeof(kHelloWorld)];
208 const int buf_len = sizeof(kHelloWorld);
209 for (int i = 0; i < send_count; ++i) {
210 unsigned recv_len = 0;
211 while (recv_len < buf_len-1) {
212 int r = HANDLE_EINTR(recv(test_socket_,
213 buf + recv_len, buf_len - 1 - recv_len, 0));
215 recv_len += static_cast<unsigned>(r);
220 ASSERT_STREQ(kHelloWorld, buf);
224 bool TCPListenSocketTester::Send(SocketDescriptor sock,
225 const std::string& str) {
226 int len = static_cast<int>(str.length());
227 int send_len = HANDLE_EINTR(send(sock, str.data(), len, 0));
228 if (send_len == StreamListenSocket::kSocketError) {
229 LOG(ERROR) << "send failed: " << errno;
231 } else if (send_len != len) {
237 void TCPListenSocketTester::DidAccept(
238 StreamListenSocket* server,
239 scoped_ptr<StreamListenSocket> connection) {
240 connection_ = connection.Pass();
241 ReportAction(TCPListenSocketTestAction(ACTION_ACCEPT));
244 void TCPListenSocketTester::DidRead(StreamListenSocket* connection,
247 std::string str(data, len);
248 ReportAction(TCPListenSocketTestAction(ACTION_READ, str));
251 void TCPListenSocketTester::DidClose(StreamListenSocket* sock) {
252 ReportAction(TCPListenSocketTestAction(ACTION_CLOSE));
255 TCPListenSocketTester::~TCPListenSocketTester() {}
257 scoped_ptr<TCPListenSocket> TCPListenSocketTester::DoListen() {
258 // Let the OS pick a free port.
259 return TCPListenSocket::CreateAndListen(kLoopback, 0, this);
262 int TCPListenSocketTester::GetServerPort() {
263 base::AutoLock locked(lock_);
267 void TCPListenSocketTester::SetServerPort(int server_port) {
268 base::AutoLock locked(lock_);
269 server_port_ = server_port;
272 class TCPListenSocketTest : public PlatformTest {
274 TCPListenSocketTest() {
278 virtual void SetUp() {
279 PlatformTest::SetUp();
280 tester_ = new TCPListenSocketTester();
284 virtual void TearDown() {
285 PlatformTest::TearDown();
290 scoped_refptr<TCPListenSocketTester> tester_;
293 TEST_F(TCPListenSocketTest, ClientSend) {
294 tester_->TestClientSend();
297 TEST_F(TCPListenSocketTest, ClientSendLong) {
298 tester_->TestClientSendLong();
301 TEST_F(TCPListenSocketTest, ServerSend) {
302 tester_->TestServerSend();
305 TEST_F(TCPListenSocketTest, ServerSendMultiple) {
306 tester_->TestServerSendMultiple();