OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
73 const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000; | 73 const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000; |
74 | 74 |
75 // Writable connections are pinged at a faster rate while stabilizing. | 75 // Writable connections are pinged at a faster rate while stabilizing. |
76 const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms | 76 const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms |
77 | 77 |
78 // Writable connections are pinged at a slower rate once stabilized. | 78 // Writable connections are pinged at a slower rate once stabilized. |
79 const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms | 79 const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms |
80 | 80 |
81 static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms | 81 static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms |
82 | 82 |
83 static const int RECEIVING_DAMPENING_INTERVAL = 500; // ms | |
pthatcher1
2016/07/13 21:17:23
I think we should be conservative with the value f
honghaiz3
2016/07/14 04:54:20
There is actually some risk of choosing the same d
| |
84 | |
83 // We periodically check if any existing networks do not have any connection | 85 // We periodically check if any existing networks do not have any connection |
84 // and regather on those networks. | 86 // and regather on those networks. |
85 static const int DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL = 5 * 60 * 1000; | 87 static const int DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL = 5 * 60 * 1000; |
86 static constexpr int a_is_better = 1; | 88 static constexpr int a_is_better = 1; |
87 static constexpr int b_is_better = -1; | 89 static constexpr int b_is_better = -1; |
88 | 90 |
89 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, | 91 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
90 int component, | 92 int component, |
91 P2PTransport* transport, | 93 P2PTransport* transport, |
92 PortAllocator* allocator) | 94 PortAllocator* allocator) |
(...skipping 12 matching lines...) Expand all Loading... | |
105 ice_role_(ICEROLE_UNKNOWN), | 107 ice_role_(ICEROLE_UNKNOWN), |
106 tiebreaker_(0), | 108 tiebreaker_(0), |
107 gathering_state_(kIceGatheringNew), | 109 gathering_state_(kIceGatheringNew), |
108 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), | 110 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), |
109 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, | 111 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, |
110 0 /* backup_connection_ping_interval */, | 112 0 /* backup_connection_ping_interval */, |
111 GATHER_ONCE /* continual_gathering_policy */, | 113 GATHER_ONCE /* continual_gathering_policy */, |
112 false /* prioritize_most_likely_candidate_pairs */, | 114 false /* prioritize_most_likely_candidate_pairs */, |
113 STABLE_WRITABLE_CONNECTION_PING_INTERVAL, | 115 STABLE_WRITABLE_CONNECTION_PING_INTERVAL, |
114 true /* presume_writable_when_fully_relayed */, | 116 true /* presume_writable_when_fully_relayed */, |
115 DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL) { | 117 DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL, |
118 RECEIVING_DAMPENING_INTERVAL) { | |
116 uint32_t weak_ping_interval = ::strtoul( | 119 uint32_t weak_ping_interval = ::strtoul( |
117 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), | 120 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), |
118 nullptr, 10); | 121 nullptr, 10); |
119 if (weak_ping_interval) { | 122 if (weak_ping_interval) { |
120 weak_ping_interval_ = static_cast<int>(weak_ping_interval); | 123 weak_ping_interval_ = static_cast<int>(weak_ping_interval); |
121 } | 124 } |
122 } | 125 } |
123 | 126 |
124 P2PTransportChannel::~P2PTransportChannel() { | 127 P2PTransportChannel::~P2PTransportChannel() { |
125 ASSERT(worker_thread_ == rtc::Thread::Current()); | 128 ASSERT(worker_thread_ == rtc::Thread::Current()); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 // criteria is as follows: | 180 // criteria is as follows: |
178 // i) write/receiving/connected states | 181 // i) write/receiving/connected states |
179 // ii) For controlled side, | 182 // ii) For controlled side, |
180 // a) nomination state, | 183 // a) nomination state, |
181 // b) last data received time. | 184 // b) last data received time. |
182 // iii) Lower cost / higher priority. | 185 // iii) Lower cost / higher priority. |
183 // iv) rtt. | 186 // iv) rtt. |
184 // TODO(honghaiz): Stop the aggressive nomination on the controlling side and | 187 // TODO(honghaiz): Stop the aggressive nomination on the controlling side and |
185 // implement the ice-renomination option. | 188 // implement the ice-renomination option. |
186 bool P2PTransportChannel::ShouldSwitchSelectedConnection( | 189 bool P2PTransportChannel::ShouldSwitchSelectedConnection( |
187 Connection* new_connection) const { | 190 Connection* new_connection) { |
188 if (!new_connection || selected_connection_ == new_connection) { | 191 if (!new_connection || selected_connection_ == new_connection) { |
189 return false; | 192 return false; |
190 } | 193 } |
191 | 194 |
192 if (selected_connection_ == nullptr) { | 195 if (selected_connection_ == nullptr) { |
193 return true; | 196 return true; |
194 } | 197 } |
195 | 198 |
196 int cmp = CompareConnections(selected_connection_, new_connection); | 199 bool connection_dampened = false; |
200 int cmp = CompareConnectionStatesWithDampening( | |
201 selected_connection_, new_connection, &connection_dampened); | |
197 if (cmp != 0) { | 202 if (cmp != 0) { |
198 return cmp < 0; | 203 return cmp < 0; |
199 } | 204 } |
205 // A connection is dampened indicates that it is in a better receiving state, | |
206 // so we need to remember it and check it again periodically. | |
207 if (connection_dampened) { | |
208 pending_selected_connection_ = new_connection; | |
209 } | |
pthatcher1
2016/07/13 21:17:23
I don't like the idea of ShouldSwitchSelectedConne
honghaiz3
2016/07/14 04:54:20
Done for other parts except that
ShouldSwitchSelec
pthatcher1
2016/07/14 18:01:44
Can't the *caller* of ShouldSwitchSelectedConnecti
| |
210 | |
211 cmp = CompareConnectionsWithoutStates(selected_connection_, new_connection); | |
pthatcher1
2016/07/13 21:17:23
I also think it would be more simple to keep it as
honghaiz3
2016/07/14 04:54:21
Done.
| |
212 if (cmp != 0) { | |
213 return cmp < 0; | |
214 } | |
200 | 215 |
201 // If everything else is the same, switch only if rtt has improved by | 216 // If everything else is the same, switch only if rtt has improved by |
202 // a margin. | 217 // a margin. |
203 return new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement; | 218 return new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement; |
204 } | 219 } |
205 | 220 |
206 void P2PTransportChannel::SetIceRole(IceRole ice_role) { | 221 void P2PTransportChannel::SetIceRole(IceRole ice_role) { |
207 ASSERT(worker_thread_ == rtc::Thread::Current()); | 222 ASSERT(worker_thread_ == rtc::Thread::Current()); |
208 if (ice_role_ != ice_role) { | 223 if (ice_role_ != ice_role) { |
209 ice_role_ = ice_role; | 224 ice_role_ = ice_role; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
362 << config_.presume_writable_when_fully_relayed; | 377 << config_.presume_writable_when_fully_relayed; |
363 } | 378 } |
364 } | 379 } |
365 | 380 |
366 if (config.regather_on_failed_networks_interval) { | 381 if (config.regather_on_failed_networks_interval) { |
367 config_.regather_on_failed_networks_interval = | 382 config_.regather_on_failed_networks_interval = |
368 config.regather_on_failed_networks_interval; | 383 config.regather_on_failed_networks_interval; |
369 LOG(LS_INFO) << "Set regather_on_failed_networks_interval to " | 384 LOG(LS_INFO) << "Set regather_on_failed_networks_interval to " |
370 << *config_.regather_on_failed_networks_interval; | 385 << *config_.regather_on_failed_networks_interval; |
371 } | 386 } |
387 if (config.receiving_dampening_interval) { | |
388 config_.receiving_dampening_interval = config.receiving_dampening_interval; | |
389 LOG(LS_INFO) << "Set receiving_dampening_interval to" | |
390 << *config_.receiving_dampening_interval; | |
391 } | |
372 } | 392 } |
373 | 393 |
374 const IceConfig& P2PTransportChannel::config() const { | 394 const IceConfig& P2PTransportChannel::config() const { |
375 return config_; | 395 return config_; |
376 } | 396 } |
377 | 397 |
378 void P2PTransportChannel::MaybeStartGathering() { | 398 void P2PTransportChannel::MaybeStartGathering() { |
379 if (ice_ufrag_.empty() || ice_pwd_.empty()) { | 399 if (ice_ufrag_.empty() || ice_pwd_.empty()) { |
380 return; | 400 return; |
381 } | 401 } |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
628 } | 648 } |
629 | 649 |
630 if (!ShouldSwitchSelectedConnection(conn)) { | 650 if (!ShouldSwitchSelectedConnection(conn)) { |
631 LOG(LS_INFO) | 651 LOG(LS_INFO) |
632 << "Not switching the selected connection on controlled side yet: " | 652 << "Not switching the selected connection on controlled side yet: " |
633 << conn->ToString(); | 653 << conn->ToString(); |
634 return; | 654 return; |
635 } | 655 } |
636 | 656 |
637 LOG(LS_INFO) | 657 LOG(LS_INFO) |
638 << "Switching selected connection on controlled side due to nomination: " | 658 << "Switching selected connection on controlled side due to nomination."; |
639 << conn->ToString(); | |
640 SwitchSelectedConnection(conn); | 659 SwitchSelectedConnection(conn); |
641 // Now that we have selected a connection, it is time to prune other | 660 // Now that we have selected a connection, it is time to prune other |
642 // connections and update the read/write state of the channel. | 661 // connections and update the read/write state of the channel. |
643 RequestSortAndStateUpdate(); | 662 RequestSortAndStateUpdate(); |
644 } | 663 } |
645 | 664 |
646 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { | 665 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { |
647 ASSERT(worker_thread_ == rtc::Thread::Current()); | 666 ASSERT(worker_thread_ == rtc::Thread::Current()); |
648 | 667 |
649 uint32_t generation = GetRemoteCandidateGeneration(candidate); | 668 uint32_t generation = GetRemoteCandidateGeneration(candidate); |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
949 | 968 |
950 // Monitor connection states. | 969 // Monitor connection states. |
951 void P2PTransportChannel::UpdateConnectionStates() { | 970 void P2PTransportChannel::UpdateConnectionStates() { |
952 int64_t now = rtc::TimeMillis(); | 971 int64_t now = rtc::TimeMillis(); |
953 | 972 |
954 // We need to copy the list of connections since some may delete themselves | 973 // We need to copy the list of connections since some may delete themselves |
955 // when we call UpdateState. | 974 // when we call UpdateState. |
956 for (Connection* c : connections_) { | 975 for (Connection* c : connections_) { |
957 c->UpdateState(now); | 976 c->UpdateState(now); |
958 } | 977 } |
978 | |
979 if (!selected_connection_) { | |
980 was_strong_ = false; | |
981 return; | |
982 } | |
983 bool is_strong = !selected_connection_->weak(); | |
984 if (was_strong_ && !is_strong) { | |
985 // If the selected connection just changes to weak, reset the number of | |
986 // pings sent on the selected connection so that it will be pinged at least | |
987 // a few times. | |
988 selected_connection_->reset_num_pings_sent(); | |
989 for (Connection* c : connections_) { | |
990 c->reset_first_received_since_channel_weak(); | |
991 } | |
992 } | |
993 was_strong_ = is_strong; | |
pthatcher1
2016/07/13 21:17:23
I think we can calculate the "has it been receivin
honghaiz3
2016/07/14 04:54:21
We can do that. But a potential problem is that if
| |
959 } | 994 } |
960 | 995 |
961 // Prepare for best candidate sorting. | 996 // Prepare for best candidate sorting. |
962 void P2PTransportChannel::RequestSortAndStateUpdate() { | 997 void P2PTransportChannel::RequestSortAndStateUpdate() { |
963 if (!sort_dirty_) { | 998 if (!sort_dirty_) { |
964 worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT_AND_UPDATE_STATE); | 999 worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT_AND_UPDATE_STATE); |
965 sort_dirty_ = true; | 1000 sort_dirty_ = true; |
966 } | 1001 } |
967 } | 1002 } |
968 | 1003 |
969 void P2PTransportChannel::MaybeStartPinging() { | 1004 void P2PTransportChannel::MaybeStartPinging() { |
970 if (started_pinging_) { | 1005 if (started_pinging_) { |
971 return; | 1006 return; |
972 } | 1007 } |
973 | 1008 |
974 int64_t now = rtc::TimeMillis(); | 1009 int64_t now = rtc::TimeMillis(); |
975 if (std::any_of( | 1010 if (std::any_of( |
976 connections_.begin(), connections_.end(), | 1011 connections_.begin(), connections_.end(), |
977 [this, now](const Connection* c) { return IsPingable(c, now); })) { | 1012 [this, now](const Connection* c) { return IsPingable(c, now); })) { |
978 LOG_J(LS_INFO, this) << "Have a pingable connection for the first time; " | 1013 LOG_J(LS_INFO, this) << "Have a pingable connection for the first time; " |
979 << "starting to ping."; | 1014 << "starting to ping."; |
980 thread()->Post(RTC_FROM_HERE, this, MSG_CHECK_AND_PING); | 1015 thread()->Post(RTC_FROM_HERE, this, MSG_CHECK_AND_PING); |
981 thread()->PostDelayed(RTC_FROM_HERE, | 1016 thread()->PostDelayed(RTC_FROM_HERE, |
982 *config_.regather_on_failed_networks_interval, this, | 1017 *config_.regather_on_failed_networks_interval, this, |
983 MSG_REGATHER_ON_FAILED_NETWORKS); | 1018 MSG_REGATHER_ON_FAILED_NETWORKS); |
984 started_pinging_ = true; | 1019 started_pinging_ = true; |
985 } | 1020 } |
986 } | 1021 } |
987 | 1022 |
988 // Compare two connections based on their writing, receiving, and connected | 1023 int P2PTransportChannel::CompareConnectionWriteAndConnectedStates( |
989 // states. | 1024 const Connection* a, |
990 int P2PTransportChannel::CompareConnectionStates(const Connection* a, | 1025 const Connection* b) const { |
991 const Connection* b) const { | |
992 // First, prefer a connection that's writable or presumed writable over | 1026 // First, prefer a connection that's writable or presumed writable over |
993 // one that's not writable. | 1027 // one that's not writable. |
994 bool a_writable = a->writable() || PresumedWritable(a); | 1028 bool a_writable = a->writable() || PresumedWritable(a); |
995 bool b_writable = b->writable() || PresumedWritable(b); | 1029 bool b_writable = b->writable() || PresumedWritable(b); |
996 if (a_writable && !b_writable) { | 1030 if (a_writable && !b_writable) { |
997 return a_is_better; | 1031 return a_is_better; |
998 } | 1032 } |
999 if (!a_writable && b_writable) { | 1033 if (!a_writable && b_writable) { |
1000 return b_is_better; | 1034 return b_is_better; |
1001 } | 1035 } |
1002 | 1036 |
1003 // Sort based on write-state. Better states have lower values. | 1037 // Better write-states have lower values, and a negative return value |
1004 if (a->write_state() < b->write_state()) { | 1038 // indicates b is better. |
1005 return a_is_better; | 1039 int cmp = b->write_state() - a->write_state(); |
1006 } | 1040 if (cmp != 0) { |
1007 if (b->write_state() < a->write_state()) { | 1041 return cmp; |
1008 return b_is_better; | |
1009 } | |
1010 | |
1011 // We prefer a receiving connection to a non-receiving, higher-priority | |
1012 // connection when sorting connections and choosing which connection to | |
1013 // switch to. | |
1014 if (a->receiving() && !b->receiving()) { | |
1015 return a_is_better; | |
1016 } | |
1017 if (!a->receiving() && b->receiving()) { | |
1018 return b_is_better; | |
1019 } | 1042 } |
1020 | 1043 |
1021 // WARNING: Some complexity here about TCP reconnecting. | 1044 // WARNING: Some complexity here about TCP reconnecting. |
1022 // When a TCP connection fails because of a TCP socket disconnecting, the | 1045 // When a TCP connection fails because of a TCP socket disconnecting, the |
1023 // active side of the connection will attempt to reconnect for 5 seconds while | 1046 // active side of the connection will attempt to reconnect for 5 seconds while |
1024 // pretending to be writable (the connection is not set to the unwritable | 1047 // pretending to be writable (the connection is not set to the unwritable |
1025 // state). On the passive side, the connection also remains writable even | 1048 // state). On the passive side, the connection also remains writable even |
1026 // though it is disconnected, and a new connection is created when the active | 1049 // though it is disconnected, and a new connection is created when the active |
1027 // side connects. At that point, there are two TCP connections on the passive | 1050 // side connects. At that point, there are two TCP connections on the passive |
1028 // side: 1. the old, disconnected one that is pretending to be writable, and | 1051 // side: 1. the old, disconnected one that is pretending to be writable, and |
(...skipping 16 matching lines...) Expand all Loading... | |
1045 if (a->connected() && !b->connected()) { | 1068 if (a->connected() && !b->connected()) { |
1046 return a_is_better; | 1069 return a_is_better; |
1047 } | 1070 } |
1048 if (!a->connected() && b->connected()) { | 1071 if (!a->connected() && b->connected()) { |
1049 return b_is_better; | 1072 return b_is_better; |
1050 } | 1073 } |
1051 } | 1074 } |
1052 return 0; | 1075 return 0; |
1053 } | 1076 } |
1054 | 1077 |
1078 // Compare two connections based on their writing, connected, and receiving | |
1079 // states. | |
1080 int P2PTransportChannel::CompareConnectionStates(const Connection* a, | |
1081 const Connection* b) const { | |
1082 int cmp = CompareConnectionWriteAndConnectedStates(a, b); | |
1083 if (cmp != 0) { | |
1084 return cmp; | |
1085 } | |
1086 | |
1087 // We prefer a receiving connection to a non-receiving, higher-priority | |
1088 // connection when sorting connections. | |
1089 if (a->receiving() && !b->receiving()) { | |
1090 return a_is_better; | |
1091 } | |
1092 if (!a->receiving() && b->receiving()) { | |
1093 return b_is_better; | |
1094 } | |
pthatcher1
2016/07/13 21:17:22
Doesn't this change the order so that connected vs
honghaiz3
2016/07/14 04:54:20
I did not think that should have a major impact al
| |
1095 | |
1096 return 0; | |
1097 } | |
1098 | |
1099 int P2PTransportChannel::CompareConnectionStatesWithDampening( | |
1100 const Connection* selected_conn, | |
1101 const Connection* new_conn, | |
pthatcher1
2016/07/13 21:17:23
CompareConnectionX should know about "selected" an
honghaiz3
2016/07/14 04:54:20
Done
| |
1102 bool* new_conn_dampened) const { | |
1103 int cmp = CompareConnectionWriteAndConnectedStates(selected_conn, new_conn); | |
1104 if (cmp != 0) { | |
1105 return cmp; | |
1106 } | |
1107 | |
1108 if (selected_conn->receiving() && !new_conn->receiving()) { | |
1109 return a_is_better; | |
1110 } | |
1111 | |
1112 if (!selected_conn->receiving() && new_conn->receiving()) { | |
1113 // If |selected_conn| is not receiving and |new_conn| is receiving, we wait | |
1114 // for a short while before switching to the new connection. | |
1115 if (new_conn->first_received_since_channel_weak() != 0 && | |
1116 rtc::TimeMillis() - new_conn->first_received_since_channel_weak() >= | |
1117 *config_.receiving_dampening_interval) { | |
pthatcher1
2016/07/13 21:17:22
I think it would make more sense to have the Conne
honghaiz3
2016/07/14 04:54:20
Done, somewhat different though.
| |
1118 return b_is_better; | |
1119 } | |
1120 *new_conn_dampened = true; | |
1121 } | |
1122 | |
1123 return 0; | |
1124 } | |
1125 | |
1055 // Compares two connections based only on the candidate and network information. | 1126 // Compares two connections based only on the candidate and network information. |
1056 // Returns positive if |a| is better than |b|. | 1127 // Returns positive if |a| is better than |b|. |
1057 int P2PTransportChannel::CompareConnectionCandidates( | 1128 int P2PTransportChannel::CompareConnectionCandidates( |
1058 const Connection* a, | 1129 const Connection* a, |
1059 const Connection* b) const { | 1130 const Connection* b) const { |
1060 // Prefer lower network cost. | 1131 // Prefer lower network cost. |
1061 uint32_t a_cost = a->ComputeNetworkCost(); | 1132 uint32_t a_cost = a->ComputeNetworkCost(); |
1062 uint32_t b_cost = b->ComputeNetworkCost(); | 1133 uint32_t b_cost = b->ComputeNetworkCost(); |
1063 // Smaller cost is better. | 1134 // Smaller cost is better. |
1064 if (a_cost < b_cost) { | 1135 if (a_cost < b_cost) { |
(...skipping 10 matching lines...) Expand all Loading... | |
1075 if (a->priority() < b->priority()) { | 1146 if (a->priority() < b->priority()) { |
1076 return b_is_better; | 1147 return b_is_better; |
1077 } | 1148 } |
1078 | 1149 |
1079 // If we're still tied at this point, prefer a younger generation. | 1150 // If we're still tied at this point, prefer a younger generation. |
1080 // (Younger generation means a larger generation number). | 1151 // (Younger generation means a larger generation number). |
1081 return (a->remote_candidate().generation() + a->port()->generation()) - | 1152 return (a->remote_candidate().generation() + a->port()->generation()) - |
1082 (b->remote_candidate().generation() + b->port()->generation()); | 1153 (b->remote_candidate().generation() + b->port()->generation()); |
1083 } | 1154 } |
1084 | 1155 |
1085 int P2PTransportChannel::CompareConnections(const Connection* a, | 1156 int P2PTransportChannel::CompareConnectionsWithoutStates( |
1086 const Connection* b) const { | 1157 const Connection* a, |
1158 const Connection* b) const { | |
1087 RTC_CHECK(a != nullptr); | 1159 RTC_CHECK(a != nullptr); |
1088 RTC_CHECK(b != nullptr); | 1160 RTC_CHECK(b != nullptr); |
1089 | 1161 |
1090 // We prefer to switch to a writable and receiving connection over a | |
1091 // non-writable or non-receiving connection, even if the latter has | |
1092 // been nominated by the controlling side. | |
1093 int state_cmp = CompareConnectionStates(a, b); | |
1094 if (state_cmp != 0) { | |
1095 return state_cmp; | |
1096 } | |
1097 | |
1098 if (ice_role_ == ICEROLE_CONTROLLED) { | 1162 if (ice_role_ == ICEROLE_CONTROLLED) { |
1099 // Compare the connections based on the nomination states and the last data | 1163 // Compare the connections based on the nomination states and the last data |
1100 // received time if this is on the controlled side. | 1164 // received time if this is on the controlled side. |
1101 if (a->nominated() && !b->nominated()) { | 1165 if (a->nominated() && !b->nominated()) { |
1102 return a_is_better; | 1166 return a_is_better; |
1103 } | 1167 } |
1104 if (!a->nominated() && b->nominated()) { | 1168 if (!a->nominated() && b->nominated()) { |
1105 return b_is_better; | 1169 return b_is_better; |
1106 } | 1170 } |
1107 | 1171 |
1108 if (a->last_data_received() > b->last_data_received()) { | 1172 if (a->last_data_received() > b->last_data_received()) { |
1109 return a_is_better; | 1173 return a_is_better; |
1110 } | 1174 } |
1111 if (a->last_data_received() < b->last_data_received()) { | 1175 if (a->last_data_received() < b->last_data_received()) { |
1112 return b_is_better; | 1176 return b_is_better; |
1113 } | 1177 } |
1114 } | 1178 } |
1115 | 1179 |
1116 // Compare the network cost and priority. | 1180 // Compare the network cost and priority. |
1117 return CompareConnectionCandidates(a, b); | 1181 return CompareConnectionCandidates(a, b); |
1118 } | 1182 } |
1119 | 1183 |
1184 int P2PTransportChannel::CompareConnections(const Connection* a, | |
1185 const Connection* b) const { | |
1186 // We prefer to switch to a writable and receiving connection over a | |
1187 // non-writable or non-receiving connection, even if the latter has | |
1188 // been nominated by the controlling side. | |
1189 int cmp = CompareConnectionStates(a, b); | |
1190 if (cmp != 0) { | |
1191 return cmp; | |
1192 } | |
1193 cmp = CompareConnectionsWithoutStates(a, b); | |
1194 if (cmp != 0) { | |
1195 return cmp; | |
1196 } | |
1197 // Otherwise, compare the latency estimate. Note that a negative return value | |
1198 // indicates |b| is better. | |
1199 return b->rtt() - a->rtt(); | |
1200 } | |
1201 | |
1120 bool P2PTransportChannel::PresumedWritable(const Connection* conn) const { | 1202 bool P2PTransportChannel::PresumedWritable(const Connection* conn) const { |
1121 return (conn->write_state() == Connection::STATE_WRITE_INIT && | 1203 return (conn->write_state() == Connection::STATE_WRITE_INIT && |
1122 config_.presume_writable_when_fully_relayed && | 1204 config_.presume_writable_when_fully_relayed && |
1123 conn->local_candidate().type() == RELAY_PORT_TYPE && | 1205 conn->local_candidate().type() == RELAY_PORT_TYPE && |
1124 (conn->remote_candidate().type() == RELAY_PORT_TYPE || | 1206 (conn->remote_candidate().type() == RELAY_PORT_TYPE || |
1125 conn->remote_candidate().type() == PRFLX_PORT_TYPE)); | 1207 conn->remote_candidate().type() == PRFLX_PORT_TYPE)); |
1126 } | 1208 } |
1127 | 1209 |
1128 // Sort the available connections to find the best one. We also monitor | 1210 // Sort the available connections to find the best one. We also monitor |
1129 // the number of available connections and the current state. | 1211 // the number of available connections and the current state. |
1130 void P2PTransportChannel::SortConnectionsAndUpdateState() { | 1212 void P2PTransportChannel::SortConnectionsAndUpdateState() { |
1131 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1213 ASSERT(worker_thread_ == rtc::Thread::Current()); |
1132 | 1214 |
1133 // Make sure the connection states are up-to-date since this affects how they | 1215 // Make sure the connection states are up-to-date since this affects how they |
1134 // will be sorted. | 1216 // will be sorted. |
1135 UpdateConnectionStates(); | 1217 UpdateConnectionStates(); |
1136 | 1218 |
1137 // Any changes after this point will require a re-sort. | 1219 // Any changes after this point will require a re-sort. |
1138 sort_dirty_ = false; | 1220 sort_dirty_ = false; |
1139 | 1221 |
1140 // Find the best alternative connection by sorting. It is important to note | 1222 // Find the best alternative connection by sorting. It is important to note |
1141 // that amongst equal preference, writable connections, this will choose the | 1223 // that amongst equal preference, writable connections, this will choose the |
1142 // one whose estimated latency is lowest. So it is the only one that we | 1224 // one whose estimated latency is lowest. So it is the only one that we |
1143 // need to consider switching to. | 1225 // need to consider switching to. |
1144 std::stable_sort(connections_.begin(), connections_.end(), | 1226 std::stable_sort(connections_.begin(), connections_.end(), |
1145 [this](const Connection* a, const Connection* b) { | 1227 [this](const Connection* a, const Connection* b) { |
1146 int cmp = CompareConnections(a, b); | 1228 return CompareConnections(a, b) > 0; |
pthatcher1
2016/07/13 21:17:22
I think it would be less risky to leave the Compar
honghaiz3
2016/07/14 04:54:20
Done.
| |
1147 if (cmp != 0) { | |
1148 return cmp > 0; | |
1149 } | |
1150 | 1229 |
1151 // Otherwise, sort based on latency estimate. | |
1152 return a->rtt() < b->rtt(); | |
1153 }); | 1230 }); |
1154 | 1231 |
1155 LOG(LS_VERBOSE) << "Sorting " << connections_.size() | 1232 LOG(LS_VERBOSE) << "Sorting " << connections_.size() |
1156 << " available connections:"; | 1233 << " available connections:"; |
1157 for (size_t i = 0; i < connections_.size(); ++i) { | 1234 for (size_t i = 0; i < connections_.size(); ++i) { |
1158 LOG(LS_VERBOSE) << connections_[i]->ToString(); | 1235 LOG(LS_VERBOSE) << connections_[i]->ToString(); |
1159 } | 1236 } |
1160 | 1237 |
1161 Connection* top_connection = | 1238 Connection* top_connection = |
1162 (connections_.size() > 0) ? connections_[0] : nullptr; | 1239 (connections_.size() > 0) ? connections_[0] : nullptr; |
1163 | 1240 |
1164 // If necessary, switch to the new choice. Note that |top_connection| doesn't | 1241 // If necessary, switch to the new choice. Note that |top_connection| doesn't |
1165 // have to be writable to become the selected connection although it will | 1242 // have to be writable to become the selected connection although it will |
1166 // have higher priority if it is writable. | 1243 // have higher priority if it is writable. |
1167 if (ShouldSwitchSelectedConnection(top_connection)) { | 1244 if (ShouldSwitchSelectedConnection(top_connection)) { |
1168 LOG(LS_INFO) << "Switching selected connection after sorting: " | 1245 LOG(LS_INFO) << "Switching selected connection after sorting"; |
1169 << top_connection->ToString(); | |
1170 SwitchSelectedConnection(top_connection); | 1246 SwitchSelectedConnection(top_connection); |
1171 } | 1247 } |
1172 | 1248 |
1173 // The controlled side can prune only if the selected connection has been | 1249 // The controlled side can prune only if the selected connection has been |
1174 // nominated because otherwise it may prune the connection that will be | 1250 // nominated because otherwise it may prune the connection that will be |
1175 // selected by the controlling side. | 1251 // selected by the controlling side. |
1176 // TODO(honghaiz): This is not enough to prevent a connection from being | 1252 // TODO(honghaiz): This is not enough to prevent a connection from being |
1177 // pruned too early because with aggressive nomination, the controlling side | 1253 // pruned too early because with aggressive nomination, the controlling side |
1178 // will nominate every connection until it becomes writable. | 1254 // will nominate every connection until it becomes writable. |
1179 if (ice_role_ == ICEROLE_CONTROLLING || | 1255 if (ice_role_ == ICEROLE_CONTROLLING || |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1240 } | 1316 } |
1241 } | 1317 } |
1242 | 1318 |
1243 // Change the selected connection, and let listeners know. | 1319 // Change the selected connection, and let listeners know. |
1244 void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) { | 1320 void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) { |
1245 // Note: if conn is NULL, the previous |selected_connection_| has been | 1321 // Note: if conn is NULL, the previous |selected_connection_| has been |
1246 // destroyed, so don't use it. | 1322 // destroyed, so don't use it. |
1247 Connection* old_selected_connection = selected_connection_; | 1323 Connection* old_selected_connection = selected_connection_; |
1248 selected_connection_ = conn; | 1324 selected_connection_ = conn; |
1249 if (selected_connection_) { | 1325 if (selected_connection_) { |
1326 if (pending_selected_connection_ == selected_connection_) { | |
1327 pending_selected_connection_ = nullptr; | |
1328 } | |
1250 if (old_selected_connection) { | 1329 if (old_selected_connection) { |
1251 LOG_J(LS_INFO, this) << "Previous selected connection: " | 1330 LOG_J(LS_INFO, this) << "Previous selected connection: " |
1252 << old_selected_connection->ToString(); | 1331 << old_selected_connection->ToString(); |
1253 } | 1332 } |
1254 LOG_J(LS_INFO, this) << "New selected connection: " | 1333 LOG_J(LS_INFO, this) << "New selected connection: " |
1255 << selected_connection_->ToString(); | 1334 << selected_connection_->ToString(); |
1256 SignalRouteChange(this, selected_connection_->remote_candidate()); | 1335 SignalRouteChange(this, selected_connection_->remote_candidate()); |
1257 // This is a temporary, but safe fix to webrtc issue 5705. | 1336 // This is a temporary, but safe fix to webrtc issue 5705. |
1258 // TODO(honghaiz): Make all EWOULDBLOCK error routed through the transport | 1337 // TODO(honghaiz): Make all EWOULDBLOCK error routed through the transport |
1259 // channel so that it knows whether the media channel is allowed to | 1338 // channel so that it knows whether the media channel is allowed to |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1408 ASSERT(false); | 1487 ASSERT(false); |
1409 break; | 1488 break; |
1410 } | 1489 } |
1411 } | 1490 } |
1412 | 1491 |
1413 // Handle queued up check-and-ping request | 1492 // Handle queued up check-and-ping request |
1414 void P2PTransportChannel::OnCheckAndPing() { | 1493 void P2PTransportChannel::OnCheckAndPing() { |
1415 // Make sure the states of the connections are up-to-date (since this affects | 1494 // Make sure the states of the connections are up-to-date (since this affects |
1416 // which ones are pingable). | 1495 // which ones are pingable). |
1417 UpdateConnectionStates(); | 1496 UpdateConnectionStates(); |
1497 if (pending_selected_connection_) { | |
1498 if (ShouldSwitchSelectedConnection(pending_selected_connection_)) { | |
1499 LOG(LS_INFO) << "Switching selected connection to a pending one"; | |
1500 SwitchSelectedConnection(pending_selected_connection_); | |
1501 } else if (!weak()) { | |
1502 pending_selected_connection_ = nullptr; | |
1503 } | |
1504 } | |
pthatcher1
2016/07/13 21:17:23
This code, or the equivalent, really should be ins
honghaiz3
2016/07/14 04:54:20
This serves the purpose of periodical checking the
| |
1505 | |
1418 // When the selected connection is not receiving or not writable, or any | 1506 // When the selected connection is not receiving or not writable, or any |
1419 // active connection has not been pinged enough times, use the weak ping | 1507 // active connection has not been pinged enough times, use the weak ping |
1420 // interval. | 1508 // interval. |
1421 bool need_more_pings_at_weak_interval = std::any_of( | 1509 bool need_more_pings_at_weak_interval = std::any_of( |
1422 connections_.begin(), connections_.end(), [](Connection* conn) { | 1510 connections_.begin(), connections_.end(), [](Connection* conn) { |
1423 return conn->active() && | 1511 return conn->active() && |
1424 conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL; | 1512 conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL; |
1425 }); | 1513 }); |
1426 int ping_interval = (weak() || need_more_pings_at_weak_interval) | 1514 int ping_interval = (weak() || need_more_pings_at_weak_interval) |
1427 ? weak_ping_interval_ | 1515 ? weak_ping_interval_ |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1615 LOG_J(LS_INFO, this) << "Removed connection (" | 1703 LOG_J(LS_INFO, this) << "Removed connection (" |
1616 << static_cast<int>(connections_.size()) << " remaining)"; | 1704 << static_cast<int>(connections_.size()) << " remaining)"; |
1617 | 1705 |
1618 // If this is currently the selected connection, then we need to pick a new | 1706 // If this is currently the selected connection, then we need to pick a new |
1619 // one. The call to SortConnectionsAndUpdateState will pick a new one. It | 1707 // one. The call to SortConnectionsAndUpdateState will pick a new one. It |
1620 // looks at the current selected connection in order to avoid switching | 1708 // looks at the current selected connection in order to avoid switching |
1621 // between fairly similar ones. Since this connection is no longer an option, | 1709 // between fairly similar ones. Since this connection is no longer an option, |
1622 // we can just set selected to nullptr and re-choose a best assuming that | 1710 // we can just set selected to nullptr and re-choose a best assuming that |
1623 // there was no selected connection. | 1711 // there was no selected connection. |
1624 if (selected_connection_ == connection) { | 1712 if (selected_connection_ == connection) { |
1625 LOG(LS_INFO) << "selected connection destroyed. Will choose a new one."; | 1713 LOG(LS_INFO) << "Selected connection destroyed. Will choose a new one."; |
1626 SwitchSelectedConnection(nullptr); | 1714 SwitchSelectedConnection(nullptr); |
1627 RequestSortAndStateUpdate(); | 1715 RequestSortAndStateUpdate(); |
1628 } else { | 1716 } else { |
1629 // If a non-selected connection was destroyed, we don't need to re-sort but | 1717 // If a non-selected connection was destroyed, we don't need to re-sort but |
1630 // we do need to update state, because we could be switching to "failed" or | 1718 // we do need to update state, because we could be switching to "failed" or |
1631 // "completed". | 1719 // "completed". |
1632 UpdateState(); | 1720 UpdateState(); |
1633 } | 1721 } |
1634 } | 1722 } |
1635 | 1723 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1722 return; | 1810 return; |
1723 | 1811 |
1724 // Let the client know of an incoming packet | 1812 // Let the client know of an incoming packet |
1725 SignalReadPacket(this, data, len, packet_time, 0); | 1813 SignalReadPacket(this, data, len, packet_time, 0); |
1726 | 1814 |
1727 // May need to switch the sending connection based on the receiving media path | 1815 // May need to switch the sending connection based on the receiving media path |
1728 // if this is the controlled side. | 1816 // if this is the controlled side. |
1729 if (ice_role_ == ICEROLE_CONTROLLED && | 1817 if (ice_role_ == ICEROLE_CONTROLLED && |
1730 ShouldSwitchSelectedConnection(connection)) { | 1818 ShouldSwitchSelectedConnection(connection)) { |
1731 LOG(LS_INFO) << "Switching selected connection on controlled side due to " | 1819 LOG(LS_INFO) << "Switching selected connection on controlled side due to " |
1732 << "data received: " << connection->ToString(); | 1820 << "data received"; |
1733 SwitchSelectedConnection(connection); | 1821 SwitchSelectedConnection(connection); |
1734 } | 1822 } |
1735 } | 1823 } |
1736 | 1824 |
1737 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) { | 1825 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) { |
1738 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1826 ASSERT(worker_thread_ == rtc::Thread::Current()); |
1739 | 1827 |
1740 SignalSentPacket(this, sent_packet); | 1828 SignalSentPacket(this, sent_packet); |
1741 } | 1829 } |
1742 | 1830 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1857 | 1945 |
1858 // During the initial state when nothing has been pinged yet, return the first | 1946 // During the initial state when nothing has been pinged yet, return the first |
1859 // one in the ordered |connections_|. | 1947 // one in the ordered |connections_|. |
1860 return *(std::find_if(connections_.begin(), connections_.end(), | 1948 return *(std::find_if(connections_.begin(), connections_.end(), |
1861 [conn1, conn2](Connection* conn) { | 1949 [conn1, conn2](Connection* conn) { |
1862 return conn == conn1 || conn == conn2; | 1950 return conn == conn1 || conn == conn2; |
1863 })); | 1951 })); |
1864 } | 1952 } |
1865 | 1953 |
1866 } // namespace cricket | 1954 } // namespace cricket |
OLD | NEW |