Avoid duplicate usrsctp_init if the last usrsctp_finish failed.

When deinitializing usrsctp, we attempt to call usrsctp_finish in a loop
for three seconds (it may fail because another sctp thread is holding a
reference to something). If the three seconds run out, usrsctp is left
in a still initialized state, and bad things happen down the road if
usrsctp_init is called in the state.

Bug: chromium:1138878
Change-Id: I9c24d51d5a274b06bdf4183261694fc2989136c5
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/189940
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Taylor <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32467}
diff --git a/media/sctp/sctp_transport.cc b/media/sctp/sctp_transport.cc
index a74c664..2b2cc42 100644
--- a/media/sctp/sctp_transport.cc
+++ b/media/sctp/sctp_transport.cc
@@ -58,6 +58,7 @@
 
 // Set the initial value of the static SCTP Data Engines reference count.
 ABSL_CONST_INIT int g_usrsctp_usage_count = 0;
+ABSL_CONST_INIT bool g_usrsctp_initialized_ = false;
 ABSL_CONST_INIT webrtc::GlobalMutex g_usrsctp_lock_(absl::kConstInit);
 
 // DataMessageType is used for the SCTP "Payload Protocol Identifier", as
@@ -262,9 +263,19 @@
  public:
   static void InitializeUsrSctp() {
     RTC_LOG(LS_INFO) << __FUNCTION__;
-    // First argument is udp_encapsulation_port, which is not releveant for our
-    // AF_CONN use of sctp.
-    usrsctp_init(0, &UsrSctpWrapper::OnSctpOutboundPacket, &DebugSctpPrintf);
+    // UninitializeUsrSctp tries to call usrsctp_finish in a loop for three
+    // seconds; if that failed and we were left in a still-initialized state, we
+    // don't want to call usrsctp_init again as that will result in undefined
+    // behavior.
+    if (g_usrsctp_initialized_) {
+      RTC_LOG(LS_WARNING) << "Not reinitializing usrsctp since last attempt at "
+                             "usrsctp_finish failed.";
+    } else {
+      // First argument is udp_encapsulation_port, which is not releveant for
+      // our AF_CONN use of sctp.
+      usrsctp_init(0, &UsrSctpWrapper::OnSctpOutboundPacket, &DebugSctpPrintf);
+      g_usrsctp_initialized_ = true;
+    }
 
     // To turn on/off detailed SCTP debugging. You will also need to have the
     // SCTP_DEBUG cpp defines flag, which can be turned on in media/BUILD.gn.
@@ -317,6 +328,7 @@
     // closed. Wait and try again until it succeeds for up to 3 seconds.
     for (size_t i = 0; i < 300; ++i) {
       if (usrsctp_finish() == 0) {
+        g_usrsctp_initialized_ = false;
         delete g_transport_map_;
         g_transport_map_ = nullptr;
         return;