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