| Index: webrtc/p2p/base/p2ptransportchannel.cc
|
| diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc
|
| index a4bde05d80cb9cac890e8aeaf81f76e3bd31611f..b5d6755ceeb605be67fd5814c85799e9fc911710 100644
|
| --- a/webrtc/p2p/base/p2ptransportchannel.cc
|
| +++ b/webrtc/p2p/base/p2ptransportchannel.cc
|
| @@ -27,7 +27,7 @@
|
| namespace {
|
|
|
| // messages for queuing up work for ourselves
|
| -enum { MSG_SORT = 1, MSG_CHECK_AND_PING };
|
| +enum { MSG_SORT_AND_UPDATE_STATE = 1, MSG_CHECK_AND_PING };
|
|
|
| // The minimum improvement in RTT that justifies a switch.
|
| static const double kMinImprovement = 10;
|
| @@ -287,7 +287,7 @@ void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag,
|
| static_cast<int>(remote_ice_parameters_.size() - 1));
|
| }
|
| // Updating the remote ICE candidate generation could change the sort order.
|
| - RequestSort();
|
| + RequestSortAndStateUpdate();
|
| }
|
|
|
| void P2PTransportChannel::SetRemoteIceMode(IceMode mode) {
|
| @@ -352,21 +352,10 @@ const IceConfig& P2PTransportChannel::config() const {
|
| return config_;
|
| }
|
|
|
| -// Go into the state of processing candidates, and running in general
|
| -void P2PTransportChannel::Connect() {
|
| - ASSERT(worker_thread_ == rtc::Thread::Current());
|
| +void P2PTransportChannel::MaybeStartGathering() {
|
| if (ice_ufrag_.empty() || ice_pwd_.empty()) {
|
| - ASSERT(false);
|
| - LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the "
|
| - << "ice_pwd_ are not set.";
|
| return;
|
| }
|
| -
|
| - // Start checking and pinging as the ports come in.
|
| - thread()->Post(RTC_FROM_HERE, this, MSG_CHECK_AND_PING);
|
| -}
|
| -
|
| -void P2PTransportChannel::MaybeStartGathering() {
|
| // Start gathering if we never started before, or if an ICE restart occurred.
|
| if (allocator_sessions_.empty() ||
|
| IceCredentialsChanged(allocator_sessions_.back()->ice_ufrag(),
|
| @@ -443,7 +432,7 @@ void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
|
| CreateConnection(port, *iter, iter->origin_port());
|
| }
|
|
|
| - SortConnections();
|
| + SortConnectionsAndUpdateState();
|
| }
|
|
|
| // A new candidate is available, let listeners know
|
| @@ -585,7 +574,7 @@ void P2PTransportChannel::OnUnknownAddress(
|
| // Update the list of connections since we just added another. We do this
|
| // after sending the response since it could (in principle) delete the
|
| // connection in question.
|
| - SortConnections();
|
| + SortConnectionsAndUpdateState();
|
| }
|
|
|
| void P2PTransportChannel::OnRoleConflict(PortInterface* port) {
|
| @@ -629,7 +618,7 @@ void P2PTransportChannel::OnNominated(Connection* conn) {
|
| SwitchSelectedConnection(conn);
|
| // Now that we have selected a connection, it is time to prune other
|
| // connections and update the read/write state of the channel.
|
| - RequestSort();
|
| + RequestSortAndStateUpdate();
|
| }
|
|
|
| void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
|
| @@ -676,7 +665,7 @@ void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
|
| CreateConnections(new_remote_candidate, NULL);
|
|
|
| // Resort the connections list, which may have new elements.
|
| - SortConnections();
|
| + SortConnectionsAndUpdateState();
|
| }
|
|
|
| void P2PTransportChannel::RemoveRemoteCandidate(
|
| @@ -942,18 +931,35 @@ void P2PTransportChannel::UpdateConnectionStates() {
|
|
|
| // We need to copy the list of connections since some may delete themselves
|
| // when we call UpdateState.
|
| - for (size_t i = 0; i < connections_.size(); ++i)
|
| - connections_[i]->UpdateState(now);
|
| + for (Connection* c : connections_) {
|
| + c->UpdateState(now);
|
| + }
|
| }
|
|
|
| // Prepare for best candidate sorting.
|
| -void P2PTransportChannel::RequestSort() {
|
| +void P2PTransportChannel::RequestSortAndStateUpdate() {
|
| if (!sort_dirty_) {
|
| - worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT);
|
| + worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT_AND_UPDATE_STATE);
|
| sort_dirty_ = true;
|
| }
|
| }
|
|
|
| +void P2PTransportChannel::MaybeStartPinging() {
|
| + if (started_pinging_) {
|
| + return;
|
| + }
|
| +
|
| + int64_t now = rtc::TimeMillis();
|
| + if (std::any_of(
|
| + connections_.begin(), connections_.end(),
|
| + [this, now](const Connection* c) { return IsPingable(c, now); })) {
|
| + LOG_J(LS_INFO, this) << "Have a pingable connection for the first time; "
|
| + << "starting to ping.";
|
| + thread()->Post(RTC_FROM_HERE, this, MSG_CHECK_AND_PING);
|
| + started_pinging_ = true;
|
| + }
|
| +}
|
| +
|
| // Compare two connections based on their writing, receiving, and connected
|
| // states.
|
| int P2PTransportChannel::CompareConnectionStates(const Connection* a,
|
| @@ -1096,7 +1102,7 @@ bool P2PTransportChannel::PresumedWritable(const Connection* conn) const {
|
|
|
| // Sort the available connections to find the best one. We also monitor
|
| // the number of available connections and the current state.
|
| -void P2PTransportChannel::SortConnections() {
|
| +void P2PTransportChannel::SortConnectionsAndUpdateState() {
|
| ASSERT(worker_thread_ == rtc::Thread::Current());
|
|
|
| // Make sure the connection states are up-to-date since this affects how they
|
| @@ -1165,9 +1171,15 @@ void P2PTransportChannel::SortConnections() {
|
| HandleAllTimedOut();
|
| }
|
|
|
| - // Update the state of this channel. This method is called whenever the
|
| - // state of any connection changes, so this is a good place to do this.
|
| + // Update the state of this channel.
|
| UpdateState();
|
| +
|
| + // Also possibly start pinging.
|
| + // We could start pinging if:
|
| + // * The first connection was created.
|
| + // * ICE credentials were provided.
|
| + // * A TCP connection became connected.
|
| + MaybeStartPinging();
|
| }
|
|
|
| void P2PTransportChannel::PruneConnections() {
|
| @@ -1238,7 +1250,7 @@ void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) {
|
| // transport controller will get the up-to-date channel state. However it
|
| // should not be called too often; in the case that multiple connection states
|
| // change, it should be called after all the connection states have changed. For
|
| -// example, we call this at the end of SortConnections.
|
| +// example, we call this at the end of SortConnectionsAndUpdateState.
|
| void P2PTransportChannel::UpdateState() {
|
| TransportChannelState state = ComputeState();
|
| if (state_ != state) {
|
| @@ -1358,8 +1370,8 @@ Connection* P2PTransportChannel::GetBestConnectionOnNetwork(
|
| // Handle any queued up requests
|
| void P2PTransportChannel::OnMessage(rtc::Message *pmsg) {
|
| switch (pmsg->message_id) {
|
| - case MSG_SORT:
|
| - OnSort();
|
| + case MSG_SORT_AND_UPDATE_STATE:
|
| + SortConnectionsAndUpdateState();
|
| break;
|
| case MSG_CHECK_AND_PING:
|
| OnCheckAndPing();
|
| @@ -1370,12 +1382,6 @@ void P2PTransportChannel::OnMessage(rtc::Message *pmsg) {
|
| }
|
| }
|
|
|
| -// Handle queued up sort request
|
| -void P2PTransportChannel::OnSort() {
|
| - // Resort the connections based on the new statistics.
|
| - SortConnections();
|
| -}
|
| -
|
| // Handle queued up check-and-ping request
|
| void P2PTransportChannel::OnCheckAndPing() {
|
| // Make sure the states of the connections are up-to-date (since this affects
|
| @@ -1405,7 +1411,7 @@ void P2PTransportChannel::OnCheckAndPing() {
|
|
|
| // A connection is considered a backup connection if the channel state
|
| // is completed, the connection is not the selected connection and it is active.
|
| -bool P2PTransportChannel::IsBackupConnection(Connection* conn) const {
|
| +bool P2PTransportChannel::IsBackupConnection(const Connection* conn) const {
|
| return state_ == STATE_COMPLETED && conn != selected_connection_ &&
|
| conn->active();
|
| }
|
| @@ -1413,7 +1419,8 @@ bool P2PTransportChannel::IsBackupConnection(Connection* conn) const {
|
| // Is the connection in a state for us to even consider pinging the other side?
|
| // We consider a connection pingable even if it's not connected because that's
|
| // how a TCP connection is kicked into reconnecting on the active side.
|
| -bool P2PTransportChannel::IsPingable(Connection* conn, int64_t now) {
|
| +bool P2PTransportChannel::IsPingable(const Connection* conn,
|
| + int64_t now) const {
|
| const Candidate& remote = conn->remote_candidate();
|
| // We should never get this far with an empty remote ufrag.
|
| ASSERT(!remote.username().empty());
|
| @@ -1471,8 +1478,9 @@ bool P2PTransportChannel::IsSelectedConnectionPingable(int64_t now) {
|
| return selected_connection_->last_ping_sent() + interval <= now;
|
| }
|
|
|
| -int P2PTransportChannel::CalculateActiveWritablePingInterval(Connection* conn,
|
| - int64_t now) {
|
| +int P2PTransportChannel::CalculateActiveWritablePingInterval(
|
| + const Connection* conn,
|
| + int64_t now) const {
|
| // Ping each connection at a higher rate at least
|
| // MIN_PINGS_AT_WEAK_PING_INTERVAL times.
|
| if (conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL) {
|
| @@ -1557,7 +1565,7 @@ void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
|
|
|
| // We have to unroll the stack before doing this because we may be changing
|
| // the state of connections while sorting.
|
| - RequestSort();
|
| + RequestSortAndStateUpdate();
|
| }
|
|
|
| // When a connection is removed, edit it out, and then update our best
|
| @@ -1580,18 +1588,21 @@ void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
|
| << static_cast<int>(connections_.size()) << " remaining)";
|
|
|
| // If this is currently the selected connection, then we need to pick a new
|
| - // one. The call to SortConnections will pick a new one. It looks at the
|
| - // current selected connection in order to avoid switching between fairly
|
| - // similar ones. Since this connection is no longer an option, we can just
|
| - // set selected to nullptr and re-choose a best assuming that there was no
|
| - // selected connection.
|
| + // one. The call to SortConnectionsAndUpdateState will pick a new one. It
|
| + // looks at the current selected connection in order to avoid switching
|
| + // between fairly similar ones. Since this connection is no longer an option,
|
| + // we can just set selected to nullptr and re-choose a best assuming that
|
| + // there was no selected connection.
|
| if (selected_connection_ == connection) {
|
| LOG(LS_INFO) << "selected connection destroyed. Will choose a new one.";
|
| SwitchSelectedConnection(nullptr);
|
| - RequestSort();
|
| + RequestSortAndStateUpdate();
|
| + } else {
|
| + // If a non-selected connection was destroyed, we don't need to re-sort but
|
| + // we do need to update state, because we could be switching to "failed" or
|
| + // "completed".
|
| + UpdateState();
|
| }
|
| -
|
| - UpdateState();
|
| }
|
|
|
| // When a port is destroyed remove it from our list of ports to use for
|
|
|