Index: webrtc/p2p/base/p2ptransportchannel.cc |
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc |
index 6bcf0d7d2bfb09e9548501dccfde4e2ba249a5bd..370b03fb8ae193f6aa987b8cfeecb3ae1ba4f28a 100644 |
--- a/webrtc/p2p/base/p2ptransportchannel.cc |
+++ b/webrtc/p2p/base/p2ptransportchannel.cc |
@@ -66,6 +66,8 @@ namespace cricket { |
// well on a 28.8K modem, which is the slowest connection on which the voice |
// quality is reasonable at all. |
static const int PING_PACKET_SIZE = 60 * 8; |
+ |
+// The next two ping intervals are at the channel level. |
// STRONG_PING_INTERVAL (480ms) is applied when the selected connection is both |
// writable and receiving. |
static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000; |
@@ -73,11 +75,13 @@ static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000; |
// not writable or not receiving. |
const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000; |
-// Writable connections are pinged at a faster rate while stabilizing. |
-const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms |
- |
-// Writable connections are pinged at a slower rate once stabilized. |
-const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms |
+// The next two ping intervals are at the connection level. |
+// Writable connections are pinged at a faster rate while the connections are |
+// stabilizing or the channel is weak. |
+const int WEAK_OR_STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms |
+// Writable connections are pinged at a slower rate once they are stabilized and |
+// the channel is strongly connected. |
+const int STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms |
static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms |
@@ -116,7 +120,7 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
DEFAULT_BACKUP_CONNECTION_PING_INTERVAL, |
GATHER_ONCE /* continual_gathering_policy */, |
false /* prioritize_most_likely_candidate_pairs */, |
- STABLE_WRITABLE_CONNECTION_PING_INTERVAL, |
+ STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL, |
true /* presume_writable_when_fully_relayed */, |
DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL, |
RECEIVING_SWITCHING_DELAY) { |
@@ -1305,6 +1309,24 @@ void P2PTransportChannel::SortConnectionsAndUpdateState() { |
MaybeStartPinging(); |
} |
+std::map<rtc::Network*, Connection*> |
+P2PTransportChannel::GetPremierConnectionsByNetwork() const { |
+ // |connections_| has been sorted, so the first one in the list on a given |
+ // network is the premier connection, except that the selected connection |
+ // is always the premier connection on the network. |
+ std::map<rtc::Network*, Connection*> premier_connections_by_network; |
+ if (selected_connection_) { |
+ premier_connections_by_network[selected_connection_->port()->Network()] = |
+ selected_connection_; |
+ } |
+ for (Connection* conn : connections_) { |
+ rtc::Network* network = conn->port()->Network(); |
+ // This only inserts when the network does not exist in the map. |
+ premier_connections_by_network.insert(std::make_pair(network, conn)); |
+ } |
+ return premier_connections_by_network; |
+} |
+ |
void P2PTransportChannel::PruneConnections() { |
// We can prune any connection for which there is a connected, writable |
// connection on the same network with better or equal priority. We leave |
@@ -1315,25 +1337,15 @@ void P2PTransportChannel::PruneConnections() { |
// switch. If the |premier| connection is not connected, we may be |
// reconnecting a TCP connection and temporarily do not prune connections in |
// this network. See the big comment in CompareConnectionStates. |
- |
- // Get a list of the networks that we are using. |
- std::set<rtc::Network*> networks; |
- for (const Connection* conn : connections_) { |
- networks.insert(conn->port()->Network()); |
- } |
- for (rtc::Network* network : networks) { |
- Connection* premier = GetBestConnectionOnNetwork(network); |
- // Do not prune connections if the current selected connection is weak on |
+ auto premier_connections_by_network = GetPremierConnectionsByNetwork(); |
+ for (Connection* conn : connections_) { |
+ // Do not prune connections if the current premier connection is weak on |
// this network. Otherwise, it may delete connections prematurely. |
- if (!premier || premier->weak()) { |
- continue; |
- } |
- |
- for (Connection* conn : connections_) { |
- if ((conn != premier) && (conn->port()->Network() == network) && |
- (CompareConnectionCandidates(premier, conn) >= 0)) { |
- conn->Prune(); |
- } |
+ Connection* premier = |
+ premier_connections_by_network[conn->port()->Network()]; |
+ if (premier && conn != premier && !premier->weak() && |
+ CompareConnectionCandidates(premier, conn) >= 0) { |
+ conn->Prune(); |
} |
} |
} |
@@ -1471,26 +1483,6 @@ bool P2PTransportChannel::ReadyToSend(Connection* connection) const { |
PresumedWritable(connection)); |
} |
-// If we have a selected connection, return it, otherwise return top one in the |
-// list (later we will mark it best). |
-Connection* P2PTransportChannel::GetBestConnectionOnNetwork( |
- rtc::Network* network) const { |
- // If the selected connection is on this network, then it wins. |
- if (selected_connection_ && |
- (selected_connection_->port()->Network() == network)) { |
- return selected_connection_; |
- } |
- |
- // Otherwise, we return the top-most in sorted order. |
- for (size_t i = 0; i < connections_.size(); ++i) { |
- if (connections_[i]->port()->Network() == network) { |
- return connections_[i]; |
- } |
- } |
- |
- return NULL; |
-} |
- |
// Handle any queued up requests |
void P2PTransportChannel::OnMessage(rtc::Message *pmsg) { |
switch (pmsg->message_id) { |
@@ -1596,14 +1588,48 @@ bool P2PTransportChannel::IsPingable(const Connection* conn, |
return (now >= conn->last_ping_sent() + ping_interval); |
} |
-bool P2PTransportChannel::IsSelectedConnectionPingable(int64_t now) { |
- if (!selected_connection_ || !selected_connection_->connected() || |
- !selected_connection_->writable()) { |
+Connection* P2PTransportChannel::FindBestPremierConnectionToPing(int64_t now) { |
+ // If the selected connection is pingable, select it to ping. |
+ if (IsPremierConnectionPingable(selected_connection_, now)) { |
+ return selected_connection_; |
+ } |
+ // If the selected connection is strongly connected, don't bother to ping |
+ // premier connections on other networks at a higher priority. This prevents |
+ // a few premier connections from saturating all transmission slots for ping |
+ // and also prevents the backup connections from being pinged frequently. |
+ if (!weak()) { |
+ return nullptr; |
+ } |
+ |
+ // Otherwise, find the premier connection that has not been pinged for the |
+ // longest time. |
+ auto premier_connections_by_network = GetPremierConnectionsByNetwork(); |
+ Connection* oldest_pingable_premier_connection = nullptr; |
+ for (auto kv : premier_connections_by_network) { |
+ Connection* conn = kv.second; |
+ if (conn == nullptr || conn == selected_connection_) { |
+ continue; |
+ } |
+ if (IsPremierConnectionPingable(conn, now) && |
+ (!oldest_pingable_premier_connection || |
+ conn->last_ping_sent() < |
+ oldest_pingable_premier_connection->last_ping_sent())) { |
+ oldest_pingable_premier_connection = conn; |
+ } |
+ } |
+ return oldest_pingable_premier_connection; |
+} |
+ |
+bool P2PTransportChannel::IsPremierConnectionPingable( |
+ Connection* premier_connection, |
+ int64_t now) { |
+ if (!premier_connection || !premier_connection->connected() || |
+ !premier_connection->writable()) { |
return false; |
} |
- int interval = CalculateActiveWritablePingInterval(selected_connection_, now); |
- return selected_connection_->last_ping_sent() + interval <= now; |
+ int interval = CalculateActiveWritablePingInterval(premier_connection, now); |
+ return premier_connection->last_ping_sent() + interval <= now; |
} |
int P2PTransportChannel::CalculateActiveWritablePingInterval( |
@@ -1616,10 +1642,12 @@ int P2PTransportChannel::CalculateActiveWritablePingInterval( |
} |
int stable_interval = config_.stable_writable_connection_ping_interval; |
- int stablizing_interval = |
- std::min(stable_interval, STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
- |
- return conn->stable(now) ? stable_interval : stablizing_interval; |
+ int weak_or_stablizing_interval = std::min( |
+ stable_interval, WEAK_OR_STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
+ // If the channel is weak or the connection is not stable yet, use the |
+ // weak_or_stablizing_interval. |
+ return (!weak() && conn->stable(now)) ? stable_interval |
+ : weak_or_stablizing_interval; |
} |
// Returns the next pingable connection to ping. This will be the oldest |
@@ -1631,10 +1659,8 @@ int P2PTransportChannel::CalculateActiveWritablePingInterval( |
// CompareConnectionStates. |
Connection* P2PTransportChannel::FindNextPingableConnection() { |
int64_t now = rtc::TimeMillis(); |
- Connection* conn_to_ping = nullptr; |
- if (IsSelectedConnectionPingable(now)) { |
- conn_to_ping = selected_connection_; |
- } else { |
+ Connection* conn_to_ping = FindBestPremierConnectionToPing(now); |
+ if (!conn_to_ping) { |
conn_to_ping = FindConnectionToPing(now); |
} |
return conn_to_ping; |
@@ -1749,8 +1775,9 @@ void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) { |
unpinged_connections_.erase(*iter); |
connections_.erase(iter); |
- LOG_J(LS_INFO, this) << "Removed connection (" |
- << static_cast<int>(connections_.size()) << " remaining)"; |
+ LOG_J(LS_INFO, this) << "Removed connection " << std::hex << connection |
+ << std::dec << " (" << connections_.size() |
+ << " remaining)"; |
// If this is currently the selected connection, then we need to pick a new |
// one. The call to SortConnectionsAndUpdateState will pick a new one. It |
@@ -1878,7 +1905,7 @@ void P2PTransportChannel::OnReadyToSend(Connection* connection) { |
// Find "triggered checks". We ping first those connections that have |
// received a ping but have not sent a ping since receiving it |
-// (last_received_ping > last_sent_ping). But we shouldn't do |
+// (last_ping_received > last_ping_sent). But we shouldn't do |
// triggered checks if the connection is already writable. |
Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck( |
int64_t now) { |