Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(646)

Side by Side Diff: webrtc/base/physicalsocketserver_unittest.cc

Issue 1616153007: Stay writable after partial socket writes. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fixed compiler error about signed/unsigned comparison. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/base/physicalsocketserver.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 11 matching lines...) Expand all
22 namespace rtc { 22 namespace rtc {
23 23
24 class PhysicalSocketTest; 24 class PhysicalSocketTest;
25 25
26 class FakeSocketDispatcher : public SocketDispatcher { 26 class FakeSocketDispatcher : public SocketDispatcher {
27 public: 27 public:
28 explicit FakeSocketDispatcher(PhysicalSocketServer* ss) 28 explicit FakeSocketDispatcher(PhysicalSocketServer* ss)
29 : SocketDispatcher(ss) { 29 : SocketDispatcher(ss) {
30 } 30 }
31 31
32 FakeSocketDispatcher(SOCKET s, PhysicalSocketServer* ss)
33 : SocketDispatcher(s, ss) {
34 }
35
32 protected: 36 protected:
33 SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen) override; 37 SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen) override;
38 int DoSend(SOCKET socket, const char* buf, int len, int flags) override;
39 int DoSendTo(SOCKET socket, const char* buf, int len, int flags,
40 const struct sockaddr* dest_addr, socklen_t addrlen) override;
34 }; 41 };
35 42
36 class FakePhysicalSocketServer : public PhysicalSocketServer { 43 class FakePhysicalSocketServer : public PhysicalSocketServer {
37 public: 44 public:
38 explicit FakePhysicalSocketServer(PhysicalSocketTest* test) 45 explicit FakePhysicalSocketServer(PhysicalSocketTest* test)
39 : test_(test) { 46 : test_(test) {
40 } 47 }
41 48
42 AsyncSocket* CreateAsyncSocket(int type) override { 49 AsyncSocket* CreateAsyncSocket(int type) override {
43 SocketDispatcher* dispatcher = new FakeSocketDispatcher(this); 50 SocketDispatcher* dispatcher = new FakeSocketDispatcher(this);
44 if (dispatcher->Create(type)) { 51 if (dispatcher->Create(type)) {
45 return dispatcher; 52 return dispatcher;
46 } else { 53 } else {
47 delete dispatcher; 54 delete dispatcher;
48 return nullptr; 55 return nullptr;
49 } 56 }
50 } 57 }
51 58
52 AsyncSocket* CreateAsyncSocket(int family, int type) override { 59 AsyncSocket* CreateAsyncSocket(int family, int type) override {
53 SocketDispatcher* dispatcher = new FakeSocketDispatcher(this); 60 SocketDispatcher* dispatcher = new FakeSocketDispatcher(this);
54 if (dispatcher->Create(family, type)) { 61 if (dispatcher->Create(family, type)) {
55 return dispatcher; 62 return dispatcher;
56 } else { 63 } else {
57 delete dispatcher; 64 delete dispatcher;
58 return nullptr; 65 return nullptr;
59 } 66 }
60 } 67 }
61 68
69 AsyncSocket* WrapSocket(SOCKET s) override {
70 SocketDispatcher* dispatcher = new FakeSocketDispatcher(s, this);
71 if (dispatcher->Initialize()) {
72 return dispatcher;
73 } else {
74 delete dispatcher;
75 return nullptr;
76 }
pthatcher1 2016/01/30 00:03:10 Can you flip this around? if (!dispatcher->Initia
joachim 2016/01/31 23:29:07 Done. This was implemented similar to the existing
77 }
78
62 PhysicalSocketTest* GetTest() const { return test_; } 79 PhysicalSocketTest* GetTest() const { return test_; }
63 80
64 private: 81 private:
65 PhysicalSocketTest* test_; 82 PhysicalSocketTest* test_;
66 }; 83 };
67 84
68 class PhysicalSocketTest : public SocketTest { 85 class PhysicalSocketTest : public SocketTest {
69 public: 86 public:
70 // Set flag to simluate failures when calling "::accept" on a AsyncSocket. 87 // Set flag to simluate failures when calling "::accept" on a AsyncSocket.
71 void SetFailAccept(bool fail) { fail_accept_ = fail; } 88 void SetFailAccept(bool fail) { fail_accept_ = fail; }
72 bool FailAccept() const { return fail_accept_; } 89 bool FailAccept() const { return fail_accept_; }
73 90
91 // Maximum size to ::send to a socket. Set to 0 to disable limiting.
pthatcher1 2016/01/30 00:03:10 Can you make "disabled limited" < 0, such as -1.
joachim 2016/01/31 23:29:06 Done.
92 void SetMaximumSendSize(int max_size) { max_send_size_ = max_size; }
93 int MaximumSendSize() const { return max_send_size_; }
pthatcher1 2016/01/30 00:03:10 Please change MaximumSendSize => MaxSendSize in bo
joachim 2016/01/31 23:29:07 Done.
94
74 protected: 95 protected:
75 PhysicalSocketTest() 96 PhysicalSocketTest()
76 : server_(new FakePhysicalSocketServer(this)), 97 : server_(new FakePhysicalSocketServer(this)),
77 scope_(server_.get()), 98 scope_(server_.get()),
78 fail_accept_(false) { 99 fail_accept_(false),
100 max_send_size_(0) {
79 } 101 }
80 102
81 void ConnectInternalAcceptError(const IPAddress& loopback); 103 void ConnectInternalAcceptError(const IPAddress& loopback);
104 void PartialWriteStayWritable(const IPAddress& loopback);
pthatcher1 2016/01/30 00:03:10 Can you name this WritableAfterPartialWrite?
joachim 2016/01/31 23:29:06 Done.
82 105
83 rtc::scoped_ptr<FakePhysicalSocketServer> server_; 106 rtc::scoped_ptr<FakePhysicalSocketServer> server_;
84 SocketServerScope scope_; 107 SocketServerScope scope_;
85 bool fail_accept_; 108 bool fail_accept_;
109 int max_send_size_;
86 }; 110 };
87 111
88 SOCKET FakeSocketDispatcher::DoAccept(SOCKET socket, 112 SOCKET FakeSocketDispatcher::DoAccept(SOCKET socket,
89 sockaddr* addr, 113 sockaddr* addr,
90 socklen_t* addrlen) { 114 socklen_t* addrlen) {
91 FakePhysicalSocketServer* ss = 115 FakePhysicalSocketServer* ss =
92 static_cast<FakePhysicalSocketServer*>(socketserver()); 116 static_cast<FakePhysicalSocketServer*>(socketserver());
93 if (ss->GetTest()->FailAccept()) { 117 if (ss->GetTest()->FailAccept()) {
94 return INVALID_SOCKET; 118 return INVALID_SOCKET;
95 } 119 }
96 120
97 return SocketDispatcher::DoAccept(socket, addr, addrlen); 121 return SocketDispatcher::DoAccept(socket, addr, addrlen);
98 } 122 }
99 123
124 int FakeSocketDispatcher::DoSend(SOCKET socket, const char* buf, int len,
125 int flags) {
126 FakePhysicalSocketServer* ss =
127 static_cast<FakePhysicalSocketServer*>(socketserver());
128 if (ss->GetTest()->MaximumSendSize() > 0) {
129 len = std::min(len, ss->GetTest()->MaximumSendSize());
130 }
131
132 return SocketDispatcher::DoSend(socket, buf, len, flags);
133 }
134
135 int FakeSocketDispatcher::DoSendTo(SOCKET socket, const char* buf, int len,
136 int flags, const struct sockaddr* dest_addr, socklen_t addrlen) {
137 FakePhysicalSocketServer* ss =
138 static_cast<FakePhysicalSocketServer*>(socketserver());
139 if (ss->GetTest()->MaximumSendSize() > 0) {
140 len = std::min(len, ss->GetTest()->MaximumSendSize());
141 }
142
143 return SocketDispatcher::DoSendTo(socket, buf, len, flags, dest_addr,
144 addrlen);
145 }
146
100 TEST_F(PhysicalSocketTest, TestConnectIPv4) { 147 TEST_F(PhysicalSocketTest, TestConnectIPv4) {
101 SocketTest::TestConnectIPv4(); 148 SocketTest::TestConnectIPv4();
102 } 149 }
103 150
104 // Crashes on Linux. See webrtc:4923. 151 // Crashes on Linux. See webrtc:4923.
105 #if defined(WEBRTC_LINUX) 152 #if defined(WEBRTC_LINUX)
106 #define MAYBE_TestConnectIPv6 DISABLED_TestConnectIPv6 153 #define MAYBE_TestConnectIPv6 DISABLED_TestConnectIPv6
107 #else 154 #else
108 #define MAYBE_TestConnectIPv6 TestConnectIPv6 155 #define MAYBE_TestConnectIPv6 TestConnectIPv6
109 #endif 156 #endif
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 // Crashes on Linux. See webrtc:4923. 249 // Crashes on Linux. See webrtc:4923.
203 #if defined(WEBRTC_LINUX) 250 #if defined(WEBRTC_LINUX)
204 #define MAYBE_TestConnectAcceptErrorIPv6 DISABLED_TestConnectAcceptErrorIPv6 251 #define MAYBE_TestConnectAcceptErrorIPv6 DISABLED_TestConnectAcceptErrorIPv6
205 #else 252 #else
206 #define MAYBE_TestConnectAcceptErrorIPv6 TestConnectAcceptErrorIPv6 253 #define MAYBE_TestConnectAcceptErrorIPv6 TestConnectAcceptErrorIPv6
207 #endif 254 #endif
208 TEST_F(PhysicalSocketTest, MAYBE_TestConnectAcceptErrorIPv6) { 255 TEST_F(PhysicalSocketTest, MAYBE_TestConnectAcceptErrorIPv6) {
209 ConnectInternalAcceptError(kIPv6Loopback); 256 ConnectInternalAcceptError(kIPv6Loopback);
210 } 257 }
211 258
259 void PhysicalSocketTest::PartialWriteStayWritable(const IPAddress& loopback) {
260 testing::StreamSink sink;
261 SocketAddress accept_addr;
262
263 // Simulate a really small maximum send size.
264 const int kMaximumSendSize = 128;
pthatcher1 2016/01/30 00:03:10 kMaxSendSize
joachim 2016/01/31 23:29:06 Done.
265 SetMaximumSendSize(kMaximumSendSize);
266
267 // Create test data.
268 const size_t kDataSize = 128 * 1024;
269 scoped_ptr<char[]> send_buffer(new char[kDataSize]);
270 scoped_ptr<char[]> recv_buffer(new char[kDataSize]);
pthatcher1 2016/01/30 00:03:10 It seems like this would benefit from using rtc::B
joachim 2016/01/31 23:29:07 Done. As I used "SocketTest::TcpInternal" as base
271 size_t send_pos = 0, recv_pos = 0;
pthatcher1 2016/01/30 00:03:10 You can replace all instances of recv_pos with rec
joachim 2016/01/31 23:29:06 Done.
272 for (size_t i = 0; i < kDataSize; ++i) {
273 send_buffer[i] = static_cast<char>(i % 256);
274 recv_buffer[i] = 0;
275 }
276
277 // Create client.
278 scoped_ptr<AsyncSocket> client(
279 server_->CreateAsyncSocket(loopback.family(), SOCK_STREAM));
280 sink.Monitor(client.get());
281
282 // Create server and listen.
283 scoped_ptr<AsyncSocket> server(
284 server_->CreateAsyncSocket(loopback.family(), SOCK_STREAM));
285 sink.Monitor(server.get());
286 EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0)));
287 EXPECT_EQ(0, server->Listen(5));
288
289 // Attempt connection.
290 EXPECT_EQ(0, client->Connect(server->GetLocalAddress()));
291
292 // Accept connection.
293 EXPECT_TRUE_WAIT((sink.Check(server.get(), testing::SSE_READ)), kTimeout);
294 scoped_ptr<AsyncSocket> accepted(server->Accept(&accept_addr));
295 ASSERT_TRUE(accepted);
296 sink.Monitor(accepted.get());
297
298 // Both sides are now connected.
299 EXPECT_EQ_WAIT(AsyncSocket::CS_CONNECTED, client->GetState(), kTimeout);
300 EXPECT_TRUE(sink.Check(client.get(), testing::SSE_OPEN));
301 EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress());
302 EXPECT_EQ(accepted->GetRemoteAddress(), client->GetLocalAddress());
303
304 // Send and receive a bunch of data.
pthatcher1 2016/01/30 00:03:10 Can you move the definition of the send and recv b
joachim 2016/01/31 23:29:06 Done.
305 bool send_waiting_for_writability = false;
pthatcher1 2016/01/30 00:03:10 Why not just "writable", with the reversed meaning
pthatcher1 2016/01/30 00:03:10 Can you call sender = accepted; receiver = clien
joachim 2016/01/31 23:29:06 Done.
joachim 2016/01/31 23:29:06 Done.
306 bool send_expect_success = true;
pthatcher1 2016/01/30 00:03:10 Can you call this send_called = false? That would
joachim 2016/01/31 23:29:07 Done.
307 bool recv_waiting_for_readability = true;
pthatcher1 2016/01/30 00:03:10 Similarly, "readable = false" here.
joachim 2016/01/31 23:29:06 Done.
308 bool recv_expect_success = false;
pthatcher1 2016/01/30 00:03:10 And this "recv_called = false"?
joachim 2016/01/31 23:29:06 Done.
309 int data_in_flight = 0;
310 while (recv_pos < kDataSize) {
311 // Send as much as we can if we've been cleared to send.
pthatcher1 2016/01/30 00:03:09 if we've been cleared to send => while we're clear
joachim 2016/01/31 23:29:06 Done.
312 while (!send_waiting_for_writability && send_pos < kDataSize) {
313 int tosend = static_cast<int>(kDataSize - send_pos);
314 int sent = accepted->Send(send_buffer.get() + send_pos, tosend);
315 if (send_expect_success) {
316 // The first Send() after connecting or getting writability should
317 // succeed and send some data.
318 EXPECT_GT(sent, 0);
319 send_expect_success = false;
320 }
321 if (sent >= 0) {
322 EXPECT_LE(sent, tosend);
323 EXPECT_LE(sent, kMaximumSendSize);
324 send_pos += sent;
325 data_in_flight += sent;
pthatcher1 2016/01/30 00:03:10 I think you can replace all instances of data_in_f
joachim 2016/01/31 23:29:06 Done.
326 }
327 if (sent < tosend) {
328 // Partial data or nothing sent.
329 ASSERT_TRUE(accepted->IsBlocking());
330 send_waiting_for_writability = true;
331 }
332 }
333
334 // Read all the sent data.
335 while (data_in_flight > 0) {
pthatcher1 2016/01/30 00:03:10 Or in this case: while (recv_buffer.size() < sent
joachim 2016/01/31 23:29:06 Done.
336 if (recv_waiting_for_readability) {
337 // Wait until data is available.
338 EXPECT_TRUE_WAIT(sink.Check(client.get(), testing::SSE_READ), kTimeout);
339 recv_waiting_for_readability = false;
340 recv_expect_success = true;
341 }
342
343 // Receive as much as we can get in a single recv call.
344 int rcvd = client->Recv(recv_buffer.get() + recv_pos,
345 kDataSize - recv_pos);
346
347 if (recv_expect_success) {
348 // The first Recv() after getting readability should succeed and receive
349 // some data.
350 EXPECT_GT(rcvd, 0);
351 recv_expect_success = false;
352 }
353 if (rcvd >= 0) {
354 EXPECT_LE(rcvd, data_in_flight);
355 recv_pos += rcvd;
356 data_in_flight -= rcvd;
357 } else {
358 ASSERT_TRUE(client->IsBlocking());
359 recv_waiting_for_readability = true;
360 }
361 }
362
363 // Once all that we've sent has been rcvd, expect to be able to send again.
364 if (send_waiting_for_writability) {
365 EXPECT_TRUE_WAIT(sink.Check(accepted.get(), testing::SSE_WRITE),
366 kTimeout);
367 send_waiting_for_writability = false;
368 send_expect_success = true;
369 }
370 }
371
372 // The received data matches the sent data.
373 EXPECT_EQ(kDataSize, send_pos);
374 EXPECT_EQ(kDataSize, recv_pos);
375 EXPECT_EQ(0, memcmp(recv_buffer.get(), send_buffer.get(), kDataSize));
376
377 // Close down.
378 accepted->Close();
379 EXPECT_EQ_WAIT(AsyncSocket::CS_CLOSED, client->GetState(), kTimeout);
380 EXPECT_TRUE(sink.Check(client.get(), testing::SSE_CLOSE));
381 client->Close();
382 }
383
384 TEST_F(PhysicalSocketTest, TestPartialWriteStayWritableIPv4) {
385 PartialWriteStayWritable(kIPv4Loopback);
386 }
387
388 // Crashes on Linux. See webrtc:4923.
389 #if defined(WEBRTC_LINUX)
390 #define MAYBE_TestPartialWriteStayWritableIPv6 \
391 DISABLED_TestPartialWriteStayWritableIPv6
392 #else
393 #define MAYBE_TestPartialWriteStayWritableIPv6 TestPartialWriteStayWritableIPv6
394 #endif
395 TEST_F(PhysicalSocketTest, MAYBE_TestPartialWriteStayWritableIPv6) {
396 PartialWriteStayWritable(kIPv6Loopback);
397 }
398
212 // Crashes on Linux. See webrtc:4923. 399 // Crashes on Linux. See webrtc:4923.
213 #if defined(WEBRTC_LINUX) 400 #if defined(WEBRTC_LINUX)
214 #define MAYBE_TestConnectFailIPv6 DISABLED_TestConnectFailIPv6 401 #define MAYBE_TestConnectFailIPv6 DISABLED_TestConnectFailIPv6
215 #else 402 #else
216 #define MAYBE_TestConnectFailIPv6 TestConnectFailIPv6 403 #define MAYBE_TestConnectFailIPv6 TestConnectFailIPv6
217 #endif 404 #endif
218 TEST_F(PhysicalSocketTest, MAYBE_TestConnectFailIPv6) { 405 TEST_F(PhysicalSocketTest, MAYBE_TestConnectFailIPv6) {
219 SocketTest::TestConnectFailIPv6(); 406 SocketTest::TestConnectFailIPv6();
220 } 407 }
221 408
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 thread->Start(runnable.get()); 704 thread->Start(runnable.get());
518 EXPECT_TRUE(ss_->Wait(1500, true)); 705 EXPECT_TRUE(ss_->Wait(1500, true));
519 EXPECT_TRUE(ExpectSignal(SIGTERM)); 706 EXPECT_TRUE(ExpectSignal(SIGTERM));
520 EXPECT_EQ(Thread::Current(), signaled_thread_); 707 EXPECT_EQ(Thread::Current(), signaled_thread_);
521 EXPECT_TRUE(ExpectNone()); 708 EXPECT_TRUE(ExpectNone());
522 } 709 }
523 710
524 #endif 711 #endif
525 712
526 } // namespace rtc 713 } // namespace rtc
OLDNEW
« no previous file with comments | « webrtc/base/physicalsocketserver.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698