| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2009 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/tcp_client_socket.h" | |
| 6 | |
| 7 #include "base/basictypes.h" | |
| 8 #include "net/base/address_list.h" | |
| 9 #include "net/base/host_resolver.h" | |
| 10 #include "net/base/io_buffer.h" | |
| 11 #include "net/base/listen_socket.h" | |
| 12 #include "net/base/net_errors.h" | |
| 13 #include "net/base/test_completion_callback.h" | |
| 14 #include "net/base/winsock_init.h" | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 #include "testing/platform_test.h" | |
| 17 | |
| 18 namespace net { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 const char kServerReply[] = "HTTP/1.1 404 Not Found"; | |
| 23 | |
| 24 class TCPClientSocketTest | |
| 25 : public PlatformTest, public ListenSocket::ListenSocketDelegate { | |
| 26 public: | |
| 27 TCPClientSocketTest() { | |
| 28 } | |
| 29 | |
| 30 // Implement ListenSocketDelegate methods | |
| 31 virtual void DidAccept(ListenSocket* server, ListenSocket* connection) { | |
| 32 connected_sock_ = connection; | |
| 33 } | |
| 34 virtual void DidRead(ListenSocket*, const std::string& s) { | |
| 35 // TODO(dkegel): this might not be long enough to tickle some bugs. | |
| 36 connected_sock_->Send(kServerReply, | |
| 37 arraysize(kServerReply) - 1, | |
| 38 false /* don't append line feed */); | |
| 39 } | |
| 40 virtual void DidClose(ListenSocket* sock) {} | |
| 41 | |
| 42 // Testcase hooks | |
| 43 virtual void SetUp(); | |
| 44 | |
| 45 void CloseServerSocket() { | |
| 46 // delete the connected_sock_, which will close it. | |
| 47 connected_sock_ = NULL; | |
| 48 } | |
| 49 | |
| 50 void PauseServerReads() { | |
| 51 connected_sock_->PauseReads(); | |
| 52 } | |
| 53 | |
| 54 void ResumeServerReads() { | |
| 55 connected_sock_->ResumeReads(); | |
| 56 } | |
| 57 | |
| 58 protected: | |
| 59 int listen_port_; | |
| 60 scoped_ptr<TCPClientSocket> sock_; | |
| 61 | |
| 62 private: | |
| 63 scoped_refptr<ListenSocket> listen_sock_; | |
| 64 scoped_refptr<ListenSocket> connected_sock_; | |
| 65 }; | |
| 66 | |
| 67 void TCPClientSocketTest::SetUp() { | |
| 68 PlatformTest::SetUp(); | |
| 69 | |
| 70 // Find a free port to listen on | |
| 71 ListenSocket *sock = NULL; | |
| 72 int port; | |
| 73 // Range of ports to listen on. Shouldn't need to try many. | |
| 74 const int kMinPort = 10100; | |
| 75 const int kMaxPort = 10200; | |
| 76 #if defined(OS_WIN) | |
| 77 EnsureWinsockInit(); | |
| 78 #endif | |
| 79 for (port = kMinPort; port < kMaxPort; port++) { | |
| 80 sock = ListenSocket::Listen("127.0.0.1", port, this); | |
| 81 if (sock) | |
| 82 break; | |
| 83 } | |
| 84 ASSERT_TRUE(sock != NULL); | |
| 85 listen_sock_ = sock; | |
| 86 listen_port_ = port; | |
| 87 | |
| 88 AddressList addr; | |
| 89 HostResolver resolver; | |
| 90 HostResolver::RequestInfo info("localhost", listen_port_); | |
| 91 int rv = resolver.Resolve(info, &addr, NULL, NULL); | |
| 92 CHECK(rv == OK); | |
| 93 sock_.reset(new TCPClientSocket(addr)); | |
| 94 } | |
| 95 | |
| 96 TEST_F(TCPClientSocketTest, Connect) { | |
| 97 TestCompletionCallback callback; | |
| 98 EXPECT_FALSE(sock_->IsConnected()); | |
| 99 | |
| 100 int rv = sock_->Connect(&callback); | |
| 101 if (rv != OK) { | |
| 102 ASSERT_EQ(rv, ERR_IO_PENDING); | |
| 103 | |
| 104 rv = callback.WaitForResult(); | |
| 105 EXPECT_EQ(rv, OK); | |
| 106 } | |
| 107 | |
| 108 EXPECT_TRUE(sock_->IsConnected()); | |
| 109 | |
| 110 sock_->Disconnect(); | |
| 111 EXPECT_FALSE(sock_->IsConnected()); | |
| 112 } | |
| 113 | |
| 114 // TODO(wtc): Add unit tests for IsConnectedAndIdle: | |
| 115 // - Server closes a connection. | |
| 116 // - Server sends data unexpectedly. | |
| 117 | |
| 118 TEST_F(TCPClientSocketTest, Read) { | |
| 119 TestCompletionCallback callback; | |
| 120 int rv = sock_->Connect(&callback); | |
| 121 if (rv != OK) { | |
| 122 ASSERT_EQ(rv, ERR_IO_PENDING); | |
| 123 | |
| 124 rv = callback.WaitForResult(); | |
| 125 EXPECT_EQ(rv, OK); | |
| 126 } | |
| 127 | |
| 128 const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; | |
| 129 scoped_refptr<IOBuffer> request_buffer = | |
| 130 new IOBuffer(arraysize(request_text) - 1); | |
| 131 memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); | |
| 132 | |
| 133 rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback); | |
| 134 EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 135 | |
| 136 if (rv == ERR_IO_PENDING) { | |
| 137 rv = callback.WaitForResult(); | |
| 138 EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1)); | |
| 139 } | |
| 140 | |
| 141 scoped_refptr<IOBuffer> buf = new IOBuffer(4096); | |
| 142 uint32 bytes_read = 0; | |
| 143 while (bytes_read < arraysize(kServerReply) - 1) { | |
| 144 rv = sock_->Read(buf, 4096, &callback); | |
| 145 EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 146 | |
| 147 if (rv == ERR_IO_PENDING) | |
| 148 rv = callback.WaitForResult(); | |
| 149 | |
| 150 ASSERT_GE(rv, 0); | |
| 151 bytes_read += rv; | |
| 152 } | |
| 153 | |
| 154 // All data has been read now. Read once more to force an ERR_IO_PENDING, and | |
| 155 // then close the server socket, and note the close. | |
| 156 | |
| 157 rv = sock_->Read(buf, 4096, &callback); | |
| 158 ASSERT_EQ(ERR_IO_PENDING, rv); | |
| 159 CloseServerSocket(); | |
| 160 EXPECT_EQ(0, callback.WaitForResult()); | |
| 161 } | |
| 162 | |
| 163 TEST_F(TCPClientSocketTest, Read_SmallChunks) { | |
| 164 TestCompletionCallback callback; | |
| 165 int rv = sock_->Connect(&callback); | |
| 166 if (rv != OK) { | |
| 167 ASSERT_EQ(rv, ERR_IO_PENDING); | |
| 168 | |
| 169 rv = callback.WaitForResult(); | |
| 170 EXPECT_EQ(rv, OK); | |
| 171 } | |
| 172 | |
| 173 const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; | |
| 174 scoped_refptr<IOBuffer> request_buffer = | |
| 175 new IOBuffer(arraysize(request_text) - 1); | |
| 176 memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); | |
| 177 | |
| 178 rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback); | |
| 179 EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 180 | |
| 181 if (rv == ERR_IO_PENDING) { | |
| 182 rv = callback.WaitForResult(); | |
| 183 EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1)); | |
| 184 } | |
| 185 | |
| 186 scoped_refptr<IOBuffer> buf = new IOBuffer(1); | |
| 187 uint32 bytes_read = 0; | |
| 188 while (bytes_read < arraysize(kServerReply) - 1) { | |
| 189 rv = sock_->Read(buf, 1, &callback); | |
| 190 EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 191 | |
| 192 if (rv == ERR_IO_PENDING) | |
| 193 rv = callback.WaitForResult(); | |
| 194 | |
| 195 ASSERT_EQ(1, rv); | |
| 196 bytes_read += rv; | |
| 197 } | |
| 198 | |
| 199 // All data has been read now. Read once more to force an ERR_IO_PENDING, and | |
| 200 // then close the server socket, and note the close. | |
| 201 | |
| 202 rv = sock_->Read(buf, 1, &callback); | |
| 203 ASSERT_EQ(ERR_IO_PENDING, rv); | |
| 204 CloseServerSocket(); | |
| 205 EXPECT_EQ(0, callback.WaitForResult()); | |
| 206 } | |
| 207 | |
| 208 TEST_F(TCPClientSocketTest, Read_Interrupted) { | |
| 209 TestCompletionCallback callback; | |
| 210 int rv = sock_->Connect(&callback); | |
| 211 if (rv != OK) { | |
| 212 ASSERT_EQ(ERR_IO_PENDING, rv); | |
| 213 | |
| 214 rv = callback.WaitForResult(); | |
| 215 EXPECT_EQ(rv, OK); | |
| 216 } | |
| 217 | |
| 218 const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; | |
| 219 scoped_refptr<IOBuffer> request_buffer = | |
| 220 new IOBuffer(arraysize(request_text) - 1); | |
| 221 memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); | |
| 222 | |
| 223 rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback); | |
| 224 EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 225 | |
| 226 if (rv == ERR_IO_PENDING) { | |
| 227 rv = callback.WaitForResult(); | |
| 228 EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1)); | |
| 229 } | |
| 230 | |
| 231 // Do a partial read and then exit. This test should not crash! | |
| 232 scoped_refptr<IOBuffer> buf = new IOBuffer(16); | |
| 233 rv = sock_->Read(buf, 16, &callback); | |
| 234 EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 235 | |
| 236 if (rv == ERR_IO_PENDING) | |
| 237 rv = callback.WaitForResult(); | |
| 238 | |
| 239 EXPECT_NE(0, rv); | |
| 240 } | |
| 241 | |
| 242 TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_ReadFirst) { | |
| 243 TestCompletionCallback callback; | |
| 244 int rv = sock_->Connect(&callback); | |
| 245 if (rv != OK) { | |
| 246 ASSERT_EQ(rv, ERR_IO_PENDING); | |
| 247 | |
| 248 rv = callback.WaitForResult(); | |
| 249 EXPECT_EQ(rv, OK); | |
| 250 } | |
| 251 | |
| 252 // Read first. There's no data, so it should return ERR_IO_PENDING. | |
| 253 const int kBufLen = 4096; | |
| 254 scoped_refptr<IOBuffer> buf = new IOBuffer(kBufLen); | |
| 255 rv = sock_->Read(buf, kBufLen, &callback); | |
| 256 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 257 | |
| 258 PauseServerReads(); | |
| 259 const int kWriteBufLen = 64 * 1024; | |
| 260 scoped_refptr<IOBuffer> request_buffer = new IOBuffer(kWriteBufLen); | |
| 261 char* request_data = request_buffer->data(); | |
| 262 memset(request_data, 'A', kWriteBufLen); | |
| 263 TestCompletionCallback write_callback; | |
| 264 | |
| 265 while (true) { | |
| 266 rv = sock_->Write(request_buffer, kWriteBufLen, &write_callback); | |
| 267 ASSERT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 268 | |
| 269 if (rv == ERR_IO_PENDING) { | |
| 270 ResumeServerReads(); | |
| 271 rv = write_callback.WaitForResult(); | |
| 272 break; | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 // At this point, both read and write have returned ERR_IO_PENDING, and the | |
| 277 // write callback has executed. We wait for the read callback to run now to | |
| 278 // make sure that the socket can handle full duplex communications. | |
| 279 | |
| 280 rv = callback.WaitForResult(); | |
| 281 EXPECT_GE(rv, 0); | |
| 282 } | |
| 283 | |
| 284 TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_WriteFirst) { | |
| 285 TestCompletionCallback callback; | |
| 286 int rv = sock_->Connect(&callback); | |
| 287 if (rv != OK) { | |
| 288 ASSERT_EQ(ERR_IO_PENDING, rv); | |
| 289 | |
| 290 rv = callback.WaitForResult(); | |
| 291 EXPECT_EQ(OK, rv); | |
| 292 } | |
| 293 | |
| 294 PauseServerReads(); | |
| 295 const int kWriteBufLen = 64 * 1024; | |
| 296 scoped_refptr<IOBuffer> request_buffer = new IOBuffer(kWriteBufLen); | |
| 297 char* request_data = request_buffer->data(); | |
| 298 memset(request_data, 'A', kWriteBufLen); | |
| 299 TestCompletionCallback write_callback; | |
| 300 | |
| 301 while (true) { | |
| 302 rv = sock_->Write(request_buffer, kWriteBufLen, &write_callback); | |
| 303 ASSERT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 304 | |
| 305 if (rv == ERR_IO_PENDING) | |
| 306 break; | |
| 307 } | |
| 308 | |
| 309 // Now we have the Write() blocked on ERR_IO_PENDING. It's time to force the | |
| 310 // Read() to block on ERR_IO_PENDING too. | |
| 311 | |
| 312 const int kBufLen = 4096; | |
| 313 scoped_refptr<IOBuffer> buf = new IOBuffer(kBufLen); | |
| 314 while (true) { | |
| 315 rv = sock_->Read(buf, kBufLen, &callback); | |
| 316 ASSERT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); | |
| 317 if (rv == ERR_IO_PENDING) | |
| 318 break; | |
| 319 } | |
| 320 | |
| 321 // At this point, both read and write have returned ERR_IO_PENDING. Now we | |
| 322 // run the write and read callbacks to make sure they can handle full duplex | |
| 323 // communications. | |
| 324 | |
| 325 ResumeServerReads(); | |
| 326 rv = write_callback.WaitForResult(); | |
| 327 EXPECT_GE(rv, 0); | |
| 328 | |
| 329 // It's possible the read is blocked because it's already read all the data. | |
| 330 // Close the server socket, so there will at least be a 0-byte read. | |
| 331 CloseServerSocket(); | |
| 332 | |
| 333 rv = callback.WaitForResult(); | |
| 334 EXPECT_GE(rv, 0); | |
| 335 } | |
| 336 | |
| 337 } // namespace | |
| 338 | |
| 339 } // namespace net | |
| OLD | NEW |