Cease all future TURN requests when a TURN refresh request fails for a given TURN port.
This fixes an assert error in Turnport::OnSendStunPacket

BUG=webrtc:5388

Review URL: https://codereview.webrtc.org/1547373002

Cr-Commit-Position: refs/heads/master@{#11152}
diff --git a/webrtc/p2p/base/stunrequest.cc b/webrtc/p2p/base/stunrequest.cc
index 0a0b1a8..ce0364e 100644
--- a/webrtc/p2p/base/stunrequest.cc
+++ b/webrtc/p2p/base/stunrequest.cc
@@ -53,11 +53,13 @@
   }
 }
 
-void StunRequestManager::Flush() {
+void StunRequestManager::Flush(int msg_type) {
   for (const auto kv : requests_) {
     StunRequest* request = kv.second;
-    thread_->Clear(request, MSG_STUN_SEND);
-    thread_->Send(request, MSG_STUN_SEND, NULL);
+    if (msg_type == kAllRequests || msg_type == request->type()) {
+      thread_->Clear(request, MSG_STUN_SEND);
+      thread_->Send(request, MSG_STUN_SEND, NULL);
+    }
   }
 }
 
diff --git a/webrtc/p2p/base/stunrequest.h b/webrtc/p2p/base/stunrequest.h
index 15ea0c7..44c1ebf 100644
--- a/webrtc/p2p/base/stunrequest.h
+++ b/webrtc/p2p/base/stunrequest.h
@@ -21,6 +21,8 @@
 
 class StunRequest;
 
+const int kAllRequests = 0;
+
 // Manages a set of STUN requests, sending and resending until we receive a
 // response or determine that the request has timed out.
 class StunRequestManager {
@@ -32,8 +34,10 @@
   void Send(StunRequest* request);
   void SendDelayed(StunRequest* request, int delay);
 
-  // Sends all pending requests right away. Only for testing.
-  void Flush();
+  // If |msg_type| is kAllRequests, sends all pending requests right away.
+  // Otherwise, sends those that have a matching type right away.
+  // Only for testing.
+  void Flush(int msg_type);
 
   // Removes a stun request that was added previously.  This will happen
   // automatically when a request succeeds, fails, or times out.
diff --git a/webrtc/p2p/base/turnport.cc b/webrtc/p2p/base/turnport.cc
index 328683b..022207a 100644
--- a/webrtc/p2p/base/turnport.cc
+++ b/webrtc/p2p/base/turnport.cc
@@ -409,11 +409,7 @@
 void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
   LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
   ASSERT(socket == socket_);
-  if (!ready()) {
-    OnAllocateError();
-  }
-  request_manager_.Clear();
-  state_ = STATE_DISCONNECTED;
+  Close();
 }
 
 void TurnPort::OnAllocateMismatch() {
@@ -717,7 +713,18 @@
   thread()->Post(this, MSG_ALLOCATE_ERROR);
 }
 
+void TurnPort::OnTurnRefreshError() {
+  // Need to Close the port asynchronously because otherwise, the refresh
+  // request may be deleted twice: once at the end of the message processing
+  // and the other in Close().
+  thread()->Post(this, MSG_REFRESH_ERROR);
+}
+
 void TurnPort::Close() {
+  if (!ready()) {
+    OnAllocateError();
+  }
+  request_manager_.Clear();
   // Stop the port from creating new connections.
   state_ = STATE_DISCONNECTED;
   // Delete all existing connections; stop sending data.
@@ -734,6 +741,9 @@
     case MSG_ALLOCATE_MISMATCH:
       OnAllocateMismatch();
       break;
+    case MSG_REFRESH_ERROR:
+      Close();
+      break;
     case MSG_TRY_ALTERNATE_SERVER:
       if (server_address().proto == PROTO_UDP) {
         // Send another allocate request to alternate server, with the received
diff --git a/webrtc/p2p/base/turnport.h b/webrtc/p2p/base/turnport.h
index 4be9249..a19f676 100644
--- a/webrtc/p2p/base/turnport.h
+++ b/webrtc/p2p/base/turnport.h
@@ -141,7 +141,8 @@
   sigslot::signal2<TurnPort*, int> SignalTurnRefreshResult;
   sigslot::signal3<TurnPort*, const rtc::SocketAddress&, int>
       SignalCreatePermissionResult;
-  void FlushRequests() { request_manager_.Flush(); }
+  void FlushRequests(int msg_type) { request_manager_.Flush(msg_type); }
+  bool HasRequests() { return !request_manager_.empty(); }
   void set_credentials(RelayCredentials& credentials) {
     credentials_ = credentials;
   }
@@ -178,7 +179,8 @@
   enum {
     MSG_ALLOCATE_ERROR = MSG_FIRST_AVAILABLE,
     MSG_ALLOCATE_MISMATCH,
-    MSG_TRY_ALTERNATE_SERVER
+    MSG_TRY_ALTERNATE_SERVER,
+    MSG_REFRESH_ERROR
   };
 
   typedef std::list<TurnEntry*> EntryList;
@@ -199,7 +201,7 @@
 
   // Shuts down the turn port, usually because of some fatal errors.
   void Close();
-  void OnTurnRefreshError() { Close(); }
+  void OnTurnRefreshError();
   bool SetAlternateServer(const rtc::SocketAddress& address);
   void ResolveTurnAddress(const rtc::SocketAddress& address);
   void OnResolveResult(rtc::AsyncResolverInterface* resolver);
diff --git a/webrtc/p2p/base/turnport_unittest.cc b/webrtc/p2p/base/turnport_unittest.cc
index eac3474..d0dc487 100644
--- a/webrtc/p2p/base/turnport_unittest.cc
+++ b/webrtc/p2p/base/turnport_unittest.cc
@@ -309,7 +309,7 @@
   }
 
   bool CheckConnectionDestroyed() {
-    turn_port_->FlushRequests();
+    turn_port_->FlushRequests(cricket::kAllRequests);
     rtc::Thread::Current()->ProcessMessages(50);
     return connection_destroyed_;
   }
@@ -693,8 +693,9 @@
 
 TEST_F(TurnPortTest, TestRefreshRequestGetsErrorResponse) {
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
-  turn_port_->PrepareAddress();
-  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  PrepareTurnAndUdpPorts();
+  turn_port_->CreateConnection(udp_port_->Candidates()[0],
+                               Port::ORIGIN_MESSAGE);
   // Set bad credentials.
   cricket::RelayCredentials bad_credentials("bad_user", "bad_pwd");
   turn_port_->set_credentials(bad_credentials);
@@ -702,13 +703,14 @@
   // This sends out the first RefreshRequest with correct credentials.
   // When this succeeds, it will schedule a new RefreshRequest with the bad
   // credential.
-  turn_port_->FlushRequests();
+  turn_port_->FlushRequests(cricket::TURN_REFRESH_REQUEST);
   EXPECT_TRUE_WAIT(turn_refresh_success_, kTimeout);
   // Flush it again, it will receive a bad response.
-  turn_port_->FlushRequests();
+  turn_port_->FlushRequests(cricket::TURN_REFRESH_REQUEST);
   EXPECT_TRUE_WAIT(!turn_refresh_success_, kTimeout);
+  EXPECT_TRUE_WAIT(!turn_port_->connected(), kTimeout);
   EXPECT_TRUE(turn_port_->connections().empty());
-  EXPECT_FALSE(turn_port_->connected());
+  EXPECT_FALSE(turn_port_->HasRequests());
 }
 
 // Test that CreateConnection will return null if port becomes disconnected.
@@ -840,10 +842,10 @@
   // another request with bad_ufrag and bad_pwd.
   cricket::RelayCredentials bad_credentials("bad_user", "bad_pwd");
   turn_port_->set_credentials(bad_credentials);
-  turn_port_->FlushRequests();
+  turn_port_->FlushRequests(cricket::kAllRequests);
   ASSERT_TRUE_WAIT(turn_create_permission_success_, kTimeout);
   // Flush the requests again; the create-permission-request will fail.
-  turn_port_->FlushRequests();
+  turn_port_->FlushRequests(cricket::kAllRequests);
   EXPECT_TRUE_WAIT(!turn_create_permission_success_, kTimeout);
   EXPECT_TRUE_WAIT(connection_destroyed_, kTimeout);
 }