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