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 |