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 |
| 11 #include <utility> // for std::pair |
| 12 |
11 #include "webrtc/p2p/base/transport.h" | 13 #include "webrtc/p2p/base/transport.h" |
12 | 14 |
13 #include "webrtc/p2p/base/candidate.h" | 15 #include "webrtc/p2p/base/candidate.h" |
14 #include "webrtc/p2p/base/constants.h" | 16 #include "webrtc/p2p/base/constants.h" |
15 #include "webrtc/p2p/base/port.h" | 17 #include "webrtc/p2p/base/port.h" |
16 #include "webrtc/p2p/base/transportchannelimpl.h" | 18 #include "webrtc/p2p/base/transportchannelimpl.h" |
17 #include "webrtc/base/bind.h" | 19 #include "webrtc/base/bind.h" |
18 #include "webrtc/base/common.h" | 20 #include "webrtc/base/common.h" |
19 #include "webrtc/base/logging.h" | 21 #include "webrtc/base/logging.h" |
20 | 22 |
21 namespace cricket { | 23 namespace cricket { |
22 | 24 |
23 using rtc::Bind; | 25 using rtc::Bind; |
24 | 26 |
25 enum { | |
26 MSG_ONSIGNALINGREADY = 1, | |
27 MSG_ONREMOTECANDIDATE, | |
28 MSG_WRITESTATE, | |
29 MSG_REQUESTSIGNALING, | |
30 MSG_CANDIDATEREADY, | |
31 MSG_ROUTECHANGE, | |
32 MSG_CONNECTING, | |
33 MSG_CANDIDATEALLOCATIONCOMPLETE, | |
34 MSG_ROLECONFLICT, | |
35 MSG_COMPLETED, | |
36 MSG_FAILED, | |
37 MSG_RECEIVINGSTATE, | |
38 }; | |
39 | |
40 struct ChannelParams : public rtc::MessageData { | |
41 ChannelParams() : channel(NULL), candidate(NULL) {} | |
42 explicit ChannelParams(int component) | |
43 : component(component), channel(NULL), candidate(NULL) {} | |
44 explicit ChannelParams(Candidate* candidate) | |
45 : channel(NULL), candidate(candidate) { | |
46 } | |
47 | |
48 ~ChannelParams() { | |
49 delete candidate; | |
50 } | |
51 | |
52 std::string name; | |
53 int component; | |
54 TransportChannelImpl* channel; | |
55 Candidate* candidate; | |
56 }; | |
57 | |
58 static bool VerifyIceParams(const TransportDescription& desc) { | 27 static bool VerifyIceParams(const TransportDescription& desc) { |
59 // For legacy protocols. | 28 // For legacy protocols. |
60 if (desc.ice_ufrag.empty() && desc.ice_pwd.empty()) | 29 if (desc.ice_ufrag.empty() && desc.ice_pwd.empty()) |
61 return true; | 30 return true; |
62 | 31 |
63 if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH || | 32 if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH || |
64 desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) { | 33 desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) { |
65 return false; | 34 return false; |
66 } | 35 } |
67 if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH || | 36 if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH || |
(...skipping 21 matching lines...) Expand all Loading... |
89 // should clean this up when GICE is no longer used. | 58 // should clean this up when GICE is no longer used. |
90 return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); | 59 return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); |
91 } | 60 } |
92 | 61 |
93 static bool IceCredentialsChanged(const TransportDescription& old_desc, | 62 static bool IceCredentialsChanged(const TransportDescription& old_desc, |
94 const TransportDescription& new_desc) { | 63 const TransportDescription& new_desc) { |
95 return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd, | 64 return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd, |
96 new_desc.ice_ufrag, new_desc.ice_pwd); | 65 new_desc.ice_ufrag, new_desc.ice_pwd); |
97 } | 66 } |
98 | 67 |
99 Transport::Transport(rtc::Thread* signaling_thread, | 68 Transport::Transport(const std::string& name, PortAllocator* allocator) |
100 rtc::Thread* worker_thread, | 69 : name_(name), allocator_(allocator) {} |
101 const std::string& content_name, | 70 |
102 PortAllocator* allocator) | 71 Transport::~Transport() { |
103 : signaling_thread_(signaling_thread), | 72 ASSERT(channels_destroyed_); |
104 worker_thread_(worker_thread), | |
105 content_name_(content_name), | |
106 allocator_(allocator), | |
107 destroyed_(false), | |
108 readable_(TRANSPORT_STATE_NONE), | |
109 writable_(TRANSPORT_STATE_NONE), | |
110 receiving_(TRANSPORT_STATE_NONE), | |
111 was_writable_(false), | |
112 connect_requested_(false), | |
113 ice_role_(ICEROLE_UNKNOWN), | |
114 tiebreaker_(0), | |
115 remote_ice_mode_(ICEMODE_FULL), | |
116 channel_receiving_timeout_(-1) { | |
117 } | 73 } |
118 | 74 |
119 Transport::~Transport() { | 75 bool Transport::AllChannelsCompleted() const { |
120 ASSERT(signaling_thread_->IsCurrent()); | 76 // We aren't completed until at least one channel is complete, so if there |
121 ASSERT(destroyed_); | 77 // are no channels, we aren't complete yet. |
| 78 if (channels_.empty()) { |
| 79 LOG(LS_INFO) << name() << " transport is not complete" |
| 80 << " because it has no TransportChannels"; |
| 81 return false; |
| 82 } |
| 83 |
| 84 // A Transport's ICE process is completed if all of its channels are writable, |
| 85 // have finished allocating candidates, and have pruned all but one of their |
| 86 // connections. |
| 87 for (const auto& iter : channels_) { |
| 88 const TransportChannelImpl* channel = iter.second.get(); |
| 89 bool complete = |
| 90 channel->writable() && |
| 91 channel->GetState() == TransportChannelState::STATE_COMPLETED && |
| 92 channel->GetIceRole() == ICEROLE_CONTROLLING && |
| 93 channel->gathering_state() == kIceGatheringComplete; |
| 94 if (!complete) { |
| 95 LOG(LS_INFO) << name() << " transport is not complete" |
| 96 << " because a channel is still incomplete."; |
| 97 return false; |
| 98 } |
| 99 } |
| 100 |
| 101 return true; |
| 102 } |
| 103 |
| 104 bool Transport::AnyChannelFailed() const { |
| 105 for (const auto& iter : channels_) { |
| 106 if (iter.second->GetState() == TransportChannelState::STATE_FAILED) { |
| 107 return true; |
| 108 } |
| 109 } |
| 110 return false; |
122 } | 111 } |
123 | 112 |
124 void Transport::SetIceRole(IceRole role) { | 113 void Transport::SetIceRole(IceRole role) { |
125 worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role)); | 114 ice_role_ = role; |
126 } | 115 for (auto& iter : channels_) { |
127 | 116 iter.second->SetIceRole(ice_role_); |
128 void Transport::SetCertificate( | 117 } |
129 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
130 worker_thread_->Invoke<void>(Bind(&Transport::SetCertificate_w, this, | |
131 certificate)); | |
132 } | |
133 | |
134 bool Transport::GetCertificate( | |
135 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { | |
136 // The identity is set on the worker thread, so for safety it must also be | |
137 // acquired on the worker thread. | |
138 return worker_thread_->Invoke<bool>( | |
139 Bind(&Transport::GetCertificate_w, this, certificate)); | |
140 } | 118 } |
141 | 119 |
142 bool Transport::GetRemoteSSLCertificate(rtc::SSLCertificate** cert) { | 120 bool Transport::GetRemoteSSLCertificate(rtc::SSLCertificate** cert) { |
143 // Channels can be deleted on the worker thread, so for safety the remote | |
144 // certificate is acquired on the worker thread. | |
145 return worker_thread_->Invoke<bool>( | |
146 Bind(&Transport::GetRemoteSSLCertificate_w, this, cert)); | |
147 } | |
148 | |
149 bool Transport::GetRemoteSSLCertificate_w(rtc::SSLCertificate** cert) { | |
150 ASSERT(worker_thread()->IsCurrent()); | |
151 if (channels_.empty()) | 121 if (channels_.empty()) |
152 return false; | 122 return false; |
153 | 123 |
154 ChannelMap::iterator iter = channels_.begin(); | 124 ChannelMap::iterator iter = channels_.begin(); |
155 return iter->second->GetRemoteSSLCertificate(cert); | 125 return iter->second->GetRemoteSSLCertificate(cert); |
156 } | 126 } |
157 | 127 |
158 void Transport::SetChannelReceivingTimeout(int timeout_ms) { | 128 void Transport::SetChannelReceivingTimeout(int timeout_ms) { |
159 worker_thread_->Invoke<void>( | |
160 Bind(&Transport::SetChannelReceivingTimeout_w, this, timeout_ms)); | |
161 } | |
162 | |
163 void Transport::SetChannelReceivingTimeout_w(int timeout_ms) { | |
164 ASSERT(worker_thread()->IsCurrent()); | |
165 channel_receiving_timeout_ = timeout_ms; | 129 channel_receiving_timeout_ = timeout_ms; |
166 for (const auto& kv : channels_) { | 130 for (const auto& kv : channels_) { |
167 kv.second->SetReceivingTimeout(timeout_ms); | 131 kv.second->SetReceivingTimeout(timeout_ms); |
168 } | 132 } |
169 } | 133 } |
170 | 134 |
171 bool Transport::SetLocalTransportDescription( | 135 bool Transport::SetLocalTransportDescription( |
172 const TransportDescription& description, | 136 const TransportDescription& description, |
173 ContentAction action, | 137 ContentAction action, |
174 std::string* error_desc) { | 138 std::string* error_desc) { |
175 return worker_thread_->Invoke<bool>(Bind( | 139 bool ret = true; |
176 &Transport::SetLocalTransportDescription_w, this, | 140 |
177 description, action, error_desc)); | 141 if (!VerifyIceParams(description)) { |
| 142 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", |
| 143 error_desc); |
| 144 } |
| 145 |
| 146 if (local_description_ && |
| 147 IceCredentialsChanged(*local_description_, description)) { |
| 148 IceRole new_ice_role = |
| 149 (action == CA_OFFER) ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED; |
| 150 |
| 151 // It must be called before ApplyLocalTransportDescription, which may |
| 152 // trigger an ICE restart and depends on the new ICE role. |
| 153 SetIceRole(new_ice_role); |
| 154 } |
| 155 |
| 156 local_description_.reset(new TransportDescription(description)); |
| 157 |
| 158 for (auto& iter : channels_) { |
| 159 ret &= ApplyLocalTransportDescription(iter.second.get(), error_desc); |
| 160 } |
| 161 if (!ret) { |
| 162 return false; |
| 163 } |
| 164 |
| 165 // If PRANSWER/ANSWER is set, we should decide transport protocol type. |
| 166 if (action == CA_PRANSWER || action == CA_ANSWER) { |
| 167 ret &= NegotiateTransportDescription(action, error_desc); |
| 168 } |
| 169 if (ret) { |
| 170 local_description_set_ = true; |
| 171 // This kicks off candidate gathering. |
| 172 ConnectChannels(); |
| 173 } |
| 174 |
| 175 return ret; |
178 } | 176 } |
179 | 177 |
180 bool Transport::SetRemoteTransportDescription( | 178 bool Transport::SetRemoteTransportDescription( |
181 const TransportDescription& description, | 179 const TransportDescription& description, |
182 ContentAction action, | 180 ContentAction action, |
183 std::string* error_desc) { | 181 std::string* error_desc) { |
184 return worker_thread_->Invoke<bool>(Bind( | 182 bool ret = true; |
185 &Transport::SetRemoteTransportDescription_w, this, | 183 |
186 description, action, error_desc)); | 184 if (!VerifyIceParams(description)) { |
| 185 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", |
| 186 error_desc); |
| 187 } |
| 188 |
| 189 remote_description_.reset(new TransportDescription(description)); |
| 190 for (auto& iter : channels_) { |
| 191 ret &= ApplyRemoteTransportDescription(iter.second.get(), error_desc); |
| 192 } |
| 193 |
| 194 // If PRANSWER/ANSWER is set, we should decide transport protocol type. |
| 195 if (action == CA_PRANSWER || action == CA_ANSWER) { |
| 196 ret = NegotiateTransportDescription(CA_OFFER, error_desc); |
| 197 } |
| 198 if (ret) { |
| 199 remote_description_set_ = true; |
| 200 } |
| 201 |
| 202 return ret; |
187 } | 203 } |
188 | 204 |
189 TransportChannelImpl* Transport::CreateChannel(int component) { | 205 TransportChannelImpl* Transport::CreateChannel(int component) { |
190 return worker_thread_->Invoke<TransportChannelImpl*>(Bind( | |
191 &Transport::CreateChannel_w, this, component)); | |
192 } | |
193 | |
194 TransportChannelImpl* Transport::CreateChannel_w(int component) { | |
195 ASSERT(worker_thread()->IsCurrent()); | |
196 TransportChannelImpl* impl; | 206 TransportChannelImpl* impl; |
197 // TODO(tommi): We don't really need to grab the lock until the actual call | |
198 // to insert() below and presumably hold it throughout initialization of | |
199 // |impl| after the impl_exists check. Maybe we can factor that out to | |
200 // a separate function and not grab the lock in this function. | |
201 // Actually, we probably don't need to hold the lock while initializing | |
202 // |impl| since we can just do the insert when that's done. | |
203 rtc::CritScope cs(&crit_); | |
204 | 207 |
205 // Create the entry if it does not exist. | 208 // Create the entry if it does not exist. |
206 bool impl_exists = false; | 209 bool impl_exists = false; |
207 auto iterator = channels_.find(component); | 210 auto iterator = channels_.find(component); |
208 if (iterator == channels_.end()) { | 211 if (iterator == channels_.end()) { |
209 impl = CreateTransportChannel(component); | 212 impl = CreateTransportChannel(component); |
210 iterator = channels_.insert(std::pair<int, ChannelMapEntry>( | 213 iterator = channels_.insert(std::pair<int, ChannelMapEntry>( |
211 component, ChannelMapEntry(impl))).first; | 214 component, ChannelMapEntry(impl))).first; |
212 } else { | 215 } else { |
213 impl = iterator->second.get(); | 216 impl = iterator->second.get(); |
214 impl_exists = true; | 217 impl_exists = true; |
215 } | 218 } |
216 | 219 |
217 // Increase the ref count. | 220 // Increase the ref count. |
218 iterator->second.AddRef(); | 221 iterator->second.AddRef(); |
219 destroyed_ = false; | 222 channels_destroyed_ = false; |
220 | 223 |
221 if (impl_exists) { | 224 if (impl_exists) { |
222 // If this is an existing channel, we should just return it without | 225 // If this is an existing channel, we should just return it without |
223 // connecting to all the signal again. | 226 // connecting to all the signal again. |
224 return impl; | 227 return impl; |
225 } | 228 } |
226 | 229 |
227 // Push down our transport state to the new channel. | 230 // Push down our transport state to the new channel. |
228 impl->SetIceRole(ice_role_); | 231 impl->SetIceRole(ice_role_); |
229 impl->SetIceTiebreaker(tiebreaker_); | 232 impl->SetIceTiebreaker(tiebreaker_); |
230 impl->SetReceivingTimeout(channel_receiving_timeout_); | 233 impl->SetReceivingTimeout(channel_receiving_timeout_); |
231 // TODO(ronghuawu): Change CreateChannel_w to be able to return error since | 234 // TODO(ronghuawu): Change CreateChannel to be able to return error since |
232 // below Apply**Description_w calls can fail. | 235 // below Apply**Description calls can fail. |
233 if (local_description_) | 236 if (local_description_) |
234 ApplyLocalTransportDescription_w(impl, NULL); | 237 ApplyLocalTransportDescription(impl, NULL); |
235 if (remote_description_) | 238 if (remote_description_) |
236 ApplyRemoteTransportDescription_w(impl, NULL); | 239 ApplyRemoteTransportDescription(impl, NULL); |
237 if (local_description_ && remote_description_) | 240 if (local_description_ && remote_description_) |
238 ApplyNegotiatedTransportDescription_w(impl, NULL); | 241 ApplyNegotiatedTransportDescription(impl, NULL); |
239 | 242 |
240 impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState); | 243 impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState); |
241 impl->SignalReceivingState.connect(this, &Transport::OnChannelReceivingState); | 244 impl->SignalReceivingState.connect(this, &Transport::OnChannelReceivingState); |
242 impl->SignalRequestSignaling.connect( | 245 impl->SignalGatheringState.connect(this, &Transport::OnChannelGatheringState); |
243 this, &Transport::OnChannelRequestSignaling); | 246 impl->SignalCandidateGathered.connect(this, |
244 impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady); | 247 &Transport::OnChannelCandidateGathered); |
245 impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange); | 248 impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange); |
246 impl->SignalCandidatesAllocationDone.connect( | |
247 this, &Transport::OnChannelCandidatesAllocationDone); | |
248 impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict); | 249 impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict); |
249 impl->SignalConnectionRemoved.connect( | 250 impl->SignalConnectionRemoved.connect( |
250 this, &Transport::OnChannelConnectionRemoved); | 251 this, &Transport::OnChannelConnectionRemoved); |
251 | 252 |
252 if (connect_requested_) { | 253 if (connect_requested_) { |
253 impl->Connect(); | 254 impl->Connect(); |
254 if (channels_.size() == 1) { | 255 if (channels_.size() == 1) { |
255 // If this is the first channel, then indicate that we have started | 256 // If this is the first channel, then indicate that we have started |
256 // connecting. | 257 // connecting. |
257 signaling_thread()->Post(this, MSG_CONNECTING, NULL); | 258 SignalConnecting(this); |
258 } | 259 } |
259 } | 260 } |
260 return impl; | 261 return impl; |
261 } | 262 } |
262 | 263 |
263 TransportChannelImpl* Transport::GetChannel(int component) { | 264 TransportChannelImpl* Transport::GetChannel(int component) { |
264 // TODO(tommi,pthatcher): Since we're returning a pointer from the channels_ | |
265 // map, shouldn't we assume that we're on the worker thread? (The pointer | |
266 // will be used outside of the lock). | |
267 // And if we're on the worker thread, which is the only thread that modifies | |
268 // channels_, can we skip grabbing the lock? | |
269 rtc::CritScope cs(&crit_); | |
270 ChannelMap::iterator iter = channels_.find(component); | 265 ChannelMap::iterator iter = channels_.find(component); |
271 return (iter != channels_.end()) ? iter->second.get() : NULL; | 266 return (iter != channels_.end()) ? iter->second.get() : NULL; |
272 } | 267 } |
273 | 268 |
274 bool Transport::HasChannels() { | 269 bool Transport::HasChannels() { |
275 rtc::CritScope cs(&crit_); | |
276 return !channels_.empty(); | 270 return !channels_.empty(); |
277 } | 271 } |
278 | 272 |
279 void Transport::DestroyChannel(int component) { | 273 void Transport::DestroyChannel(int component) { |
280 worker_thread_->Invoke<void>(Bind( | |
281 &Transport::DestroyChannel_w, this, component)); | |
282 } | |
283 | |
284 void Transport::DestroyChannel_w(int component) { | |
285 ASSERT(worker_thread()->IsCurrent()); | |
286 | |
287 ChannelMap::iterator iter = channels_.find(component); | 274 ChannelMap::iterator iter = channels_.find(component); |
288 if (iter == channels_.end()) | 275 if (iter == channels_.end()) |
289 return; | 276 return; |
290 | 277 |
291 TransportChannelImpl* impl = NULL; | 278 TransportChannelImpl* impl = NULL; |
292 | 279 |
293 iter->second.DecRef(); | 280 iter->second.DecRef(); |
294 if (!iter->second.ref()) { | 281 if (!iter->second.ref()) { |
295 impl = iter->second.get(); | 282 impl = iter->second.get(); |
296 rtc::CritScope cs(&crit_); | |
297 channels_.erase(iter); | 283 channels_.erase(iter); |
298 } | 284 } |
299 | 285 |
300 if (connect_requested_ && channels_.empty()) { | 286 if (connect_requested_ && channels_.empty()) { |
301 // We're no longer attempting to connect. | 287 // We're no longer attempting to connect. |
302 signaling_thread()->Post(this, MSG_CONNECTING, NULL); | 288 SignalConnecting(this); |
303 } | 289 } |
304 | 290 |
305 if (impl) { | 291 if (impl) { |
306 // Check in case the deleted channel was the only non-writable channel. | |
307 OnChannelWritableState(impl); | |
308 DestroyTransportChannel(impl); | 292 DestroyTransportChannel(impl); |
| 293 // Need to update aggregate state after destroying a channel, |
| 294 // for example if it was the only one that wasn't yet writable. |
| 295 UpdateWritableState(); |
| 296 UpdateReceivingState(); |
| 297 UpdateGatheringState(); |
| 298 MaybeSignalCompleted(); |
309 } | 299 } |
310 } | 300 } |
311 | 301 |
312 void Transport::ConnectChannels() { | 302 void Transport::ConnectChannels() { |
313 ASSERT(signaling_thread()->IsCurrent()); | |
314 worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this)); | |
315 } | |
316 | |
317 void Transport::ConnectChannels_w() { | |
318 ASSERT(worker_thread()->IsCurrent()); | |
319 if (connect_requested_ || channels_.empty()) | 303 if (connect_requested_ || channels_.empty()) |
320 return; | 304 return; |
321 | 305 |
322 connect_requested_ = true; | 306 connect_requested_ = true; |
323 signaling_thread()->Post(this, MSG_CANDIDATEREADY, NULL); | 307 |
| 308 if (!ready_candidates_.empty()) { |
| 309 SignalCandidatesGathered(this, ready_candidates_); |
| 310 ready_candidates_.clear(); |
| 311 } |
324 | 312 |
325 if (!local_description_) { | 313 if (!local_description_) { |
326 // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here. | 314 // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here. |
327 // As Transport must know TD is offer or answer and cricket::Transport | 315 // As Transport must know TD is offer or answer and cricket::Transport |
328 // doesn't have the capability to decide it. This should be set by the | 316 // doesn't have the capability to decide it. This should be set by the |
329 // Session. | 317 // Session. |
330 // Session must generate local TD before remote candidates pushed when | 318 // Session must generate local TD before remote candidates pushed when |
331 // initiate request initiated by the remote. | 319 // initiate request initiated by the remote. |
332 LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has " | 320 LOG(LS_INFO) << "Transport::ConnectChannels: No local description has " |
333 << "been set. Will generate one."; | 321 << "been set. Will generate one."; |
334 TransportDescription desc(std::vector<std::string>(), | 322 TransportDescription desc( |
335 rtc::CreateRandomString(ICE_UFRAG_LENGTH), | 323 std::vector<std::string>(), rtc::CreateRandomString(ICE_UFRAG_LENGTH), |
336 rtc::CreateRandomString(ICE_PWD_LENGTH), | 324 rtc::CreateRandomString(ICE_PWD_LENGTH), ICEMODE_FULL, |
337 ICEMODE_FULL, CONNECTIONROLE_NONE, NULL, | 325 CONNECTIONROLE_NONE, NULL, Candidates()); |
338 Candidates()); | 326 SetLocalTransportDescription(desc, CA_OFFER, NULL); |
339 SetLocalTransportDescription_w(desc, CA_OFFER, NULL); | |
340 } | 327 } |
341 | 328 |
342 CallChannels_w(&TransportChannelImpl::Connect); | 329 CallChannels(&TransportChannelImpl::Connect); |
343 if (!channels_.empty()) { | 330 if (HasChannels()) { |
344 signaling_thread()->Post(this, MSG_CONNECTING, NULL); | 331 SignalConnecting(this); |
345 } | 332 } |
346 } | 333 } |
347 | 334 |
348 void Transport::OnConnecting_s() { | |
349 ASSERT(signaling_thread()->IsCurrent()); | |
350 SignalConnecting(this); | |
351 } | |
352 | |
353 void Transport::DestroyAllChannels() { | 335 void Transport::DestroyAllChannels() { |
354 ASSERT(signaling_thread()->IsCurrent()); | |
355 worker_thread_->Invoke<void>(Bind(&Transport::DestroyAllChannels_w, this)); | |
356 worker_thread()->Clear(this); | |
357 signaling_thread()->Clear(this); | |
358 destroyed_ = true; | |
359 } | |
360 | |
361 void Transport::DestroyAllChannels_w() { | |
362 ASSERT(worker_thread()->IsCurrent()); | |
363 | |
364 std::vector<TransportChannelImpl*> impls; | 336 std::vector<TransportChannelImpl*> impls; |
365 for (auto& iter : channels_) { | 337 for (auto& iter : channels_) { |
366 iter.second.DecRef(); | 338 iter.second.DecRef(); |
367 if (!iter.second.ref()) | 339 if (!iter.second.ref()) |
368 impls.push_back(iter.second.get()); | 340 impls.push_back(iter.second.get()); |
369 } | 341 } |
370 | 342 |
371 { | 343 channels_.clear(); |
372 rtc::CritScope cs(&crit_); | 344 |
373 channels_.clear(); | 345 for (TransportChannelImpl* impl : impls) { |
| 346 DestroyTransportChannel(impl); |
374 } | 347 } |
375 | 348 channels_destroyed_ = true; |
376 for (size_t i = 0; i < impls.size(); ++i) | |
377 DestroyTransportChannel(impls[i]); | |
378 } | 349 } |
379 | 350 |
380 void Transport::OnSignalingReady() { | 351 void Transport::CallChannels(TransportChannelFunc func) { |
381 ASSERT(signaling_thread()->IsCurrent()); | |
382 if (destroyed_) return; | |
383 | |
384 worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL); | |
385 | |
386 // Notify the subclass. | |
387 OnTransportSignalingReady(); | |
388 } | |
389 | |
390 void Transport::CallChannels_w(TransportChannelFunc func) { | |
391 ASSERT(worker_thread()->IsCurrent()); | |
392 for (const auto& iter : channels_) { | 352 for (const auto& iter : channels_) { |
393 ((iter.second.get())->*func)(); | 353 ((iter.second.get())->*func)(); |
394 } | 354 } |
395 } | 355 } |
396 | 356 |
397 bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) { | 357 bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) { |
398 // No address zero. | 358 // No address zero. |
399 if (cand.address().IsNil() || cand.address().IsAny()) { | 359 if (cand.address().IsNil() || cand.address().IsAny()) { |
400 *error = "candidate has address of zero"; | 360 *error = "candidate has address of zero"; |
401 return false; | 361 return false; |
(...skipping 18 matching lines...) Expand all Loading... |
420 *error = "candidate has port of 80 or 443 with private IP address"; | 380 *error = "candidate has port of 80 or 443 with private IP address"; |
421 return false; | 381 return false; |
422 } | 382 } |
423 } | 383 } |
424 | 384 |
425 return true; | 385 return true; |
426 } | 386 } |
427 | 387 |
428 | 388 |
429 bool Transport::GetStats(TransportStats* stats) { | 389 bool Transport::GetStats(TransportStats* stats) { |
430 ASSERT(signaling_thread()->IsCurrent()); | 390 stats->transport_name = name(); |
431 return worker_thread_->Invoke<bool>(Bind( | |
432 &Transport::GetStats_w, this, stats)); | |
433 } | |
434 | |
435 bool Transport::GetStats_w(TransportStats* stats) { | |
436 ASSERT(worker_thread()->IsCurrent()); | |
437 stats->content_name = content_name(); | |
438 stats->channel_stats.clear(); | 391 stats->channel_stats.clear(); |
439 for (auto iter : channels_) { | 392 for (auto iter : channels_) { |
440 ChannelMapEntry& entry = iter.second; | 393 ChannelMapEntry& entry = iter.second; |
441 TransportChannelStats substats; | 394 TransportChannelStats substats; |
442 substats.component = entry->component(); | 395 substats.component = entry->component(); |
443 entry->GetSrtpCipher(&substats.srtp_cipher); | 396 entry->GetSrtpCipher(&substats.srtp_cipher); |
444 entry->GetSslCipher(&substats.ssl_cipher); | 397 entry->GetSslCipher(&substats.ssl_cipher); |
445 if (!entry->GetStats(&substats.connection_infos)) { | 398 if (!entry->GetStats(&substats.connection_infos)) { |
446 return false; | 399 return false; |
447 } | 400 } |
448 stats->channel_stats.push_back(substats); | 401 stats->channel_stats.push_back(substats); |
449 } | 402 } |
450 return true; | 403 return true; |
451 } | 404 } |
452 | 405 |
453 bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const { | 406 bool Transport::AddRemoteCandidates(const std::vector<Candidate>& candidates, |
454 return worker_thread_->Invoke<bool>(Bind( | 407 std::string* error) { |
455 &Transport::GetSslRole_w, this, ssl_role)); | 408 ASSERT(!channels_destroyed_); |
456 } | 409 // Verify each candidate before passing down to transport layer. |
| 410 for (const Candidate& cand : candidates) { |
| 411 if (!VerifyCandidate(cand, error)) { |
| 412 return false; |
| 413 } |
| 414 if (!HasChannel(cand.component())) { |
| 415 *error = "Candidate has unknown component: " + cand.ToString() + |
| 416 " for content: " + name(); |
| 417 return false; |
| 418 } |
| 419 } |
457 | 420 |
458 bool Transport::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) { | |
459 return worker_thread_->Invoke<bool>(Bind( | |
460 &Transport::SetSslMaxProtocolVersion_w, this, version)); | |
461 } | |
462 | |
463 void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) { | |
464 for (std::vector<Candidate>::const_iterator iter = candidates.begin(); | 421 for (std::vector<Candidate>::const_iterator iter = candidates.begin(); |
465 iter != candidates.end(); | 422 iter != candidates.end(); |
466 ++iter) { | 423 ++iter) { |
467 OnRemoteCandidate(*iter); | 424 TransportChannelImpl* channel = GetChannel(iter->component()); |
| 425 if (channel != NULL) { |
| 426 channel->AddRemoteCandidate(*iter); |
| 427 } |
468 } | 428 } |
469 } | 429 return true; |
470 | |
471 void Transport::OnRemoteCandidate(const Candidate& candidate) { | |
472 ASSERT(signaling_thread()->IsCurrent()); | |
473 if (destroyed_) return; | |
474 | |
475 if (!HasChannel(candidate.component())) { | |
476 LOG(LS_WARNING) << "Ignoring candidate for unknown component " | |
477 << candidate.component(); | |
478 return; | |
479 } | |
480 | |
481 ChannelParams* params = new ChannelParams(new Candidate(candidate)); | |
482 worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params); | |
483 } | |
484 | |
485 void Transport::OnRemoteCandidate_w(const Candidate& candidate) { | |
486 ASSERT(worker_thread()->IsCurrent()); | |
487 ChannelMap::iterator iter = channels_.find(candidate.component()); | |
488 // It's ok for a channel to go away while this message is in transit. | |
489 if (iter != channels_.end()) { | |
490 iter->second->OnCandidate(candidate); | |
491 } | |
492 } | 430 } |
493 | 431 |
494 void Transport::OnChannelWritableState(TransportChannel* channel) { | 432 void Transport::OnChannelWritableState(TransportChannel* channel) { |
495 ASSERT(worker_thread()->IsCurrent()); | 433 LOG(LS_INFO) << name() << " TransportChannel " << channel->component() |
496 signaling_thread()->Post(this, MSG_WRITESTATE, NULL); | 434 << " writability changed to " << channel->writable() |
497 | 435 << ". Check if transport is complete."; |
498 MaybeCompleted_w(); | 436 UpdateWritableState(); |
499 } | 437 MaybeSignalCompleted(); |
500 | |
501 void Transport::OnChannelWritableState_s() { | |
502 ASSERT(signaling_thread()->IsCurrent()); | |
503 TransportState writable = GetTransportState_s(TRANSPORT_WRITABLE_STATE); | |
504 if (writable_ != writable) { | |
505 was_writable_ = (writable_ == TRANSPORT_STATE_ALL); | |
506 writable_ = writable; | |
507 SignalWritableState(this); | |
508 } | |
509 } | 438 } |
510 | 439 |
511 void Transport::OnChannelReceivingState(TransportChannel* channel) { | 440 void Transport::OnChannelReceivingState(TransportChannel* channel) { |
512 ASSERT(worker_thread()->IsCurrent()); | 441 UpdateReceivingState(); |
513 signaling_thread()->Post(this, MSG_RECEIVINGSTATE); | |
514 } | 442 } |
515 | 443 |
516 void Transport::OnChannelReceivingState_s() { | 444 TransportState Transport::GetTransportState(TransportStateType state_type) { |
517 ASSERT(signaling_thread()->IsCurrent()); | |
518 TransportState receiving = GetTransportState_s(TRANSPORT_RECEIVING_STATE); | |
519 if (receiving_ != receiving) { | |
520 receiving_ = receiving; | |
521 SignalReceivingState(this); | |
522 } | |
523 } | |
524 | |
525 TransportState Transport::GetTransportState_s(TransportStateType state_type) { | |
526 ASSERT(signaling_thread()->IsCurrent()); | |
527 | |
528 rtc::CritScope cs(&crit_); | |
529 bool any = false; | 445 bool any = false; |
530 bool all = !channels_.empty(); | 446 bool all = !channels_.empty(); |
531 for (const auto iter : channels_) { | 447 for (const auto iter : channels_) { |
532 bool b = false; | 448 bool b = false; |
533 switch (state_type) { | 449 switch (state_type) { |
534 case TRANSPORT_WRITABLE_STATE: | 450 case TRANSPORT_WRITABLE_STATE: |
535 b = iter.second->writable(); | 451 b = iter.second->writable(); |
536 break; | 452 break; |
537 case TRANSPORT_RECEIVING_STATE: | 453 case TRANSPORT_RECEIVING_STATE: |
538 b = iter.second->receiving(); | 454 b = iter.second->receiving(); |
539 break; | 455 break; |
540 default: | 456 default: |
541 ASSERT(false); | 457 ASSERT(false); |
542 } | 458 } |
543 any |= b; | 459 any |= b; |
544 all &= b; | 460 all &= b; |
545 } | 461 } |
546 | 462 |
547 if (all) { | 463 if (all) { |
548 return TRANSPORT_STATE_ALL; | 464 return TRANSPORT_STATE_ALL; |
549 } else if (any) { | 465 } else if (any) { |
550 return TRANSPORT_STATE_SOME; | 466 return TRANSPORT_STATE_SOME; |
551 } | 467 } |
552 | 468 |
553 return TRANSPORT_STATE_NONE; | 469 return TRANSPORT_STATE_NONE; |
554 } | 470 } |
555 | 471 |
556 void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) { | 472 void Transport::OnChannelGatheringState(TransportChannelImpl* channel) { |
557 ASSERT(worker_thread()->IsCurrent()); | 473 ASSERT(channels_.find(channel->component()) != channels_.end()); |
558 // Resetting ICE state for the channel. | 474 UpdateGatheringState(); |
559 ChannelMap::iterator iter = channels_.find(channel->component()); | 475 if (gathering_state_ == kIceGatheringComplete) { |
560 if (iter != channels_.end()) | 476 // If UpdateGatheringState brought us to kIceGatheringComplete, check if |
561 iter->second.set_candidates_allocated(false); | 477 // our connection state is also "Completed". Otherwise, there's no point in |
562 signaling_thread()->Post(this, MSG_REQUESTSIGNALING, nullptr); | 478 // checking (since it would only produce log messages). |
| 479 MaybeSignalCompleted(); |
| 480 } |
563 } | 481 } |
564 | 482 |
565 void Transport::OnChannelRequestSignaling_s() { | 483 void Transport::OnChannelCandidateGathered(TransportChannelImpl* channel, |
566 ASSERT(signaling_thread()->IsCurrent()); | 484 const Candidate& candidate) { |
567 LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates"; | |
568 SignalRequestSignaling(this); | |
569 } | |
570 | |
571 void Transport::OnChannelCandidateReady(TransportChannelImpl* channel, | |
572 const Candidate& candidate) { | |
573 // We should never signal peer-reflexive candidates. | 485 // We should never signal peer-reflexive candidates. |
574 if (candidate.type() == PRFLX_PORT_TYPE) { | 486 if (candidate.type() == PRFLX_PORT_TYPE) { |
575 ASSERT(false); | 487 ASSERT(false); |
576 return; | 488 return; |
577 } | 489 } |
578 | 490 |
579 ASSERT(worker_thread()->IsCurrent()); | |
580 rtc::CritScope cs(&crit_); | |
581 ready_candidates_.push_back(candidate); | |
582 | |
583 // We hold any messages until the client lets us connect. | |
584 if (connect_requested_) { | 491 if (connect_requested_) { |
585 signaling_thread()->Post( | 492 std::vector<Candidate> candidates; |
586 this, MSG_CANDIDATEREADY, NULL); | 493 candidates.push_back(candidate); |
587 } | 494 SignalCandidatesGathered(this, candidates); |
588 } | 495 } else { |
589 | 496 // We hold any candidates until the client lets us connect. |
590 void Transport::OnChannelCandidateReady_s() { | 497 ready_candidates_.push_back(candidate); |
591 ASSERT(signaling_thread()->IsCurrent()); | |
592 ASSERT(connect_requested_); | |
593 | |
594 std::vector<Candidate> candidates; | |
595 { | |
596 rtc::CritScope cs(&crit_); | |
597 candidates.swap(ready_candidates_); | |
598 } | |
599 | |
600 // we do the deleting of Candidate* here to keep the new above and | |
601 // delete below close to each other | |
602 if (!candidates.empty()) { | |
603 SignalCandidatesReady(this, candidates); | |
604 } | 498 } |
605 } | 499 } |
606 | 500 |
607 void Transport::OnChannelRouteChange(TransportChannel* channel, | 501 void Transport::OnChannelRouteChange(TransportChannel* channel, |
608 const Candidate& remote_candidate) { | 502 const Candidate& remote_candidate) { |
609 ASSERT(worker_thread()->IsCurrent()); | |
610 ChannelParams* params = new ChannelParams(new Candidate(remote_candidate)); | |
611 params->channel = static_cast<cricket::TransportChannelImpl*>(channel); | |
612 signaling_thread()->Post(this, MSG_ROUTECHANGE, params); | |
613 } | |
614 | |
615 void Transport::OnChannelRouteChange_s(const TransportChannel* channel, | |
616 const Candidate& remote_candidate) { | |
617 ASSERT(signaling_thread()->IsCurrent()); | |
618 SignalRouteChange(this, remote_candidate.component(), remote_candidate); | 503 SignalRouteChange(this, remote_candidate.component(), remote_candidate); |
619 } | 504 } |
620 | 505 |
621 void Transport::OnChannelCandidatesAllocationDone( | |
622 TransportChannelImpl* channel) { | |
623 ASSERT(worker_thread()->IsCurrent()); | |
624 ChannelMap::iterator iter = channels_.find(channel->component()); | |
625 ASSERT(iter != channels_.end()); | |
626 LOG(LS_INFO) << "Transport: " << content_name_ << ", component " | |
627 << channel->component() << " allocation complete"; | |
628 | |
629 iter->second.set_candidates_allocated(true); | |
630 | |
631 // If all channels belonging to this Transport got signal, then | |
632 // forward this signal to upper layer. | |
633 // Can this signal arrive before all transport channels are created? | |
634 for (auto& iter : channels_) { | |
635 if (!iter.second.candidates_allocated()) | |
636 return; | |
637 } | |
638 signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE); | |
639 | |
640 MaybeCompleted_w(); | |
641 } | |
642 | |
643 void Transport::OnChannelCandidatesAllocationDone_s() { | |
644 ASSERT(signaling_thread()->IsCurrent()); | |
645 LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete"; | |
646 SignalCandidatesAllocationDone(this); | |
647 } | |
648 | |
649 void Transport::OnRoleConflict(TransportChannelImpl* channel) { | 506 void Transport::OnRoleConflict(TransportChannelImpl* channel) { |
650 signaling_thread_->Post(this, MSG_ROLECONFLICT); | 507 SignalRoleConflict(); |
651 } | 508 } |
652 | 509 |
653 void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) { | 510 void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) { |
654 ASSERT(worker_thread()->IsCurrent()); | 511 LOG(LS_INFO) << name() << " TransportChannel " << channel->component() |
655 MaybeCompleted_w(); | 512 << " connection removed. Check if transport is complete."; |
| 513 MaybeSignalCompleted(); |
656 | 514 |
657 // Check if the state is now Failed. | 515 // Check if the state is now Failed. |
658 // Failed is only available in the Controlling ICE role. | 516 // Failed is only available in the Controlling ICE role. |
659 if (channel->GetIceRole() != ICEROLE_CONTROLLING) { | 517 if (channel->GetIceRole() != ICEROLE_CONTROLLING) { |
660 return; | 518 return; |
661 } | 519 } |
662 | 520 |
663 ChannelMap::iterator iter = channels_.find(channel->component()); | 521 // Failed can only occur after candidate gathering has stopped. |
664 ASSERT(iter != channels_.end()); | 522 if (channel->gathering_state() != kIceGatheringComplete) { |
665 // Failed can only occur after candidate allocation has stopped. | |
666 if (!iter->second.candidates_allocated()) { | |
667 return; | 523 return; |
668 } | 524 } |
669 | 525 |
670 if (channel->GetState() == TransportChannelState::STATE_FAILED) { | 526 if (channel->GetState() == TransportChannelState::STATE_FAILED) { |
671 // A Transport has failed if any of its channels have no remaining | 527 // A Transport has failed if any of its channels have no remaining |
672 // connections. | 528 // connections. |
673 signaling_thread_->Post(this, MSG_FAILED); | 529 SignalFailed(this); |
674 } | 530 } |
675 } | 531 } |
676 | 532 |
677 void Transport::MaybeCompleted_w() { | 533 void Transport::MaybeSignalCompleted() { |
678 ASSERT(worker_thread()->IsCurrent()); | 534 if (AllChannelsCompleted()) { |
| 535 LOG(LS_INFO) << name() << " transport is complete" |
| 536 << " because all the channels are complete."; |
| 537 SignalCompleted(this); |
| 538 } |
| 539 // TODO(deadbeef): Should we do anything if we previously were completed, |
| 540 // but now are not (if, for example, a new remote candidate is added)? |
| 541 } |
679 | 542 |
680 // When there is no channel created yet, calling this function could fire an | 543 void Transport::UpdateGatheringState() { |
681 // IceConnectionCompleted event prematurely. | 544 IceGatheringState new_state = kIceGatheringNew; |
682 if (channels_.empty()) { | 545 bool any_gathering = false; |
683 return; | 546 bool all_complete = !channels_.empty(); |
| 547 for (const auto& kv : channels_) { |
| 548 any_gathering = |
| 549 any_gathering || kv.second->gathering_state() != kIceGatheringNew; |
| 550 all_complete = |
| 551 all_complete && kv.second->gathering_state() == kIceGatheringComplete; |
| 552 } |
| 553 if (all_complete) { |
| 554 new_state = kIceGatheringComplete; |
| 555 } else if (any_gathering) { |
| 556 new_state = kIceGatheringGathering; |
684 } | 557 } |
685 | 558 |
686 // A Transport's ICE process is completed if all of its channels are writable, | 559 if (gathering_state_ != new_state) { |
687 // have finished allocating candidates, and have pruned all but one of their | 560 gathering_state_ = new_state; |
688 // connections. | 561 if (gathering_state_ == kIceGatheringGathering) { |
689 for (const auto& iter : channels_) { | 562 LOG(LS_INFO) << "Transport: " << name_ << ", gathering candidates"; |
690 const TransportChannelImpl* channel = iter.second.get(); | 563 } else if (gathering_state_ == kIceGatheringComplete) { |
691 if (!(channel->writable() && | 564 LOG(LS_INFO) << "Transport " << name() << " gathering complete."; |
692 channel->GetState() == TransportChannelState::STATE_COMPLETED && | |
693 channel->GetIceRole() == ICEROLE_CONTROLLING && | |
694 iter.second.candidates_allocated())) { | |
695 return; | |
696 } | 565 } |
697 } | 566 SignalGatheringState(this); |
698 | |
699 signaling_thread_->Post(this, MSG_COMPLETED); | |
700 } | |
701 | |
702 void Transport::SetIceRole_w(IceRole role) { | |
703 ASSERT(worker_thread()->IsCurrent()); | |
704 rtc::CritScope cs(&crit_); | |
705 ice_role_ = role; | |
706 for (auto& iter : channels_) { | |
707 iter.second->SetIceRole(ice_role_); | |
708 } | 567 } |
709 } | 568 } |
710 | 569 |
711 void Transport::SetRemoteIceMode_w(IceMode mode) { | 570 void Transport::UpdateReceivingState() { |
712 ASSERT(worker_thread()->IsCurrent()); | 571 TransportState receiving = GetTransportState(TRANSPORT_RECEIVING_STATE); |
713 remote_ice_mode_ = mode; | 572 if (receiving_ != receiving) { |
714 // Shouldn't channels be created after this method executed? | 573 receiving_ = receiving; |
715 for (auto& iter : channels_) { | 574 SignalReceivingState(this); |
716 iter.second->SetRemoteIceMode(remote_ice_mode_); | |
717 } | 575 } |
718 } | 576 } |
719 | 577 |
720 bool Transport::SetLocalTransportDescription_w( | 578 void Transport::UpdateWritableState() { |
721 const TransportDescription& desc, | 579 TransportState writable = GetTransportState(TRANSPORT_WRITABLE_STATE); |
722 ContentAction action, | 580 LOG(LS_INFO) << name() << " transport writable state changed? " << writable_ |
723 std::string* error_desc) { | 581 << " => " << writable; |
724 ASSERT(worker_thread()->IsCurrent()); | 582 if (writable_ != writable) { |
725 bool ret = true; | 583 was_writable_ = (writable_ == TRANSPORT_STATE_ALL); |
726 | 584 writable_ = writable; |
727 if (!VerifyIceParams(desc)) { | 585 SignalWritableState(this); |
728 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", | |
729 error_desc); | |
730 } | 586 } |
731 | |
732 // TODO(tommi,pthatcher): I'm not sure why we need to grab this lock at this | |
733 // point. |local_description_| seems to always be modified on the worker | |
734 // thread, so we should be able to use it here without grabbing the lock. | |
735 // However, we _might_ need it before the call to reset() below? | |
736 // Raw access to |local_description_| is granted to derived transports outside | |
737 // of locking (see local_description() in the header file). | |
738 // The contract is that the derived implementations must be aware of when the | |
739 // description might change and do appropriate synchronization. | |
740 rtc::CritScope cs(&crit_); | |
741 if (local_description_ && IceCredentialsChanged(*local_description_, desc)) { | |
742 IceRole new_ice_role = (action == CA_OFFER) ? ICEROLE_CONTROLLING | |
743 : ICEROLE_CONTROLLED; | |
744 | |
745 // It must be called before ApplyLocalTransportDescription_w, which may | |
746 // trigger an ICE restart and depends on the new ICE role. | |
747 SetIceRole_w(new_ice_role); | |
748 } | |
749 | |
750 local_description_.reset(new TransportDescription(desc)); | |
751 | |
752 for (auto& iter : channels_) { | |
753 ret &= ApplyLocalTransportDescription_w(iter.second.get(), error_desc); | |
754 } | |
755 if (!ret) | |
756 return false; | |
757 | |
758 // If PRANSWER/ANSWER is set, we should decide transport protocol type. | |
759 if (action == CA_PRANSWER || action == CA_ANSWER) { | |
760 ret &= NegotiateTransportDescription_w(action, error_desc); | |
761 } | |
762 return ret; | |
763 } | 587 } |
764 | 588 |
765 bool Transport::SetRemoteTransportDescription_w( | 589 bool Transport::ApplyLocalTransportDescription(TransportChannelImpl* ch, |
766 const TransportDescription& desc, | 590 std::string* error_desc) { |
767 ContentAction action, | |
768 std::string* error_desc) { | |
769 bool ret = true; | |
770 | |
771 if (!VerifyIceParams(desc)) { | |
772 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", | |
773 error_desc); | |
774 } | |
775 | |
776 // TODO(tommi,pthatcher): See todo for local_description_ above. | |
777 rtc::CritScope cs(&crit_); | |
778 remote_description_.reset(new TransportDescription(desc)); | |
779 for (auto& iter : channels_) { | |
780 ret &= ApplyRemoteTransportDescription_w(iter.second.get(), error_desc); | |
781 } | |
782 | |
783 // If PRANSWER/ANSWER is set, we should decide transport protocol type. | |
784 if (action == CA_PRANSWER || action == CA_ANSWER) { | |
785 ret = NegotiateTransportDescription_w(CA_OFFER, error_desc); | |
786 } | |
787 return ret; | |
788 } | |
789 | |
790 bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch, | |
791 std::string* error_desc) { | |
792 ASSERT(worker_thread()->IsCurrent()); | |
793 ch->SetIceCredentials(local_description_->ice_ufrag, | 591 ch->SetIceCredentials(local_description_->ice_ufrag, |
794 local_description_->ice_pwd); | 592 local_description_->ice_pwd); |
795 return true; | 593 return true; |
796 } | 594 } |
797 | 595 |
798 bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch, | 596 bool Transport::ApplyRemoteTransportDescription(TransportChannelImpl* ch, |
799 std::string* error_desc) { | 597 std::string* error_desc) { |
800 ch->SetRemoteIceCredentials(remote_description_->ice_ufrag, | 598 ch->SetRemoteIceCredentials(remote_description_->ice_ufrag, |
801 remote_description_->ice_pwd); | 599 remote_description_->ice_pwd); |
802 return true; | 600 return true; |
803 } | 601 } |
804 | 602 |
805 bool Transport::ApplyNegotiatedTransportDescription_w( | 603 bool Transport::ApplyNegotiatedTransportDescription( |
806 TransportChannelImpl* channel, std::string* error_desc) { | 604 TransportChannelImpl* channel, |
807 ASSERT(worker_thread()->IsCurrent()); | 605 std::string* error_desc) { |
808 channel->SetRemoteIceMode(remote_ice_mode_); | 606 channel->SetRemoteIceMode(remote_ice_mode_); |
809 return true; | 607 return true; |
810 } | 608 } |
811 | 609 |
812 bool Transport::NegotiateTransportDescription_w(ContentAction local_role, | 610 bool Transport::NegotiateTransportDescription(ContentAction local_role, |
813 std::string* error_desc) { | 611 std::string* error_desc) { |
814 ASSERT(worker_thread()->IsCurrent()); | |
815 // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into | 612 // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into |
816 // P2PTransport. | 613 // P2PTransport. |
817 | 614 |
818 // If transport is in ICEROLE_CONTROLLED and remote end point supports only | 615 // If transport is in ICEROLE_CONTROLLED and remote end point supports only |
819 // ice_lite, this local end point should take CONTROLLING role. | 616 // ice_lite, this local end point should take CONTROLLING role. |
820 if (ice_role_ == ICEROLE_CONTROLLED && | 617 if (ice_role_ == ICEROLE_CONTROLLED && |
821 remote_description_->ice_mode == ICEMODE_LITE) { | 618 remote_description_->ice_mode == ICEMODE_LITE) { |
822 SetIceRole_w(ICEROLE_CONTROLLING); | 619 SetIceRole(ICEROLE_CONTROLLING); |
823 } | 620 } |
824 | 621 |
825 // Update remote ice_mode to all existing channels. | 622 // Update remote ice_mode to all existing channels. |
826 remote_ice_mode_ = remote_description_->ice_mode; | 623 remote_ice_mode_ = remote_description_->ice_mode; |
827 | 624 |
828 // Now that we have negotiated everything, push it downward. | 625 // Now that we have negotiated everything, push it downward. |
829 // Note that we cache the result so that if we have race conditions | 626 // Note that we cache the result so that if we have race conditions |
830 // between future SetRemote/SetLocal invocations and new channel | 627 // between future SetRemote/SetLocal invocations and new channel |
831 // creation, we have the negotiation state saved until a new | 628 // creation, we have the negotiation state saved until a new |
832 // negotiation happens. | 629 // negotiation happens. |
833 for (auto& iter : channels_) { | 630 for (auto& iter : channels_) { |
834 if (!ApplyNegotiatedTransportDescription_w(iter.second.get(), error_desc)) | 631 if (!ApplyNegotiatedTransportDescription(iter.second.get(), error_desc)) |
835 return false; | 632 return false; |
836 } | 633 } |
837 return true; | 634 return true; |
838 } | 635 } |
839 | 636 |
840 void Transport::OnMessage(rtc::Message* msg) { | |
841 switch (msg->message_id) { | |
842 case MSG_ONSIGNALINGREADY: | |
843 CallChannels_w(&TransportChannelImpl::OnSignalingReady); | |
844 break; | |
845 case MSG_ONREMOTECANDIDATE: { | |
846 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata); | |
847 OnRemoteCandidate_w(*params->candidate); | |
848 delete params; | |
849 } | |
850 break; | |
851 case MSG_CONNECTING: | |
852 OnConnecting_s(); | |
853 break; | |
854 case MSG_WRITESTATE: | |
855 OnChannelWritableState_s(); | |
856 break; | |
857 case MSG_RECEIVINGSTATE: | |
858 OnChannelReceivingState_s(); | |
859 break; | |
860 case MSG_REQUESTSIGNALING: | |
861 OnChannelRequestSignaling_s(); | |
862 break; | |
863 case MSG_CANDIDATEREADY: | |
864 OnChannelCandidateReady_s(); | |
865 break; | |
866 case MSG_ROUTECHANGE: { | |
867 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata); | |
868 OnChannelRouteChange_s(params->channel, *params->candidate); | |
869 delete params; | |
870 } | |
871 break; | |
872 case MSG_CANDIDATEALLOCATIONCOMPLETE: | |
873 OnChannelCandidatesAllocationDone_s(); | |
874 break; | |
875 case MSG_ROLECONFLICT: | |
876 SignalRoleConflict(); | |
877 break; | |
878 case MSG_COMPLETED: | |
879 SignalCompleted(this); | |
880 break; | |
881 case MSG_FAILED: | |
882 SignalFailed(this); | |
883 break; | |
884 } | |
885 } | |
886 | |
887 } // namespace cricket | 637 } // namespace cricket |
OLD | NEW |