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 11 matching lines...) Expand all Loading... | |
22 #include "webrtc/p2p/base/common.h" | 22 #include "webrtc/p2p/base/common.h" |
23 #include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE. | 23 #include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE. |
24 #include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE. | 24 #include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE. |
25 #include "webrtc/system_wrappers/include/field_trial.h" | 25 #include "webrtc/system_wrappers/include/field_trial.h" |
26 | 26 |
27 namespace { | 27 namespace { |
28 | 28 |
29 // messages for queuing up work for ourselves | 29 // messages for queuing up work for ourselves |
30 enum { MSG_SORT = 1, MSG_CHECK_AND_PING }; | 30 enum { MSG_SORT = 1, MSG_CHECK_AND_PING }; |
31 | 31 |
32 // Mapped write states used by P2PTransportChannel::MappedWriteState. | |
33 enum { | |
34 MAPPED_WRITE_STATE_WRITABLE = 1, | |
35 MAPPED_WRITE_STATE_PROBABLY_WRITABLE, | |
36 MAPPED_WRITE_STATE_UNRELIABLE, | |
37 MAPPED_WRITE_STATE_INIT, | |
38 MAPPED_WRITE_STATE_TIMEOUT | |
39 }; | |
pthatcher1
2016/06/15 19:12:46
Can we just add Connection::STATE_WRITE_PRESUMED t
| |
40 | |
32 // The minimum improvement in RTT that justifies a switch. | 41 // The minimum improvement in RTT that justifies a switch. |
33 static const double kMinImprovement = 10; | 42 static const double kMinImprovement = 10; |
34 | 43 |
35 bool IsRelayRelay(cricket::Connection* conn) { | 44 bool IsRelayRelay(const cricket::Connection* conn) { |
36 return conn->local_candidate().type() == cricket::RELAY_PORT_TYPE && | 45 return conn->local_candidate().type() == cricket::RELAY_PORT_TYPE && |
37 conn->remote_candidate().type() == cricket::RELAY_PORT_TYPE; | 46 conn->remote_candidate().type() == cricket::RELAY_PORT_TYPE; |
38 } | 47 } |
39 | 48 |
40 bool IsUdp(cricket::Connection* conn) { | 49 bool IsUdp(cricket::Connection* conn) { |
41 return conn->local_candidate().relay_protocol() == cricket::UDP_PROTOCOL_NAME; | 50 return conn->local_candidate().relay_protocol() == cricket::UDP_PROTOCOL_NAME; |
42 } | 51 } |
43 | 52 |
44 cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port, | 53 cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port, |
45 cricket::PortInterface* origin_port) { | 54 cricket::PortInterface* origin_port) { |
46 if (!origin_port) | 55 if (!origin_port) |
47 return cricket::PortInterface::ORIGIN_MESSAGE; | 56 return cricket::PortInterface::ORIGIN_MESSAGE; |
48 else if (port == origin_port) | 57 else if (port == origin_port) |
49 return cricket::PortInterface::ORIGIN_THIS_PORT; | 58 return cricket::PortInterface::ORIGIN_THIS_PORT; |
50 else | 59 else |
51 return cricket::PortInterface::ORIGIN_OTHER_PORT; | 60 return cricket::PortInterface::ORIGIN_OTHER_PORT; |
52 } | 61 } |
53 | 62 |
54 // Compares two connections based only on the candidate and network information. | |
55 // Returns positive if |a| is better than |b|. | |
56 int CompareConnectionCandidates(cricket::Connection* a, | |
57 cricket::Connection* b) { | |
58 uint32_t a_cost = a->ComputeNetworkCost(); | |
59 uint32_t b_cost = b->ComputeNetworkCost(); | |
60 // Smaller cost is better. | |
61 if (a_cost < b_cost) { | |
62 return 1; | |
63 } | |
64 if (a_cost > b_cost) { | |
65 return -1; | |
66 } | |
67 | |
68 // Compare connection priority. Lower values get sorted last. | |
69 if (a->priority() > b->priority()) | |
70 return 1; | |
71 if (a->priority() < b->priority()) | |
72 return -1; | |
73 | |
74 // If we're still tied at this point, prefer a younger generation. | |
75 return (a->remote_candidate().generation() + a->port()->generation()) - | |
76 (b->remote_candidate().generation() + b->port()->generation()); | |
77 } | |
78 | |
79 // Compare two connections based on their writing, receiving, and connected | |
80 // states. | |
81 int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) { | |
82 // Sort based on write-state. Better states have lower values. | |
83 if (a->write_state() < b->write_state()) | |
84 return 1; | |
85 if (a->write_state() > b->write_state()) | |
86 return -1; | |
87 | |
88 // We prefer a receiving connection to a non-receiving, higher-priority | |
89 // connection when sorting connections and choosing which connection to | |
90 // switch to. | |
91 if (a->receiving() && !b->receiving()) | |
92 return 1; | |
93 if (!a->receiving() && b->receiving()) | |
94 return -1; | |
95 | |
96 // WARNING: Some complexity here about TCP reconnecting. | |
97 // When a TCP connection fails because of a TCP socket disconnecting, the | |
98 // active side of the connection will attempt to reconnect for 5 seconds while | |
99 // pretending to be writable (the connection is not set to the unwritable | |
100 // state). On the passive side, the connection also remains writable even | |
101 // though it is disconnected, and a new connection is created when the active | |
102 // side connects. At that point, there are two TCP connections on the passive | |
103 // side: 1. the old, disconnected one that is pretending to be writable, and | |
104 // 2. the new, connected one that is maybe not yet writable. For purposes of | |
105 // pruning, pinging, and selecting the best connection, we want to treat the | |
106 // new connection as "better" than the old one. We could add a method called | |
107 // something like Connection::ImReallyBadEvenThoughImWritable, but that is | |
108 // equivalent to the existing Connection::connected(), which we already have. | |
109 // So, in code throughout this file, we'll check whether the connection is | |
110 // connected() or not, and if it is not, treat it as "worse" than a connected | |
111 // one, even though it's writable. In the code below, we're doing so to make | |
112 // sure we treat a new writable connection as better than an old disconnected | |
113 // connection. | |
114 | |
115 // In the case where we reconnect TCP connections, the original best | |
116 // connection is disconnected without changing to WRITE_TIMEOUT. In this case, | |
117 // the new connection, when it becomes writable, should have higher priority. | |
118 if (a->write_state() == cricket::Connection::STATE_WRITABLE && | |
119 b->write_state() == cricket::Connection::STATE_WRITABLE) { | |
120 if (a->connected() && !b->connected()) { | |
121 return 1; | |
122 } | |
123 if (!a->connected() && b->connected()) { | |
124 return -1; | |
125 } | |
126 } | |
127 return 0; | |
128 } | |
129 | |
130 int CompareConnections(cricket::Connection* a, cricket::Connection* b) { | |
131 int state_cmp = CompareConnectionStates(a, b); | |
132 if (state_cmp != 0) { | |
133 return state_cmp; | |
134 } | |
135 // Compare the candidate information. | |
136 return CompareConnectionCandidates(a, b); | |
137 } | |
138 | |
139 // Wraps the comparison connection into a less than operator that puts higher | |
140 // priority writable connections first. | |
141 class ConnectionCompare { | |
142 public: | |
143 bool operator()(const cricket::Connection *ca, | |
144 const cricket::Connection *cb) { | |
145 cricket::Connection* a = const_cast<cricket::Connection*>(ca); | |
146 cricket::Connection* b = const_cast<cricket::Connection*>(cb); | |
147 | |
148 // Compare first on writability and static preferences. | |
149 int cmp = CompareConnections(a, b); | |
150 if (cmp > 0) | |
151 return true; | |
152 if (cmp < 0) | |
153 return false; | |
154 | |
155 // Otherwise, sort based on latency estimate. | |
156 return a->rtt() < b->rtt(); | |
157 | |
158 // Should we bother checking for the last connection that last received | |
159 // data? It would help rendezvous on the connection that is also receiving | |
160 // packets. | |
161 // | |
162 // TODO: Yes we should definitely do this. The TCP protocol gains | |
163 // efficiency by being used bidirectionally, as opposed to two separate | |
164 // unidirectional streams. This test should probably occur before | |
165 // comparison of local prefs (assuming combined prefs are the same). We | |
166 // need to be careful though, not to bounce back and forth with both sides | |
167 // trying to rendevous with the other. | |
168 } | |
169 }; | |
170 | |
171 // Determines whether we should switch between two connections, based first on | |
172 // connection states, static preferences, and then (if those are equal) on | |
173 // latency estimates. | |
174 bool ShouldSwitch(cricket::Connection* a_conn, | |
175 cricket::Connection* b_conn, | |
176 cricket::IceRole ice_role) { | |
177 if (a_conn == b_conn) | |
178 return false; | |
179 | |
180 if (!a_conn || !b_conn) // don't think the latter should happen | |
181 return true; | |
182 | |
183 // We prefer to switch to a writable and receiving connection over a | |
184 // non-writable or non-receiving connection, even if the latter has | |
185 // been nominated by the controlling side. | |
186 int state_cmp = CompareConnectionStates(a_conn, b_conn); | |
187 if (state_cmp != 0) { | |
188 return state_cmp < 0; | |
189 } | |
190 if (ice_role == cricket::ICEROLE_CONTROLLED && a_conn->nominated()) { | |
191 LOG(LS_VERBOSE) << "Controlled side did not switch due to nominated status"; | |
192 return false; | |
193 } | |
194 | |
195 int prefs_cmp = CompareConnectionCandidates(a_conn, b_conn); | |
196 if (prefs_cmp != 0) { | |
197 return prefs_cmp < 0; | |
198 } | |
199 | |
200 return b_conn->rtt() <= a_conn->rtt() + kMinImprovement; | |
201 } | |
202 | |
203 } // unnamed namespace | 63 } // unnamed namespace |
204 | 64 |
205 namespace cricket { | 65 namespace cricket { |
206 | 66 |
207 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) | 67 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) |
208 // for pinging. When the socket is writable, we will use only 1 Kbps because | 68 // for pinging. When the socket is writable, we will use only 1 Kbps because |
209 // we don't want to degrade the quality on a modem. These numbers should work | 69 // we don't want to degrade the quality on a modem. These numbers should work |
210 // well on a 28.8K modem, which is the slowest connection on which the voice | 70 // well on a 28.8K modem, which is the slowest connection on which the voice |
211 // quality is reasonable at all. | 71 // quality is reasonable at all. |
212 static const int PING_PACKET_SIZE = 60 * 8; | 72 static const int PING_PACKET_SIZE = 60 * 8; |
(...skipping 30 matching lines...) Expand all Loading... | |
243 sort_dirty_(false), | 103 sort_dirty_(false), |
244 remote_ice_mode_(ICEMODE_FULL), | 104 remote_ice_mode_(ICEMODE_FULL), |
245 ice_role_(ICEROLE_UNKNOWN), | 105 ice_role_(ICEROLE_UNKNOWN), |
246 tiebreaker_(0), | 106 tiebreaker_(0), |
247 gathering_state_(kIceGatheringNew), | 107 gathering_state_(kIceGatheringNew), |
248 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), | 108 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), |
249 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, | 109 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, |
250 0 /* backup_connection_ping_interval */, | 110 0 /* backup_connection_ping_interval */, |
251 false /* gather_continually */, | 111 false /* gather_continually */, |
252 false /* prioritize_most_likely_candidate_pairs */, | 112 false /* prioritize_most_likely_candidate_pairs */, |
253 MAX_CURRENT_STRONG_INTERVAL /* max_strong_interval */) { | 113 MAX_CURRENT_STRONG_INTERVAL /* max_strong_interval */, |
114 true /* turn_to_turn_createpermission_needed */) { | |
254 uint32_t weak_ping_interval = ::strtoul( | 115 uint32_t weak_ping_interval = ::strtoul( |
255 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), | 116 webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), |
256 nullptr, 10); | 117 nullptr, 10); |
257 if (weak_ping_interval) { | 118 if (weak_ping_interval) { |
258 weak_ping_interval_ = static_cast<int>(weak_ping_interval); | 119 weak_ping_interval_ = static_cast<int>(weak_ping_interval); |
259 } | 120 } |
260 } | 121 } |
261 | 122 |
262 P2PTransportChannel::~P2PTransportChannel() { | 123 P2PTransportChannel::~P2PTransportChannel() { |
263 ASSERT(worker_thread_ == rtc::Thread::Current()); | 124 ASSERT(worker_thread_ == rtc::Thread::Current()); |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
431 config.prioritize_most_likely_candidate_pairs; | 292 config.prioritize_most_likely_candidate_pairs; |
432 LOG(LS_INFO) << "Set ping most likely connection to " | 293 LOG(LS_INFO) << "Set ping most likely connection to " |
433 << config_.prioritize_most_likely_candidate_pairs; | 294 << config_.prioritize_most_likely_candidate_pairs; |
434 | 295 |
435 if (config.max_strong_interval >= 0 && | 296 if (config.max_strong_interval >= 0 && |
436 config_.max_strong_interval != config.max_strong_interval) { | 297 config_.max_strong_interval != config.max_strong_interval) { |
437 config_.max_strong_interval = config.max_strong_interval; | 298 config_.max_strong_interval = config.max_strong_interval; |
438 LOG(LS_INFO) << "Set max strong interval to " | 299 LOG(LS_INFO) << "Set max strong interval to " |
439 << config_.max_strong_interval; | 300 << config_.max_strong_interval; |
440 } | 301 } |
302 | |
303 if (config.turn_to_turn_createpermission_needed != | |
304 config_.turn_to_turn_createpermission_needed) { | |
305 if (!connections_.empty()) { | |
306 LOG(LS_ERROR) << "Trying to change TURN-TURN CreatePermission needed " | |
307 << "while connections already exist!"; | |
308 } else { | |
309 config_.turn_to_turn_createpermission_needed = | |
310 config.turn_to_turn_createpermission_needed; | |
311 LOG(LS_INFO) << "Set TURN-TURN CreatePermission needed to " | |
312 << config_.turn_to_turn_createpermission_needed; | |
313 } | |
314 } | |
pthatcher1
2016/06/15 19:12:46
Why not just allow it and document that it doesn't
Taylor Brandstetter
2016/06/16 00:13:40
It's easier to just disallow it then to allow it i
| |
441 } | 315 } |
442 | 316 |
443 const IceConfig& P2PTransportChannel::config() const { | 317 const IceConfig& P2PTransportChannel::config() const { |
444 return config_; | 318 return config_; |
445 } | 319 } |
446 | 320 |
447 // Go into the state of processing candidates, and running in general | 321 // Go into the state of processing candidates, and running in general |
448 void P2PTransportChannel::Connect() { | 322 void P2PTransportChannel::Connect() { |
449 ASSERT(worker_thread_ == rtc::Thread::Current()); | 323 ASSERT(worker_thread_ == rtc::Thread::Current()); |
450 if (ice_ufrag_.empty() || ice_pwd_.empty()) { | 324 if (ice_ufrag_.empty() || ice_pwd_.empty()) { |
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1056 } | 930 } |
1057 | 931 |
1058 // Prepare for best candidate sorting. | 932 // Prepare for best candidate sorting. |
1059 void P2PTransportChannel::RequestSort() { | 933 void P2PTransportChannel::RequestSort() { |
1060 if (!sort_dirty_) { | 934 if (!sort_dirty_) { |
1061 worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT); | 935 worker_thread_->Post(RTC_FROM_HERE, this, MSG_SORT); |
1062 sort_dirty_ = true; | 936 sort_dirty_ = true; |
1063 } | 937 } |
1064 } | 938 } |
1065 | 939 |
940 int P2PTransportChannel::MappedWriteState(const cricket::Connection* a) const { | |
941 switch (a->write_state()) { | |
942 case Connection::STATE_WRITABLE: | |
943 return MAPPED_WRITE_STATE_WRITABLE; | |
944 case Connection::STATE_WRITE_UNRELIABLE: | |
945 return MAPPED_WRITE_STATE_UNRELIABLE; | |
946 case Connection::STATE_WRITE_INIT: | |
947 // If the connection hasn't received a binding response, but it's a TURN- | |
948 // TURN connection and CreatePermission isn't needed, the connection is | |
949 // "probably writable" which is just a step below writable. | |
950 if (!config_.turn_to_turn_createpermission_needed && IsRelayRelay(a)) { | |
951 return MAPPED_WRITE_STATE_PROBABLY_WRITABLE; | |
952 } | |
953 return MAPPED_WRITE_STATE_INIT; | |
954 case Connection::STATE_WRITE_TIMEOUT: | |
955 return MAPPED_WRITE_STATE_TIMEOUT; | |
956 default: | |
957 RTC_DCHECK(false); | |
958 return MAPPED_WRITE_STATE_TIMEOUT; | |
honghaiz3
2016/06/15 16:37:18
Should we consider putting the write state mapping
Taylor Brandstetter
2016/06/15 17:08:56
I considered that. But that would mean we'd be let
pthatcher1
2016/06/15 19:12:46
What if we passed the initial Connection state int
honghaiz3
2016/06/15 19:26:36
There is one case in which the write_state reset t
Taylor Brandstetter
2016/06/16 00:13:40
I *really* don't want to pass a state in, or make
| |
959 } | |
960 } | |
961 | |
962 // Compare two connections based on their writing, receiving, and connected | |
963 // states. | |
964 int P2PTransportChannel::CompareConnectionStates(const Connection* a, | |
965 const Connection* b) const { | |
966 // Sort based on write-state. Better states have lower values. | |
967 if (MappedWriteState(a) < MappedWriteState(b)) { | |
968 return 1; | |
969 } | |
970 if (MappedWriteState(a) > MappedWriteState(b)) { | |
971 return -1; | |
972 } | |
pthatcher1
2016/06/15 19:12:46
This could be like the other comps:
// Prefer bett
Taylor Brandstetter
2016/06/16 00:13:41
Done.
| |
973 | |
974 // We prefer a receiving connection to a non-receiving, higher-priority | |
975 // connection when sorting connections and choosing which connection to | |
976 // switch to. | |
977 if (a->receiving() && !b->receiving()) { | |
978 return 1; | |
979 } | |
980 if (!a->receiving() && b->receiving()) { | |
981 return -1; | |
982 } | |
983 | |
984 // WARNING: Some complexity here about TCP reconnecting. | |
985 // When a TCP connection fails because of a TCP socket disconnecting, the | |
986 // active side of the connection will attempt to reconnect for 5 seconds while | |
987 // pretending to be writable (the connection is not set to the unwritable | |
988 // state). On the passive side, the connection also remains writable even | |
989 // though it is disconnected, and a new connection is created when the active | |
990 // side connects. At that point, there are two TCP connections on the passive | |
991 // side: 1. the old, disconnected one that is pretending to be writable, and | |
992 // 2. the new, connected one that is maybe not yet writable. For purposes of | |
993 // pruning, pinging, and selecting the best connection, we want to treat the | |
994 // new connection as "better" than the old one. We could add a method called | |
995 // something like Connection::ImReallyBadEvenThoughImWritable, but that is | |
996 // equivalent to the existing Connection::connected(), which we already have. | |
997 // So, in code throughout this file, we'll check whether the connection is | |
998 // connected() or not, and if it is not, treat it as "worse" than a connected | |
999 // one, even though it's writable. In the code below, we're doing so to make | |
1000 // sure we treat a new writable connection as better than an old disconnected | |
1001 // connection. | |
1002 | |
1003 // In the case where we reconnect TCP connections, the original best | |
1004 // connection is disconnected without changing to WRITE_TIMEOUT. In this case, | |
1005 // the new connection, when it becomes writable, should have higher priority. | |
1006 if (a->write_state() == Connection::STATE_WRITABLE && | |
1007 b->write_state() == Connection::STATE_WRITABLE) { | |
1008 if (a->connected() && !b->connected()) { | |
1009 return 1; | |
1010 } | |
1011 if (!a->connected() && b->connected()) { | |
1012 return -1; | |
1013 } | |
1014 } | |
1015 return 0; | |
1016 } | |
1017 | |
1018 // Compares two connections based only on the candidate and network information. | |
1019 // Returns positive if |a| is better than |b|. | |
1020 int P2PTransportChannel::CompareConnectionCandidates( | |
1021 const Connection* a, | |
1022 const Connection* b) const { | |
1023 uint32_t a_cost = a->ComputeNetworkCost(); | |
1024 uint32_t b_cost = b->ComputeNetworkCost(); | |
1025 // Smaller cost is better. | |
1026 if (a_cost < b_cost) { | |
1027 return 1; | |
1028 } | |
1029 if (a_cost > b_cost) { | |
1030 return -1; | |
1031 } | |
pthatcher1
2016/06/15 19:12:46
To make it a lot like the other comp code, should
Taylor Brandstetter
2016/06/16 00:13:40
Hmm. Now we're talking about subtracting unsigned
pthatcher1
2016/06/16 23:31:36
True.
| |
1032 | |
1033 // Compare connection priority. Lower values get sorted last. | |
1034 if (a->priority() > b->priority()) { | |
1035 return 1; | |
1036 } | |
1037 if (a->priority() < b->priority()) { | |
1038 return -1; | |
1039 } | |
pthatcher1
2016/06/15 19:12:46
Similarly here:
// Prefer higher priority
int pri
Taylor Brandstetter
2016/06/16 00:13:40
See above. Plus, these are uint64_t's. Even if we
| |
1040 | |
1041 // If we're still tied at this point, prefer a younger generation. | |
pthatcher1
2016/06/15 19:12:46
Could you add "(larger generation number)" to make
Taylor Brandstetter
2016/06/16 00:13:40
Done.
| |
1042 return (a->remote_candidate().generation() + a->port()->generation()) - | |
1043 (b->remote_candidate().generation() + b->port()->generation()); | |
1044 } | |
1045 | |
1046 int P2PTransportChannel::CompareConnections(const Connection* a, | |
1047 const Connection* b) const { | |
1048 // Compare first on writability and static preferences. | |
1049 int state_cmp = CompareConnectionStates(a, b); | |
1050 if (state_cmp != 0) { | |
1051 return state_cmp; | |
1052 } | |
1053 // Then compare the candidate information. | |
1054 int candidates_cmp = CompareConnectionCandidates(a, b); | |
1055 if (candidates_cmp != 0) { | |
1056 return candidates_cmp; | |
1057 } | |
1058 // Otherwise, compare based on latency estimate. | |
1059 return b->rtt() - a->rtt(); | |
1060 | |
1061 // Should we bother checking for the last connection that last received | |
1062 // data? It would help rendezvous on the connection that is also receiving | |
1063 // packets. | |
1064 // | |
1065 // TODO(deadbeef): Yes we should definitely do this. The TCP protocol gains | |
1066 // efficiency by being used bidirectionally, as opposed to two separate | |
1067 // unidirectional streams. This test should probably occur before | |
1068 // comparison of local prefs (assuming combined prefs are the same). We | |
1069 // need to be careful though, not to bounce back and forth with both sides | |
1070 // trying to rendevous with the other. | |
pthatcher1
2016/06/15 19:12:46
That's a good point. It would make sense for the
Taylor Brandstetter
2016/06/16 00:13:40
FYI: I didn't write this comment, I just moved it
| |
1071 } | |
1072 | |
1073 // Determines whether we should switch between two connections, based first on | |
1074 // connection states, static preferences, and then (if those are equal) on | |
1075 // latency estimates. | |
1076 bool P2PTransportChannel::ShouldSwitch(const Connection* a, | |
1077 const Connection* b) const { | |
pthatcher1
2016/06/15 19:12:46
If you're going to move this, we might as well nam
Taylor Brandstetter
2016/06/16 00:13:41
Done.
| |
1078 if (a == b) { | |
1079 return false; | |
1080 } | |
1081 | |
1082 if (!a || !b) { // don't think the latter should happen | |
1083 return true; | |
1084 } | |
pthatcher1
2016/06/15 19:12:46
This might be more readable as:
if (!conn) {
re
Taylor Brandstetter
2016/06/16 00:13:40
Done.
| |
1085 | |
1086 // We prefer to switch to a writable and receiving connection over a | |
1087 // non-writable or non-receiving connection, even if the latter has | |
1088 // been nominated by the controlling side. | |
1089 int state_cmp = CompareConnectionStates(a, b); | |
1090 if (state_cmp != 0) { | |
1091 return state_cmp < 0; | |
1092 } | |
1093 if (ice_role_ == ICEROLE_CONTROLLED && a->nominated()) { | |
pthatcher1
2016/06/15 19:12:46
Would it make sense to have a few helper methods?
Taylor Brandstetter
2016/06/16 00:13:40
We don't need the former function. If the other si
| |
1094 LOG(LS_VERBOSE) << "Controlled side did not switch due to nominated status"; | |
1095 return false; | |
1096 } | |
1097 | |
1098 int prefs_cmp = CompareConnectionCandidates(a, b); | |
1099 if (prefs_cmp != 0) { | |
1100 return prefs_cmp < 0; | |
1101 } | |
1102 | |
1103 return b->rtt() <= a->rtt() + kMinImprovement; | |
pthatcher1
2016/06/15 19:12:46
This might be more readable as:
return (selected-
Taylor Brandstetter
2016/06/16 00:13:40
Done.
| |
1104 } | |
1105 | |
1066 // Sort the available connections to find the best one. We also monitor | 1106 // Sort the available connections to find the best one. We also monitor |
1067 // the number of available connections and the current state. | 1107 // the number of available connections and the current state. |
1068 void P2PTransportChannel::SortConnections() { | 1108 void P2PTransportChannel::SortConnections() { |
1069 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1109 ASSERT(worker_thread_ == rtc::Thread::Current()); |
1070 | 1110 |
1071 // Make sure the connection states are up-to-date since this affects how they | 1111 // Make sure the connection states are up-to-date since this affects how they |
1072 // will be sorted. | 1112 // will be sorted. |
1073 UpdateConnectionStates(); | 1113 UpdateConnectionStates(); |
1074 | 1114 |
1075 // Any changes after this point will require a re-sort. | 1115 // Any changes after this point will require a re-sort. |
1076 sort_dirty_ = false; | 1116 sort_dirty_ = false; |
1077 | 1117 |
1078 // Find the best alternative connection by sorting. It is important to note | 1118 // Find the best alternative connection by sorting. It is important to note |
1079 // that amongst equal preference, writable connections, this will choose the | 1119 // that amongst equal preference, writable connections, this will choose the |
1080 // one whose estimated latency is lowest. So it is the only one that we | 1120 // one whose estimated latency is lowest. So it is the only one that we |
1081 // need to consider switching to. | 1121 // need to consider switching to. |
1082 ConnectionCompare cmp; | 1122 std::stable_sort(connections_.begin(), connections_.end(), |
1083 std::stable_sort(connections_.begin(), connections_.end(), cmp); | 1123 [this](const Connection* a, const Connection* b) { |
1124 return CompareConnections(a, b) > 0; | |
1125 }); | |
1084 LOG(LS_VERBOSE) << "Sorting " << connections_.size() | 1126 LOG(LS_VERBOSE) << "Sorting " << connections_.size() |
1085 << " available connections:"; | 1127 << " available connections:"; |
1086 for (size_t i = 0; i < connections_.size(); ++i) { | 1128 for (size_t i = 0; i < connections_.size(); ++i) { |
1087 LOG(LS_VERBOSE) << connections_[i]->ToString(); | 1129 LOG(LS_VERBOSE) << connections_[i]->ToString(); |
1088 } | 1130 } |
1089 | 1131 |
1090 Connection* top_connection = | 1132 Connection* top_connection = |
1091 (connections_.size() > 0) ? connections_[0] : nullptr; | 1133 (connections_.size() > 0) ? connections_[0] : nullptr; |
1092 | 1134 |
1093 // If necessary, switch to the new choice. | 1135 // If necessary, switch to the new choice. |
1094 // Note that |top_connection| doesn't have to be writable to become the best | 1136 // Note that |top_connection| doesn't have to be writable to become the best |
1095 // connection although it will have higher priority if it is writable. | 1137 // connection although it will have higher priority if it is writable. |
1096 if (ShouldSwitch(best_connection_, top_connection, ice_role_)) { | 1138 if (ShouldSwitch(best_connection_, top_connection)) { |
1097 LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString(); | 1139 LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString(); |
1098 SwitchBestConnectionTo(top_connection); | 1140 SwitchBestConnectionTo(top_connection); |
1099 } | 1141 } |
1100 | 1142 |
1101 // Controlled side can prune only if the best connection has been nominated. | 1143 // Controlled side can prune only if the best connection has been nominated. |
1102 // because otherwise it may delete the connection that will be selected by | 1144 // because otherwise it may delete the connection that will be selected by |
1103 // the controlling side. | 1145 // the controlling side. |
1104 if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) { | 1146 if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) { |
1105 PruneConnections(); | 1147 PruneConnections(); |
1106 } | 1148 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1230 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED); | 1272 RTC_DCHECK(state == STATE_CONNECTING || state == STATE_COMPLETED); |
1231 break; | 1273 break; |
1232 default: | 1274 default: |
1233 RTC_DCHECK(false); | 1275 RTC_DCHECK(false); |
1234 break; | 1276 break; |
1235 } | 1277 } |
1236 state_ = state; | 1278 state_ = state; |
1237 SignalStateChanged(this); | 1279 SignalStateChanged(this); |
1238 } | 1280 } |
1239 | 1281 |
1240 bool writable = best_connection_ && best_connection_->writable(); | 1282 // If our best connection is "probably writable" (TURN-TURN with no |
1283 // CreatePermission required), act like we're already writable to the upper | |
pthatcher1
2016/06/15 19:12:46
I think the phrased "presumed writable" might be s
Taylor Brandstetter
2016/06/16 00:13:41
Done.
| |
1284 // layers, so they can start media quicker. | |
1285 bool writable = | |
pthatcher1
2016/06/15 19:12:46
Can we make a method called PresumedWritable()? T
Taylor Brandstetter
2016/06/16 00:13:41
Done.
| |
1286 best_connection_ && | |
1287 (MappedWriteState(best_connection_) == MAPPED_WRITE_STATE_WRITABLE || | |
1288 MappedWriteState(best_connection_) == | |
1289 MAPPED_WRITE_STATE_PROBABLY_WRITABLE); | |
1241 set_writable(writable); | 1290 set_writable(writable); |
1242 | 1291 |
1243 bool receiving = false; | 1292 bool receiving = false; |
1244 for (const Connection* connection : connections_) { | 1293 for (const Connection* connection : connections_) { |
1245 if (connection->receiving()) { | 1294 if (connection->receiving()) { |
1246 receiving = true; | 1295 receiving = true; |
1247 break; | 1296 break; |
1248 } | 1297 } |
1249 } | 1298 } |
1250 set_receiving(receiving); | 1299 set_receiving(receiving); |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1688 | 1737 |
1689 // During the initial state when nothing has been pinged yet, return the first | 1738 // During the initial state when nothing has been pinged yet, return the first |
1690 // one in the ordered |connections_|. | 1739 // one in the ordered |connections_|. |
1691 return *(std::find_if(connections_.begin(), connections_.end(), | 1740 return *(std::find_if(connections_.begin(), connections_.end(), |
1692 [conn1, conn2](Connection* conn) { | 1741 [conn1, conn2](Connection* conn) { |
1693 return conn == conn1 || conn == conn2; | 1742 return conn == conn1 || conn == conn2; |
1694 })); | 1743 })); |
1695 } | 1744 } |
1696 | 1745 |
1697 } // namespace cricket | 1746 } // namespace cricket |
OLD | NEW |