Index: webrtc/base/socket_unittest.cc |
diff --git a/webrtc/base/socket_unittest.cc b/webrtc/base/socket_unittest.cc |
index 8143823b862d792e98f83ae153ba54f941219113..d1369e2f78c1bef806e272ece186c9f60e327292 100644 |
--- a/webrtc/base/socket_unittest.cc |
+++ b/webrtc/base/socket_unittest.cc |
@@ -11,6 +11,7 @@ |
#include "webrtc/base/socket_unittest.h" |
#include "webrtc/base/arraysize.h" |
+#include "webrtc/base/buffer.h" |
#include "webrtc/base/asyncudpsocket.h" |
#include "webrtc/base/gunit.h" |
#include "webrtc/base/nethelpers.h" |
@@ -21,6 +22,9 @@ |
namespace rtc { |
+// Data size to be used in TcpInternal tests. |
+static const size_t kTcpInternalDataSize = 1024 * 1024; // bytes |
+ |
#define MAYBE_SKIP_IPV6 \ |
if (!HasIPv6Enabled()) { \ |
LOG(LS_INFO) << "No IPv6... skipping"; \ |
@@ -129,12 +133,12 @@ void SocketTest::TestSocketServerWaitIPv6() { |
} |
void SocketTest::TestTcpIPv4() { |
- TcpInternal(kIPv4Loopback); |
+ TcpInternal(kIPv4Loopback, kTcpInternalDataSize, -1); |
} |
void SocketTest::TestTcpIPv6() { |
MAYBE_SKIP_IPV6; |
- TcpInternal(kIPv6Loopback); |
+ TcpInternal(kIPv6Loopback, kTcpInternalDataSize, -1); |
} |
void SocketTest::TestSingleFlowControlCallbackIPv4() { |
@@ -671,24 +675,15 @@ void SocketTest::SocketServerWaitInternal(const IPAddress& loopback) { |
EXPECT_LT(0, accepted->Recv(buf, 1024)); |
} |
-void SocketTest::TcpInternal(const IPAddress& loopback) { |
+void SocketTest::TcpInternal(const IPAddress& loopback, size_t data_size, |
+ ssize_t max_send_size) { |
testing::StreamSink sink; |
SocketAddress accept_addr; |
- // Create test data. |
- const size_t kDataSize = 1024 * 1024; |
- scoped_ptr<char[]> send_buffer(new char[kDataSize]); |
- scoped_ptr<char[]> recv_buffer(new char[kDataSize]); |
- size_t send_pos = 0, recv_pos = 0; |
- for (size_t i = 0; i < kDataSize; ++i) { |
- send_buffer[i] = static_cast<char>(i % 256); |
- recv_buffer[i] = 0; |
- } |
- |
- // Create client. |
- scoped_ptr<AsyncSocket> client( |
+ // Create receiving client. |
+ scoped_ptr<AsyncSocket> receiver( |
ss_->CreateAsyncSocket(loopback.family(), SOCK_STREAM)); |
- sink.Monitor(client.get()); |
+ sink.Monitor(receiver.get()); |
// Create server and listen. |
scoped_ptr<AsyncSocket> server( |
@@ -698,97 +693,115 @@ void SocketTest::TcpInternal(const IPAddress& loopback) { |
EXPECT_EQ(0, server->Listen(5)); |
// Attempt connection. |
- EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); |
+ EXPECT_EQ(0, receiver->Connect(server->GetLocalAddress())); |
- // Accept connection. |
+ // Accept connection which will be used for sending. |
EXPECT_TRUE_WAIT((sink.Check(server.get(), testing::SSE_READ)), kTimeout); |
- scoped_ptr<AsyncSocket> accepted(server->Accept(&accept_addr)); |
- ASSERT_TRUE(accepted); |
- sink.Monitor(accepted.get()); |
+ scoped_ptr<AsyncSocket> sender(server->Accept(&accept_addr)); |
+ ASSERT_TRUE(sender); |
+ sink.Monitor(sender.get()); |
// Both sides are now connected. |
- EXPECT_EQ_WAIT(AsyncSocket::CS_CONNECTED, client->GetState(), kTimeout); |
- EXPECT_TRUE(sink.Check(client.get(), testing::SSE_OPEN)); |
- EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); |
- EXPECT_EQ(accepted->GetRemoteAddress(), client->GetLocalAddress()); |
+ EXPECT_EQ_WAIT(AsyncSocket::CS_CONNECTED, receiver->GetState(), kTimeout); |
+ EXPECT_TRUE(sink.Check(receiver.get(), testing::SSE_OPEN)); |
+ EXPECT_EQ(receiver->GetRemoteAddress(), sender->GetLocalAddress()); |
+ EXPECT_EQ(sender->GetRemoteAddress(), receiver->GetLocalAddress()); |
+ |
+ // Create test data. |
+ rtc::Buffer send_buffer(0, data_size); |
+ rtc::Buffer recv_buffer(0, data_size); |
+ for (size_t i = 0; i < data_size; ++i) { |
+ char ch = static_cast<char>(i % 256); |
+ send_buffer.AppendData(&ch, sizeof(ch)); |
+ } |
// Send and receive a bunch of data. |
- bool send_waiting_for_writability = false; |
- bool send_expect_success = true; |
- bool recv_waiting_for_readability = true; |
- bool recv_expect_success = false; |
- int data_in_flight = 0; |
- while (recv_pos < kDataSize) { |
- // Send as much as we can if we've been cleared to send. |
- while (!send_waiting_for_writability && send_pos < kDataSize) { |
- int tosend = static_cast<int>(kDataSize - send_pos); |
- int sent = accepted->Send(send_buffer.get() + send_pos, tosend); |
- if (send_expect_success) { |
+ size_t sent_size = 0; |
+ bool writable = true; |
+ bool send_called = false; |
+ bool readable = false; |
+ bool recv_called = false; |
+ while (recv_buffer.size() < send_buffer.size()) { |
+ // Send as much as we can while we're cleared to send. |
+ while (writable && sent_size < send_buffer.size()) { |
+ int unsent_size = static_cast<int>(send_buffer.size() - sent_size); |
+ int sent = sender->Send(send_buffer.data() + sent_size, unsent_size); |
+ if (!send_called) { |
// The first Send() after connecting or getting writability should |
// succeed and send some data. |
EXPECT_GT(sent, 0); |
- send_expect_success = false; |
+ send_called = true; |
} |
if (sent >= 0) { |
- EXPECT_LE(sent, tosend); |
- send_pos += sent; |
- data_in_flight += sent; |
+ EXPECT_LE(sent, unsent_size); |
+ sent_size += sent; |
+ if (max_send_size >= 0) { |
+ EXPECT_LE(static_cast<ssize_t>(sent), max_send_size); |
+ if (sent < unsent_size) { |
+ // If max_send_size is limiting the amount to send per call such |
+ // that the sent amount is less than the unsent amount, we simulate |
+ // that the socket is no longer writable. |
+ writable = false; |
+ } |
+ } |
} else { |
- ASSERT_TRUE(accepted->IsBlocking()); |
- send_waiting_for_writability = true; |
+ ASSERT_TRUE(sender->IsBlocking()); |
+ writable = false; |
} |
} |
// Read all the sent data. |
- while (data_in_flight > 0) { |
- if (recv_waiting_for_readability) { |
+ while (recv_buffer.size() < sent_size) { |
+ if (!readable) { |
// Wait until data is available. |
- EXPECT_TRUE_WAIT(sink.Check(client.get(), testing::SSE_READ), kTimeout); |
- recv_waiting_for_readability = false; |
- recv_expect_success = true; |
+ EXPECT_TRUE_WAIT(sink.Check(receiver.get(), testing::SSE_READ), |
+ kTimeout); |
+ readable = true; |
+ recv_called = false; |
} |
// Receive as much as we can get in a single recv call. |
- int rcvd = client->Recv(recv_buffer.get() + recv_pos, |
- kDataSize - recv_pos); |
+ char recved_data[data_size]; |
+ int recved_size = receiver->Recv(recved_data, data_size); |
- if (recv_expect_success) { |
+ if (!recv_called) { |
// The first Recv() after getting readability should succeed and receive |
// some data. |
// TODO: The following line is disabled due to flakey pulse |
// builds. Re-enable if/when possible. |
- // EXPECT_GT(rcvd, 0); |
- recv_expect_success = false; |
+ // EXPECT_GT(recved_size, 0); |
+ recv_called = true; |
} |
- if (rcvd >= 0) { |
- EXPECT_LE(rcvd, data_in_flight); |
- recv_pos += rcvd; |
- data_in_flight -= rcvd; |
+ if (recved_size >= 0) { |
+ EXPECT_LE(static_cast<size_t>(recved_size), |
+ sent_size - recv_buffer.size()); |
+ recv_buffer.AppendData(recved_data, recved_size); |
} else { |
- ASSERT_TRUE(client->IsBlocking()); |
- recv_waiting_for_readability = true; |
+ ASSERT_TRUE(receiver->IsBlocking()); |
+ readable = false; |
} |
} |
- // Once all that we've sent has been rcvd, expect to be able to send again. |
- if (send_waiting_for_writability) { |
- EXPECT_TRUE_WAIT(sink.Check(accepted.get(), testing::SSE_WRITE), |
+ // Once all that we've sent has been received, expect to be able to send |
+ // again. |
+ if (!writable) { |
+ EXPECT_TRUE_WAIT(sink.Check(sender.get(), testing::SSE_WRITE), |
kTimeout); |
- send_waiting_for_writability = false; |
- send_expect_success = true; |
+ writable = true; |
+ send_called = false; |
} |
} |
// The received data matches the sent data. |
- EXPECT_EQ(kDataSize, send_pos); |
- EXPECT_EQ(kDataSize, recv_pos); |
- EXPECT_EQ(0, memcmp(recv_buffer.get(), send_buffer.get(), kDataSize)); |
+ EXPECT_EQ(data_size, sent_size); |
+ EXPECT_EQ(data_size, recv_buffer.size()); |
+ EXPECT_EQ(recv_buffer, send_buffer); |
// Close down. |
- accepted->Close(); |
- EXPECT_EQ_WAIT(AsyncSocket::CS_CLOSED, client->GetState(), kTimeout); |
- EXPECT_TRUE(sink.Check(client.get(), testing::SSE_CLOSE)); |
- client->Close(); |
+ sender->Close(); |
+ EXPECT_EQ_WAIT(AsyncSocket::CS_CLOSED, receiver->GetState(), kTimeout); |
+ EXPECT_TRUE(sink.Check(receiver.get(), testing::SSE_CLOSE)); |
+ receiver->Close(); |
} |
void SocketTest::SingleFlowControlCallbackInternal(const IPAddress& loopback) { |