Test that SCTP succeeds with one MTU and fails with a lower MTU
This pair of tests will ensure that the SCTP layer's response to
MTU size changes has not been modified.
Bug: webrtc:12495
Change-Id: If9776ad399871e9f01b38715594b732e156118ff
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/211246
Reviewed-by: Tommi <tommi@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33459}
diff --git a/pc/data_channel_integrationtest.cc b/pc/data_channel_integrationtest.cc
index 91c8870..d4a259b 100644
--- a/pc/data_channel_integrationtest.cc
+++ b/pc/data_channel_integrationtest.cc
@@ -397,6 +397,122 @@
kDefaultTimeout);
}
+// This test sets up a call between two parties with an SCTP
+// data channel only, and sends messages of various sizes.
+TEST_P(DataChannelIntegrationTest,
+ EndToEndCallWithSctpDataChannelVariousSizes) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ // Expect that data channel created on caller side will show up for callee as
+ // well.
+ caller()->CreateDataChannel();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ // Caller data channel should already exist (it created one). Callee data
+ // channel may not exist yet, since negotiation happens in-band, not in SDP.
+ ASSERT_NE(nullptr, caller()->data_channel());
+ ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+ EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+ EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+ for (int message_size = 1; message_size < 100000; message_size *= 2) {
+ std::string data(message_size, 'a');
+ caller()->data_channel()->Send(DataBuffer(data));
+ EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+ kDefaultTimeout);
+ callee()->data_channel()->Send(DataBuffer(data));
+ EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+ kDefaultTimeout);
+ }
+ // Specifically probe the area around the MTU size.
+ for (int message_size = 1100; message_size < 1300; message_size += 1) {
+ std::string data(message_size, 'a');
+ caller()->data_channel()->Send(DataBuffer(data));
+ EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+ kDefaultTimeout);
+ callee()->data_channel()->Send(DataBuffer(data));
+ EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+ kDefaultTimeout);
+ }
+}
+
+TEST_P(DataChannelIntegrationTest,
+ EndToEndCallWithSctpDataChannelLowestSafeMtu) {
+ // The lowest payload size limit that's tested and found safe for this
+ // application. Note that this is not the safe limit under all conditions;
+ // in particular, the default is not the largest DTLS signature, and
+ // this test does not use TURN.
+ const size_t kLowestSafePayloadSizeLimit = 1225;
+
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ // Expect that data channel created on caller side will show up for callee as
+ // well.
+ caller()->CreateDataChannel();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ // Caller data channel should already exist (it created one). Callee data
+ // channel may not exist yet, since negotiation happens in-band, not in SDP.
+ ASSERT_NE(nullptr, caller()->data_channel());
+ ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+ EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+ EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+ virtual_socket_server()->set_max_udp_payload(kLowestSafePayloadSizeLimit);
+ for (int message_size = 1140; message_size < 1240; message_size += 1) {
+ std::string data(message_size, 'a');
+ caller()->data_channel()->Send(DataBuffer(data));
+ ASSERT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+ kDefaultTimeout);
+ callee()->data_channel()->Send(DataBuffer(data));
+ ASSERT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+ kDefaultTimeout);
+ }
+}
+
+// This test verifies that lowering the MTU of the connection will cause
+// the datachannel to not transmit reliably.
+// The purpose of this test is to ensure that we know how a too-small MTU
+// error manifests itself.
+TEST_P(DataChannelIntegrationTest, EndToEndCallWithSctpDataChannelHarmfulMtu) {
+ // The lowest payload size limit that's tested and found safe for this
+ // application in this configuration (see test above).
+ const size_t kLowestSafePayloadSizeLimit = 1225;
+ // The size of the smallest message that fails to be delivered.
+ const size_t kMessageSizeThatIsNotDelivered = 1157;
+
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->CreateDataChannel();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ ASSERT_NE(nullptr, caller()->data_channel());
+ ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+ EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+ EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+ virtual_socket_server()->set_max_udp_payload(kLowestSafePayloadSizeLimit - 1);
+ // Probe for an undelivered or slowly delivered message. The exact
+ // size limit seems to be dependent on the message history, so make the
+ // code easily able to find the current value.
+ bool failure_seen = false;
+ for (size_t message_size = 1110; message_size < 1400; message_size++) {
+ const size_t message_count =
+ callee()->data_observer()->received_message_count();
+ const std::string data(message_size, 'a');
+ caller()->data_channel()->Send(DataBuffer(data));
+ // Wait a very short time for the message to be delivered.
+ WAIT(callee()->data_observer()->received_message_count() > message_count,
+ 10);
+ if (callee()->data_observer()->received_message_count() == message_count) {
+ ASSERT_EQ(kMessageSizeThatIsNotDelivered, message_size);
+ failure_seen = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(failure_seen);
+}
+
// Ensure that when the callee closes an SCTP data channel, the closing
// procedure results in the data channel being closed for the caller as well.
TEST_P(DataChannelIntegrationTest, CalleeClosesSctpDataChannel) {