Updated PeerConnection integration test to fix race condition.
The PeerConnection integration test was creating TurnServers on the
stack on the signaling thread. This could cause a race condition problem
when the test was being taken down. Since the turn server was destructed
on the signaling thread, a socket might still try and send to it after
it was destroyed causing a seg fault. This change creates/destroys the
TestTurnServers on the network thread to fix this issue.
Bug: None
Change-Id: I080098502b737f0972ce2fa5357920de057a3312
Reviewed-on: https://webrtc-review.googlesource.com/81301
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Seth Hampson <shampson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23590}
diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc
index 186da00..1e61604 100644
--- a/pc/peerconnection_integrationtest.cc
+++ b/pc/peerconnection_integrationtest.cc
@@ -1116,12 +1116,26 @@
}
~PeerConnectionIntegrationBaseTest() {
+ // The PeerConnections should deleted before the TurnCustomizers.
+ // A TurnPort is created with a raw pointer to a TurnCustomizer. The
+ // TurnPort has the same lifetime as the PeerConnection, so it's expected
+ // that the TurnCustomizer outlives the life of the PeerConnection or else
+ // when Send() is called it will hit a seg fault.
if (caller_) {
caller_->set_signaling_message_receiver(nullptr);
+ delete SetCallerPcWrapperAndReturnCurrent(nullptr);
}
if (callee_) {
callee_->set_signaling_message_receiver(nullptr);
+ delete SetCalleePcWrapperAndReturnCurrent(nullptr);
}
+
+ // If turn servers were created for the test they need to be destroyed on
+ // the network thread.
+ network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
+ turn_servers_.clear();
+ turn_customizers_.clear();
+ });
}
bool SignalingStateStable() {
@@ -1286,6 +1300,52 @@
std::move(dependencies), nullptr);
}
+ cricket::TestTurnServer* CreateTurnServer(
+ rtc::SocketAddress internal_address,
+ rtc::SocketAddress external_address,
+ cricket::ProtocolType type = cricket::ProtocolType::PROTO_UDP,
+ const std::string& common_name = "test turn server") {
+ rtc::Thread* thread = network_thread();
+ std::unique_ptr<cricket::TestTurnServer> turn_server =
+ network_thread()->Invoke<std::unique_ptr<cricket::TestTurnServer>>(
+ RTC_FROM_HERE,
+ [thread, internal_address, external_address, type, common_name] {
+ return rtc::MakeUnique<cricket::TestTurnServer>(
+ thread, internal_address, external_address, type,
+ /*ignore_bad_certs=*/true, common_name);
+ });
+ turn_servers_.push_back(std::move(turn_server));
+ // Interactions with the turn server should be done on the network thread.
+ return turn_servers_.back().get();
+ }
+
+ cricket::TestTurnCustomizer* CreateTurnCustomizer() {
+ std::unique_ptr<cricket::TestTurnCustomizer> turn_customizer =
+ network_thread()->Invoke<std::unique_ptr<cricket::TestTurnCustomizer>>(
+ RTC_FROM_HERE,
+ [] { return rtc::MakeUnique<cricket::TestTurnCustomizer>(); });
+ turn_customizers_.push_back(std::move(turn_customizer));
+ // Interactions with the turn customizer should be done on the network
+ // thread.
+ return turn_customizers_.back().get();
+ }
+
+ // Checks that the function counters for a TestTurnCustomizer are greater than
+ // 0.
+ void ExpectTurnCustomizerCountersIncremented(
+ cricket::TestTurnCustomizer* turn_customizer) {
+ unsigned int allow_channel_data_counter =
+ network_thread()->Invoke<unsigned int>(
+ RTC_FROM_HERE, [turn_customizer] {
+ return turn_customizer->allow_channel_data_cnt_;
+ });
+ EXPECT_GT(allow_channel_data_counter, 0u);
+ unsigned int modify_counter = network_thread()->Invoke<unsigned int>(
+ RTC_FROM_HERE,
+ [turn_customizer] { return turn_customizer->modify_cnt_; });
+ EXPECT_GT(modify_counter, 0u);
+ }
+
// Once called, SDP blobs and ICE candidates will be automatically signaled
// between PeerConnections.
void ConnectFakeSignaling() {
@@ -1499,6 +1559,11 @@
// later.
std::unique_ptr<rtc::Thread> network_thread_;
std::unique_ptr<rtc::Thread> worker_thread_;
+ // The turn servers and turn customizers should be accessed & deleted on the
+ // network thread to avoid a race with the socket read/write that occurs
+ // on the network thread.
+ std::vector<std::unique_ptr<cricket::TestTurnServer>> turn_servers_;
+ std::vector<std::unique_ptr<cricket::TestTurnCustomizer>> turn_customizers_;
std::unique_ptr<PeerConnectionWrapper> caller_;
std::unique_ptr<PeerConnectionWrapper> callee_;
};
@@ -3799,17 +3864,19 @@
3478};
static const rtc::SocketAddress turn_server_2_external_address{"99.99.99.1",
0};
- cricket::TestTurnServer turn_server_1(network_thread(),
- turn_server_1_internal_address,
- turn_server_1_external_address);
- cricket::TestTurnServer turn_server_2(network_thread(),
- turn_server_2_internal_address,
- turn_server_2_external_address);
+ cricket::TestTurnServer* turn_server_1 = CreateTurnServer(
+ turn_server_1_internal_address, turn_server_1_external_address);
+ cricket::TestTurnServer* turn_server_2 = CreateTurnServer(
+ turn_server_2_internal_address, turn_server_2_external_address);
// Bypass permission check on received packets so media can be sent before
// the candidate is signaled.
- turn_server_1.set_enable_permission_checks(false);
- turn_server_2.set_enable_permission_checks(false);
+ network_thread()->Invoke<void>(RTC_FROM_HERE, [turn_server_1] {
+ turn_server_1->set_enable_permission_checks(false);
+ });
+ network_thread()->Invoke<void>(RTC_FROM_HERE, [turn_server_2] {
+ turn_server_2->set_enable_permission_checks(false);
+ });
PeerConnectionInterface::RTCConfiguration client_1_config;
webrtc::PeerConnectionInterface::IceServer ice_server_1;
@@ -3846,10 +3913,6 @@
caller()->CreateAndSetAndSignalOffer();
EXPECT_TRUE_SIMULATED_WAIT(DtlsConnected(), total_connection_time_ms,
fake_clock);
- // Need to free the clients here since they're using things we created on
- // the stack.
- delete SetCallerPcWrapperAndReturnCurrent(nullptr);
- delete SetCalleePcWrapperAndReturnCurrent(nullptr);
}
// Verify that a TurnCustomizer passed in through RTCConfiguration
@@ -3864,12 +3927,10 @@
3478};
static const rtc::SocketAddress turn_server_2_external_address{"99.99.99.1",
0};
- cricket::TestTurnServer turn_server_1(network_thread(),
- turn_server_1_internal_address,
- turn_server_1_external_address);
- cricket::TestTurnServer turn_server_2(network_thread(),
- turn_server_2_internal_address,
- turn_server_2_external_address);
+ CreateTurnServer(turn_server_1_internal_address,
+ turn_server_1_external_address);
+ CreateTurnServer(turn_server_2_internal_address,
+ turn_server_2_external_address);
PeerConnectionInterface::RTCConfiguration client_1_config;
webrtc::PeerConnectionInterface::IceServer ice_server_1;
@@ -3878,8 +3939,8 @@
ice_server_1.password = "test";
client_1_config.servers.push_back(ice_server_1);
client_1_config.type = webrtc::PeerConnectionInterface::kRelay;
- auto customizer1 = rtc::MakeUnique<cricket::TestTurnCustomizer>();
- client_1_config.turn_customizer = customizer1.get();
+ auto* customizer1 = CreateTurnCustomizer();
+ client_1_config.turn_customizer = customizer1;
PeerConnectionInterface::RTCConfiguration client_2_config;
webrtc::PeerConnectionInterface::IceServer ice_server_2;
@@ -3888,8 +3949,8 @@
ice_server_2.password = "test";
client_2_config.servers.push_back(ice_server_2);
client_2_config.type = webrtc::PeerConnectionInterface::kRelay;
- auto customizer2 = rtc::MakeUnique<cricket::TestTurnCustomizer>();
- client_2_config.turn_customizer = customizer2.get();
+ auto* customizer2 = CreateTurnCustomizer();
+ client_2_config.turn_customizer = customizer2;
ASSERT_TRUE(
CreatePeerConnectionWrappersWithConfig(client_1_config, client_2_config));
@@ -3904,16 +3965,8 @@
caller()->CreateAndSetAndSignalOffer();
ASSERT_TRUE_WAIT(DtlsConnected(), kDefaultTimeout);
- EXPECT_GT(customizer1->allow_channel_data_cnt_, 0u);
- EXPECT_GT(customizer1->modify_cnt_, 0u);
-
- EXPECT_GT(customizer2->allow_channel_data_cnt_, 0u);
- EXPECT_GT(customizer2->modify_cnt_, 0u);
-
- // Need to free the clients here since they're using things we created on
- // the stack.
- delete SetCallerPcWrapperAndReturnCurrent(nullptr);
- delete SetCalleePcWrapperAndReturnCurrent(nullptr);
+ ExpectTurnCustomizerCountersIncremented(customizer1);
+ ExpectTurnCustomizerCountersIncremented(customizer2);
}
// Verifies that you can use TCP instead of UDP to connect to a TURN server and
@@ -3924,9 +3977,8 @@
static const rtc::SocketAddress turn_server_external_address{"88.88.88.1", 0};
// Enable TCP for the fake turn server.
- cricket::TestTurnServer turn_server(
- network_thread(), turn_server_internal_address,
- turn_server_external_address, cricket::PROTO_TCP);
+ CreateTurnServer(turn_server_internal_address, turn_server_external_address,
+ cricket::PROTO_TCP);
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.urls.push_back("turn:88.88.88.0:3478?transport=tcp");
@@ -3971,10 +4023,8 @@
// Enable TCP-TLS for the fake turn server. We need to pass in 88.88.88.0 so
// that host name verification passes on the fake certificate.
- cricket::TestTurnServer turn_server(
- network_thread(), turn_server_internal_address,
- turn_server_external_address, cricket::PROTO_TLS,
- /*ignore_bad_certs=*/true, "88.88.88.0");
+ CreateTurnServer(turn_server_internal_address, turn_server_external_address,
+ cricket::PROTO_TLS, "88.88.88.0");
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.urls.push_back("turns:88.88.88.0:3478?transport=tcp");
@@ -4023,11 +4073,6 @@
EXPECT_GT(client_1_cert_verifier->call_count_, 0u);
EXPECT_GT(client_2_cert_verifier->call_count_, 0u);
-
- // Need to free the clients here since they're using things we created on
- // the stack.
- delete SetCallerPcWrapperAndReturnCurrent(nullptr);
- delete SetCalleePcWrapperAndReturnCurrent(nullptr);
}
TEST_P(PeerConnectionIntegrationTest,
@@ -4038,10 +4083,8 @@
// Enable TCP-TLS for the fake turn server. We need to pass in 88.88.88.0 so
// that host name verification passes on the fake certificate.
- cricket::TestTurnServer turn_server(
- network_thread(), turn_server_internal_address,
- turn_server_external_address, cricket::PROTO_TLS,
- /*ignore_bad_certs=*/true, "88.88.88.0");
+ CreateTurnServer(turn_server_internal_address, turn_server_external_address,
+ cricket::PROTO_TLS, "88.88.88.0");
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.urls.push_back("turns:88.88.88.0:3478?transport=tcp");
@@ -4095,11 +4138,6 @@
EXPECT_GT(client_1_cert_verifier->call_count_, 0u);
EXPECT_GT(client_2_cert_verifier->call_count_, 0u);
-
- // Need to free the clients here since they're using things we created on
- // the stack.
- delete SetCallerPcWrapperAndReturnCurrent(nullptr);
- delete SetCalleePcWrapperAndReturnCurrent(nullptr);
}
// Test that audio and video flow end-to-end when codec names don't use the