Schedule a CreatePermissionRequest after the success of a previous request
unless a channel binding request is already scheduled.
BUG=5178
R=pthatcher@webrtc.org
Review URL: https://codereview.webrtc.org/1434603002 .
Cr-Commit-Position: refs/heads/master@{#10625}
diff --git a/webrtc/p2p/base/stunrequest.cc b/webrtc/p2p/base/stunrequest.cc
index df5614d..0a0b1a8 100644
--- a/webrtc/p2p/base/stunrequest.cc
+++ b/webrtc/p2p/base/stunrequest.cc
@@ -53,6 +53,14 @@
}
}
+void StunRequestManager::Flush() {
+ for (const auto kv : requests_) {
+ StunRequest* request = kv.second;
+ thread_->Clear(request, MSG_STUN_SEND);
+ thread_->Send(request, MSG_STUN_SEND, NULL);
+ }
+}
+
void StunRequestManager::Remove(StunRequest* request) {
ASSERT(request->manager() == this);
RequestMap::iterator iter = requests_.find(request->id());
diff --git a/webrtc/p2p/base/stunrequest.h b/webrtc/p2p/base/stunrequest.h
index 267b4a1..15ea0c7 100644
--- a/webrtc/p2p/base/stunrequest.h
+++ b/webrtc/p2p/base/stunrequest.h
@@ -32,6 +32,9 @@
void Send(StunRequest* request);
void SendDelayed(StunRequest* request, int delay);
+ // Sends all pending requests right away. Only for testing.
+ void Flush();
+
// Removes a stun request that was added previously. This will happen
// automatically when a request succeeds, fails, or times out.
void Remove(StunRequest* request);
diff --git a/webrtc/p2p/base/turnport.cc b/webrtc/p2p/base/turnport.cc
index 1cc885e..32f63be 100644
--- a/webrtc/p2p/base/turnport.cc
+++ b/webrtc/p2p/base/turnport.cc
@@ -141,7 +141,7 @@
BindState state() const { return state_; }
// Helper methods to send permission and channel bind requests.
- void SendCreatePermissionRequest();
+ void SendCreatePermissionRequest(int delay);
void SendChannelBindRequest(int delay);
// Sends a packet to the given destination address.
// This will wrap the packet in STUN if necessary.
@@ -1289,12 +1289,12 @@
ext_addr_(ext_addr),
state_(STATE_UNBOUND) {
// Creating permission for |ext_addr_|.
- SendCreatePermissionRequest();
+ SendCreatePermissionRequest(0);
}
-void TurnEntry::SendCreatePermissionRequest() {
- port_->SendRequest(new TurnCreatePermissionRequest(
- port_, this, ext_addr_), 0);
+void TurnEntry::SendCreatePermissionRequest(int delay) {
+ port_->SendRequest(new TurnCreatePermissionRequest(port_, this, ext_addr_),
+ delay);
}
void TurnEntry::SendChannelBindRequest(int delay) {
@@ -1337,12 +1337,23 @@
<< " succeeded";
// For success result code will be 0.
port_->SignalCreatePermissionResult(port_, ext_addr_, 0);
+
+ // If |state_| is STATE_BOUND, the permission will be refreshed
+ // by ChannelBindRequest.
+ if (state_ != STATE_BOUND) {
+ // Refresh the permission request about 1 minute before the permission
+ // times out.
+ int delay = TURN_PERMISSION_TIMEOUT - 60000;
+ SendCreatePermissionRequest(delay);
+ LOG_J(LS_INFO, port_) << "Scheduled create-permission-request in "
+ << delay << "ms.";
+ }
}
void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
if (code == STUN_ERROR_STALE_NONCE) {
if (port_->UpdateNonce(response)) {
- SendCreatePermissionRequest();
+ SendCreatePermissionRequest(0);
}
} else {
// Send signal with error code.
diff --git a/webrtc/p2p/base/turnport.h b/webrtc/p2p/base/turnport.h
index 3bca727..3a1b432 100644
--- a/webrtc/p2p/base/turnport.h
+++ b/webrtc/p2p/base/turnport.h
@@ -132,6 +132,8 @@
// This signal is only for testing purpose.
sigslot::signal3<TurnPort*, const rtc::SocketAddress&, int>
SignalCreatePermissionResult;
+ // For testing only.
+ void FlushRequests() { request_manager_.Flush(); }
protected:
TurnPort(rtc::Thread* thread,
diff --git a/webrtc/p2p/base/turnport_unittest.cc b/webrtc/p2p/base/turnport_unittest.cc
index 724485d..484b152 100644
--- a/webrtc/p2p/base/turnport_unittest.cc
+++ b/webrtc/p2p/base/turnport_unittest.cc
@@ -715,6 +715,28 @@
TestTurnConnection();
}
+// Test that CreatePermissionRequest will be scheduled after the success
+// of the first create permission request.
+TEST_F(TurnPortTest, TestRefreshCreatePermissionRequest) {
+ CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+
+ ASSERT_TRUE(turn_port_ != NULL);
+ turn_port_->PrepareAddress();
+ ASSERT_TRUE_WAIT(turn_ready_, kTimeout);
+ CreateUdpPort();
+ udp_port_->PrepareAddress();
+ ASSERT_TRUE_WAIT(udp_ready_, kTimeout);
+
+ Connection* conn = turn_port_->CreateConnection(udp_port_->Candidates()[0],
+ Port::ORIGIN_MESSAGE);
+ ASSERT_TRUE(conn != NULL);
+ ASSERT_TRUE_WAIT(turn_create_permission_success_, kTimeout);
+ turn_create_permission_success_ = false;
+ // A create-permission-request should be pending.
+ turn_port_->FlushRequests();
+ ASSERT_TRUE_WAIT(turn_create_permission_success_, kTimeout);
+}
+
// Do a TURN allocation, establish a UDP connection, and send some data.
TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) {
// Create ports and prepare addresses.