3 * Copyright 2004, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "talk/p2p/base/transport.h"
30 #include "talk/p2p/base/candidate.h"
31 #include "talk/p2p/base/constants.h"
32 #include "talk/p2p/base/parsing.h"
33 #include "talk/p2p/base/port.h"
34 #include "talk/p2p/base/sessionmanager.h"
35 #include "talk/p2p/base/transportchannelimpl.h"
36 #include "webrtc/libjingle/xmllite/xmlelement.h"
37 #include "talk/xmpp/constants.h"
38 #include "webrtc/base/bind.h"
39 #include "webrtc/base/common.h"
40 #include "webrtc/base/logging.h"
47 MSG_ONSIGNALINGREADY = 1,
48 MSG_ONREMOTECANDIDATE,
55 MSG_CANDIDATEALLOCATIONCOMPLETE,
61 struct ChannelParams : public rtc::MessageData {
62 ChannelParams() : channel(NULL), candidate(NULL) {}
63 explicit ChannelParams(int component)
64 : component(component), channel(NULL), candidate(NULL) {}
65 explicit ChannelParams(Candidate* candidate)
66 : channel(NULL), candidate(candidate) {
75 TransportChannelImpl* channel;
79 static std::string IceProtoToString(TransportProtocol proto) {
80 std::string proto_str;
88 case ICEPROTO_RFC5245:
98 static bool VerifyIceParams(const TransportDescription& desc) {
99 // For legacy protocols.
100 if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
103 if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
104 desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
107 if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
108 desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
114 bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
118 LOG(LS_ERROR) << desc;
122 bool IceCredentialsChanged(const std::string& old_ufrag,
123 const std::string& old_pwd,
124 const std::string& new_ufrag,
125 const std::string& new_pwd) {
126 // TODO(jiayl): The standard (RFC 5245 Section 9.1.1.1) says that ICE should
127 // restart when both the ufrag and password are changed, but we do restart
128 // when either ufrag or passwrod is changed to keep compatible with GICE. We
129 // should clean this up when GICE is no longer used.
130 return (old_ufrag != new_ufrag) || (old_pwd != new_pwd);
133 static bool IceCredentialsChanged(const TransportDescription& old_desc,
134 const TransportDescription& new_desc) {
135 return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd,
136 new_desc.ice_ufrag, new_desc.ice_pwd);
139 Transport::Transport(rtc::Thread* signaling_thread,
140 rtc::Thread* worker_thread,
141 const std::string& content_name,
142 const std::string& type,
143 PortAllocator* allocator)
144 : signaling_thread_(signaling_thread),
145 worker_thread_(worker_thread),
146 content_name_(content_name),
148 allocator_(allocator),
150 readable_(TRANSPORT_STATE_NONE),
151 writable_(TRANSPORT_STATE_NONE),
152 was_writable_(false),
153 connect_requested_(false),
154 ice_role_(ICEROLE_UNKNOWN),
156 protocol_(ICEPROTO_HYBRID),
157 remote_ice_mode_(ICEMODE_FULL) {
160 Transport::~Transport() {
161 ASSERT(signaling_thread_->IsCurrent());
165 void Transport::SetIceRole(IceRole role) {
166 worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
169 void Transport::SetIdentity(rtc::SSLIdentity* identity) {
170 worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity));
173 bool Transport::GetIdentity(rtc::SSLIdentity** identity) {
174 // The identity is set on the worker thread, so for safety it must also be
175 // acquired on the worker thread.
176 return worker_thread_->Invoke<bool>(
177 Bind(&Transport::GetIdentity_w, this, identity));
180 bool Transport::GetRemoteCertificate(rtc::SSLCertificate** cert) {
181 // Channels can be deleted on the worker thread, so for safety the remote
182 // certificate is acquired on the worker thread.
183 return worker_thread_->Invoke<bool>(
184 Bind(&Transport::GetRemoteCertificate_w, this, cert));
187 bool Transport::GetRemoteCertificate_w(rtc::SSLCertificate** cert) {
188 ASSERT(worker_thread()->IsCurrent());
189 if (channels_.empty())
192 ChannelMap::iterator iter = channels_.begin();
193 return iter->second->GetRemoteCertificate(cert);
196 bool Transport::SetLocalTransportDescription(
197 const TransportDescription& description,
198 ContentAction action,
199 std::string* error_desc) {
200 return worker_thread_->Invoke<bool>(Bind(
201 &Transport::SetLocalTransportDescription_w, this,
202 description, action, error_desc));
205 bool Transport::SetRemoteTransportDescription(
206 const TransportDescription& description,
207 ContentAction action,
208 std::string* error_desc) {
209 return worker_thread_->Invoke<bool>(Bind(
210 &Transport::SetRemoteTransportDescription_w, this,
211 description, action, error_desc));
214 TransportChannelImpl* Transport::CreateChannel(int component) {
215 return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
216 &Transport::CreateChannel_w, this, component));
219 TransportChannelImpl* Transport::CreateChannel_w(int component) {
220 ASSERT(worker_thread()->IsCurrent());
221 TransportChannelImpl *impl;
222 rtc::CritScope cs(&crit_);
224 // Create the entry if it does not exist.
225 bool impl_exists = false;
226 if (channels_.find(component) == channels_.end()) {
227 impl = CreateTransportChannel(component);
228 channels_[component] = ChannelMapEntry(impl);
230 impl = channels_[component].get();
234 // Increase the ref count.
235 channels_[component].AddRef();
239 // If this is an existing channel, we should just return it without
240 // connecting to all the signal again.
244 // Push down our transport state to the new channel.
245 impl->SetIceRole(ice_role_);
246 impl->SetIceTiebreaker(tiebreaker_);
247 // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
248 // below Apply**Description_w calls can fail.
249 if (local_description_)
250 ApplyLocalTransportDescription_w(impl, NULL);
251 if (remote_description_)
252 ApplyRemoteTransportDescription_w(impl, NULL);
253 if (local_description_ && remote_description_)
254 ApplyNegotiatedTransportDescription_w(impl, NULL);
256 impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
257 impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
258 impl->SignalRequestSignaling.connect(
259 this, &Transport::OnChannelRequestSignaling);
260 impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady);
261 impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange);
262 impl->SignalCandidatesAllocationDone.connect(
263 this, &Transport::OnChannelCandidatesAllocationDone);
264 impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
265 impl->SignalConnectionRemoved.connect(
266 this, &Transport::OnChannelConnectionRemoved);
268 if (connect_requested_) {
270 if (channels_.size() == 1) {
271 // If this is the first channel, then indicate that we have started
273 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
279 TransportChannelImpl* Transport::GetChannel(int component) {
280 rtc::CritScope cs(&crit_);
281 ChannelMap::iterator iter = channels_.find(component);
282 return (iter != channels_.end()) ? iter->second.get() : NULL;
285 bool Transport::HasChannels() {
286 rtc::CritScope cs(&crit_);
287 return !channels_.empty();
290 void Transport::DestroyChannel(int component) {
291 worker_thread_->Invoke<void>(Bind(
292 &Transport::DestroyChannel_w, this, component));
295 void Transport::DestroyChannel_w(int component) {
296 ASSERT(worker_thread()->IsCurrent());
298 TransportChannelImpl* impl = NULL;
300 rtc::CritScope cs(&crit_);
301 ChannelMap::iterator iter = channels_.find(component);
302 if (iter == channels_.end())
305 iter->second.DecRef();
306 if (!iter->second.ref()) {
307 impl = iter->second.get();
308 channels_.erase(iter);
312 if (connect_requested_ && channels_.empty()) {
313 // We're no longer attempting to connect.
314 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
318 // Check in case the deleted channel was the only non-writable channel.
319 OnChannelWritableState(impl);
320 DestroyTransportChannel(impl);
324 void Transport::ConnectChannels() {
325 ASSERT(signaling_thread()->IsCurrent());
326 worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
329 void Transport::ConnectChannels_w() {
330 ASSERT(worker_thread()->IsCurrent());
331 if (connect_requested_ || channels_.empty())
333 connect_requested_ = true;
334 signaling_thread()->Post(
335 this, MSG_CANDIDATEREADY, NULL);
337 if (!local_description_) {
338 // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
339 // As Transport must know TD is offer or answer and cricket::Transport
340 // doesn't have the capability to decide it. This should be set by the
342 // Session must generate local TD before remote candidates pushed when
343 // initiate request initiated by the remote.
344 LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has "
345 << "been set. Will generate one.";
346 TransportDescription desc(NS_GINGLE_P2P, std::vector<std::string>(),
347 rtc::CreateRandomString(ICE_UFRAG_LENGTH),
348 rtc::CreateRandomString(ICE_PWD_LENGTH),
349 ICEMODE_FULL, CONNECTIONROLE_NONE, NULL,
351 SetLocalTransportDescription_w(desc, CA_OFFER, NULL);
354 CallChannels_w(&TransportChannelImpl::Connect);
355 if (!channels_.empty()) {
356 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
360 void Transport::OnConnecting_s() {
361 ASSERT(signaling_thread()->IsCurrent());
362 SignalConnecting(this);
365 void Transport::DestroyAllChannels() {
366 ASSERT(signaling_thread()->IsCurrent());
367 worker_thread_->Invoke<void>(
368 Bind(&Transport::DestroyAllChannels_w, this));
369 worker_thread()->Clear(this);
370 signaling_thread()->Clear(this);
374 void Transport::DestroyAllChannels_w() {
375 ASSERT(worker_thread()->IsCurrent());
376 std::vector<TransportChannelImpl*> impls;
378 rtc::CritScope cs(&crit_);
379 for (ChannelMap::iterator iter = channels_.begin();
380 iter != channels_.end();
382 iter->second.DecRef();
383 if (!iter->second.ref())
384 impls.push_back(iter->second.get());
390 for (size_t i = 0; i < impls.size(); ++i)
391 DestroyTransportChannel(impls[i]);
394 void Transport::ResetChannels() {
395 ASSERT(signaling_thread()->IsCurrent());
396 worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this));
399 void Transport::ResetChannels_w() {
400 ASSERT(worker_thread()->IsCurrent());
402 // We are no longer attempting to connect
403 connect_requested_ = false;
405 // Clear out the old messages, they aren't relevant
406 rtc::CritScope cs(&crit_);
407 ready_candidates_.clear();
409 // Reset all of the channels
410 CallChannels_w(&TransportChannelImpl::Reset);
413 void Transport::OnSignalingReady() {
414 ASSERT(signaling_thread()->IsCurrent());
415 if (destroyed_) return;
417 worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
419 // Notify the subclass.
420 OnTransportSignalingReady();
423 void Transport::CallChannels_w(TransportChannelFunc func) {
424 ASSERT(worker_thread()->IsCurrent());
425 rtc::CritScope cs(&crit_);
426 for (ChannelMap::iterator iter = channels_.begin();
427 iter != channels_.end();
429 ((iter->second.get())->*func)();
433 bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) {
435 if (cand.address().IsNil() || cand.address().IsAny()) {
436 *error = "candidate has address of zero";
440 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
441 int port = cand.address().port();
442 if (cand.protocol() == TCP_PROTOCOL_NAME &&
443 (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) {
444 // Expected for active-only candidates per
445 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
446 // Libjingle clients emit port 0, in "active" mode.
450 if ((port != 80) && (port != 443)) {
451 *error = "candidate has port below 1024, but not 80 or 443";
455 if (cand.address().IsPrivateIP()) {
456 *error = "candidate has port of 80 or 443 with private IP address";
465 bool Transport::GetStats(TransportStats* stats) {
466 ASSERT(signaling_thread()->IsCurrent());
467 return worker_thread_->Invoke<bool>(Bind(
468 &Transport::GetStats_w, this, stats));
471 bool Transport::GetStats_w(TransportStats* stats) {
472 ASSERT(worker_thread()->IsCurrent());
473 stats->content_name = content_name();
474 stats->channel_stats.clear();
475 for (ChannelMap::iterator iter = channels_.begin();
476 iter != channels_.end();
478 TransportChannelStats substats;
479 substats.component = iter->second->component();
480 if (!iter->second->GetStats(&substats.connection_infos)) {
483 stats->channel_stats.push_back(substats);
488 bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const {
489 return worker_thread_->Invoke<bool>(Bind(
490 &Transport::GetSslRole_w, this, ssl_role));
493 void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) {
494 for (std::vector<Candidate>::const_iterator iter = candidates.begin();
495 iter != candidates.end();
497 OnRemoteCandidate(*iter);
501 void Transport::OnRemoteCandidate(const Candidate& candidate) {
502 ASSERT(signaling_thread()->IsCurrent());
503 if (destroyed_) return;
505 if (!HasChannel(candidate.component())) {
506 LOG(LS_WARNING) << "Ignoring candidate for unknown component "
507 << candidate.component();
511 ChannelParams* params = new ChannelParams(new Candidate(candidate));
512 worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params);
515 void Transport::OnRemoteCandidate_w(const Candidate& candidate) {
516 ASSERT(worker_thread()->IsCurrent());
517 ChannelMap::iterator iter = channels_.find(candidate.component());
518 // It's ok for a channel to go away while this message is in transit.
519 if (iter != channels_.end()) {
520 iter->second->OnCandidate(candidate);
524 void Transport::OnChannelReadableState(TransportChannel* channel) {
525 ASSERT(worker_thread()->IsCurrent());
526 signaling_thread()->Post(this, MSG_READSTATE, NULL);
529 void Transport::OnChannelReadableState_s() {
530 ASSERT(signaling_thread()->IsCurrent());
531 TransportState readable = GetTransportState_s(true);
532 if (readable_ != readable) {
533 readable_ = readable;
534 SignalReadableState(this);
538 void Transport::OnChannelWritableState(TransportChannel* channel) {
539 ASSERT(worker_thread()->IsCurrent());
540 signaling_thread()->Post(this, MSG_WRITESTATE, NULL);
545 void Transport::OnChannelWritableState_s() {
546 ASSERT(signaling_thread()->IsCurrent());
547 TransportState writable = GetTransportState_s(false);
548 if (writable_ != writable) {
549 was_writable_ = (writable_ == TRANSPORT_STATE_ALL);
550 writable_ = writable;
551 SignalWritableState(this);
555 TransportState Transport::GetTransportState_s(bool read) {
556 ASSERT(signaling_thread()->IsCurrent());
557 rtc::CritScope cs(&crit_);
559 bool all = !channels_.empty();
560 for (ChannelMap::iterator iter = channels_.begin();
561 iter != channels_.end();
563 bool b = (read ? iter->second->readable() :
564 iter->second->writable());
569 return TRANSPORT_STATE_ALL;
571 return TRANSPORT_STATE_SOME;
573 return TRANSPORT_STATE_NONE;
577 void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) {
578 ASSERT(worker_thread()->IsCurrent());
579 ChannelParams* params = new ChannelParams(channel->component());
580 signaling_thread()->Post(this, MSG_REQUESTSIGNALING, params);
583 void Transport::OnChannelRequestSignaling_s(int component) {
584 ASSERT(signaling_thread()->IsCurrent());
585 LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates";
586 // Resetting ICE state for the channel.
588 rtc::CritScope cs(&crit_);
589 ChannelMap::iterator iter = channels_.find(component);
590 if (iter != channels_.end())
591 iter->second.set_candidates_allocated(false);
593 SignalRequestSignaling(this);
596 void Transport::OnChannelCandidateReady(TransportChannelImpl* channel,
597 const Candidate& candidate) {
598 ASSERT(worker_thread()->IsCurrent());
599 rtc::CritScope cs(&crit_);
600 ready_candidates_.push_back(candidate);
602 // We hold any messages until the client lets us connect.
603 if (connect_requested_) {
604 signaling_thread()->Post(
605 this, MSG_CANDIDATEREADY, NULL);
609 void Transport::OnChannelCandidateReady_s() {
610 ASSERT(signaling_thread()->IsCurrent());
611 ASSERT(connect_requested_);
613 std::vector<Candidate> candidates;
615 rtc::CritScope cs(&crit_);
616 candidates.swap(ready_candidates_);
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);
626 void Transport::OnChannelRouteChange(TransportChannel* channel,
627 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);
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);
640 void Transport::OnChannelCandidatesAllocationDone(
641 TransportChannelImpl* channel) {
642 ASSERT(worker_thread()->IsCurrent());
643 rtc::CritScope cs(&crit_);
644 ChannelMap::iterator iter = channels_.find(channel->component());
645 ASSERT(iter != channels_.end());
646 LOG(LS_INFO) << "Transport: " << content_name_ << ", component "
647 << channel->component() << " allocation complete";
648 iter->second.set_candidates_allocated(true);
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 (iter = channels_.begin(); iter != channels_.end(); ++iter) {
654 if (!iter->second.candidates_allocated())
657 signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE);
662 void Transport::OnChannelCandidatesAllocationDone_s() {
663 ASSERT(signaling_thread()->IsCurrent());
664 LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
665 SignalCandidatesAllocationDone(this);
668 void Transport::OnRoleConflict(TransportChannelImpl* channel) {
669 signaling_thread_->Post(this, MSG_ROLECONFLICT);
672 void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
673 ASSERT(worker_thread()->IsCurrent());
676 // Check if the state is now Failed.
677 // Failed is only available in the Controlling ICE role.
678 if (channel->GetIceRole() != ICEROLE_CONTROLLING) {
682 ChannelMap::iterator iter = channels_.find(channel->component());
683 ASSERT(iter != channels_.end());
684 // Failed can only occur after candidate allocation has stopped.
685 if (!iter->second.candidates_allocated()) {
689 size_t connections = channel->GetConnectionCount();
690 if (connections == 0) {
691 // A Transport has failed if any of its channels have no remaining
693 signaling_thread_->Post(this, MSG_FAILED);
697 void Transport::MaybeCompleted_w() {
698 ASSERT(worker_thread()->IsCurrent());
700 // A Transport's ICE process is completed if all of its channels are writable,
701 // have finished allocating candidates, and have pruned all but one of their
703 ChannelMap::const_iterator iter;
704 for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
705 const TransportChannelImpl* channel = iter->second.get();
706 if (!(channel->writable() &&
707 channel->GetConnectionCount() == 1 &&
708 channel->GetIceRole() == ICEROLE_CONTROLLING &&
709 iter->second.candidates_allocated())) {
714 signaling_thread_->Post(this, MSG_COMPLETED);
717 void Transport::SetIceRole_w(IceRole role) {
718 rtc::CritScope cs(&crit_);
720 for (ChannelMap::iterator iter = channels_.begin();
721 iter != channels_.end(); ++iter) {
722 iter->second->SetIceRole(ice_role_);
726 void Transport::SetRemoteIceMode_w(IceMode mode) {
727 rtc::CritScope cs(&crit_);
728 remote_ice_mode_ = mode;
729 // Shouldn't channels be created after this method executed?
730 for (ChannelMap::iterator iter = channels_.begin();
731 iter != channels_.end(); ++iter) {
732 iter->second->SetRemoteIceMode(remote_ice_mode_);
736 bool Transport::SetLocalTransportDescription_w(
737 const TransportDescription& desc,
738 ContentAction action,
739 std::string* error_desc) {
741 rtc::CritScope cs(&crit_);
743 if (!VerifyIceParams(desc)) {
744 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
748 if (local_description_ && IceCredentialsChanged(*local_description_, desc)) {
749 IceRole new_ice_role = (action == CA_OFFER) ? ICEROLE_CONTROLLING
750 : ICEROLE_CONTROLLED;
752 // It must be called before ApplyLocalTransportDescription_w, which may
753 // trigger an ICE restart and depends on the new ICE role.
754 SetIceRole_w(new_ice_role);
757 local_description_.reset(new TransportDescription(desc));
759 for (ChannelMap::iterator iter = channels_.begin();
760 iter != channels_.end(); ++iter) {
761 ret &= ApplyLocalTransportDescription_w(iter->second.get(), error_desc);
766 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
767 if (action == CA_PRANSWER || action == CA_ANSWER) {
768 ret &= NegotiateTransportDescription_w(action, error_desc);
773 bool Transport::SetRemoteTransportDescription_w(
774 const TransportDescription& desc,
775 ContentAction action,
776 std::string* error_desc) {
778 rtc::CritScope cs(&crit_);
780 if (!VerifyIceParams(desc)) {
781 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
785 remote_description_.reset(new TransportDescription(desc));
786 for (ChannelMap::iterator iter = channels_.begin();
787 iter != channels_.end(); ++iter) {
788 ret &= ApplyRemoteTransportDescription_w(iter->second.get(), error_desc);
791 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
792 if (action == CA_PRANSWER || action == CA_ANSWER) {
793 ret = NegotiateTransportDescription_w(CA_OFFER, error_desc);
798 bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch,
799 std::string* error_desc) {
800 // If existing protocol_type is HYBRID, we may have not chosen the final
801 // protocol type, so update the channel protocol type from the
802 // local description. Otherwise, skip updating the protocol type.
803 // We check for HYBRID to avoid accidental changes; in the case of a
804 // session renegotiation, the new offer will have the google-ice ICE option,
805 // so we need to make sure we don't switch back from ICE mode to HYBRID
806 // when this happens.
807 // There are some other ways we could have solved this, but this is the
808 // simplest. The ultimate solution will be to get rid of GICE altogether.
809 IceProtocolType protocol_type;
810 if (ch->GetIceProtocolType(&protocol_type) &&
811 protocol_type == ICEPROTO_HYBRID) {
812 ch->SetIceProtocolType(
813 TransportProtocolFromDescription(local_description()));
815 ch->SetIceCredentials(local_description_->ice_ufrag,
816 local_description_->ice_pwd);
820 bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
821 std::string* error_desc) {
822 ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
823 remote_description_->ice_pwd);
827 bool Transport::ApplyNegotiatedTransportDescription_w(
828 TransportChannelImpl* channel, std::string* error_desc) {
829 channel->SetIceProtocolType(protocol_);
830 channel->SetRemoteIceMode(remote_ice_mode_);
834 bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
835 std::string* error_desc) {
836 // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
838 const TransportDescription* offer;
839 const TransportDescription* answer;
841 if (local_role == CA_OFFER) {
842 offer = local_description_.get();
843 answer = remote_description_.get();
845 offer = remote_description_.get();
846 answer = local_description_.get();
849 TransportProtocol offer_proto = TransportProtocolFromDescription(offer);
850 TransportProtocol answer_proto = TransportProtocolFromDescription(answer);
852 // If offered protocol is gice/ice, then we expect to receive matching
853 // protocol in answer, anything else is treated as an error.
854 // HYBRID is not an option when offered specific protocol.
855 // If offered protocol is HYBRID and answered protocol is HYBRID then
856 // gice is preferred protocol.
857 // TODO(mallinath) - Answer from local or remote should't have both ice
858 // and gice support. It should always pick which protocol it wants to use.
859 // Once WebRTC stops supporting gice (for backward compatibility), HYBRID in
860 // answer must be treated as error.
861 if ((offer_proto == ICEPROTO_GOOGLE || offer_proto == ICEPROTO_RFC5245) &&
862 (offer_proto != answer_proto)) {
863 std::ostringstream desc;
864 desc << "Offer and answer protocol mismatch: "
865 << IceProtoToString(offer_proto)
867 << IceProtoToString(answer_proto);
868 return BadTransportDescription(desc.str(), error_desc);
870 protocol_ = answer_proto == ICEPROTO_HYBRID ? ICEPROTO_GOOGLE : answer_proto;
872 // If transport is in ICEROLE_CONTROLLED and remote end point supports only
873 // ice_lite, this local end point should take CONTROLLING role.
874 if (ice_role_ == ICEROLE_CONTROLLED &&
875 remote_description_->ice_mode == ICEMODE_LITE) {
876 SetIceRole_w(ICEROLE_CONTROLLING);
879 // Update remote ice_mode to all existing channels.
880 remote_ice_mode_ = remote_description_->ice_mode;
882 // Now that we have negotiated everything, push it downward.
883 // Note that we cache the result so that if we have race conditions
884 // between future SetRemote/SetLocal invocations and new channel
885 // creation, we have the negotiation state saved until a new
886 // negotiation happens.
887 for (ChannelMap::iterator iter = channels_.begin();
888 iter != channels_.end();
890 if (!ApplyNegotiatedTransportDescription_w(iter->second.get(), error_desc))
896 void Transport::OnMessage(rtc::Message* msg) {
897 switch (msg->message_id) {
898 case MSG_ONSIGNALINGREADY:
899 CallChannels_w(&TransportChannelImpl::OnSignalingReady);
901 case MSG_ONREMOTECANDIDATE: {
902 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
903 OnRemoteCandidate_w(*params->candidate);
911 OnChannelReadableState_s();
914 OnChannelWritableState_s();
916 case MSG_REQUESTSIGNALING: {
917 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
918 OnChannelRequestSignaling_s(params->component);
922 case MSG_CANDIDATEREADY:
923 OnChannelCandidateReady_s();
925 case MSG_ROUTECHANGE: {
926 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
927 OnChannelRouteChange_s(params->channel, *params->candidate);
931 case MSG_CANDIDATEALLOCATIONCOMPLETE:
932 OnChannelCandidatesAllocationDone_s();
934 case MSG_ROLECONFLICT:
935 SignalRoleConflict();
938 SignalCompleted(this);
946 bool TransportParser::ParseAddress(const buzz::XmlElement* elem,
947 const buzz::QName& address_name,
948 const buzz::QName& port_name,
949 rtc::SocketAddress* address,
951 if (!elem->HasAttr(address_name))
952 return BadParse("address does not have " + address_name.LocalPart(), error);
953 if (!elem->HasAttr(port_name))
954 return BadParse("address does not have " + port_name.LocalPart(), error);
956 address->SetIP(elem->Attr(address_name));
957 std::istringstream ist(elem->Attr(port_name));
960 address->SetPort(port);
965 // We're GICE if the namespace is NS_GOOGLE_P2P, or if NS_JINGLE_ICE_UDP is
966 // used and the GICE ice-option is set.
967 TransportProtocol TransportProtocolFromDescription(
968 const TransportDescription* desc) {
969 ASSERT(desc != NULL);
970 if (desc->transport_type == NS_JINGLE_ICE_UDP) {
971 return (desc->HasOption(ICE_OPTION_GICE)) ?
972 ICEPROTO_HYBRID : ICEPROTO_RFC5245;
974 return ICEPROTO_GOOGLE;
977 } // namespace cricket