3 * Copyright 2004--2005, 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/base/bind.h"
31 #include "talk/base/common.h"
32 #include "talk/base/logging.h"
33 #include "talk/p2p/base/candidate.h"
34 #include "talk/p2p/base/constants.h"
35 #include "talk/p2p/base/sessionmanager.h"
36 #include "talk/p2p/base/parsing.h"
37 #include "talk/p2p/base/transportchannelimpl.h"
38 #include "talk/xmllite/xmlelement.h"
39 #include "talk/xmpp/constants.h"
43 using talk_base::Bind;
46 MSG_ONSIGNALINGREADY = 1,
47 MSG_ONREMOTECANDIDATE,
54 MSG_CANDIDATEALLOCATIONCOMPLETE,
60 struct ChannelParams : public talk_base::MessageData {
61 ChannelParams() : channel(NULL), candidate(NULL) {}
62 explicit ChannelParams(int component)
63 : component(component), channel(NULL), candidate(NULL) {}
64 explicit ChannelParams(Candidate* candidate)
65 : channel(NULL), candidate(candidate) {
74 TransportChannelImpl* channel;
78 static std::string IceProtoToString(TransportProtocol proto) {
79 std::string proto_str;
87 case ICEPROTO_RFC5245:
97 bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
101 LOG(LS_ERROR) << desc;
105 Transport::Transport(talk_base::Thread* signaling_thread,
106 talk_base::Thread* worker_thread,
107 const std::string& content_name,
108 const std::string& type,
109 PortAllocator* allocator)
110 : signaling_thread_(signaling_thread),
111 worker_thread_(worker_thread),
112 content_name_(content_name),
114 allocator_(allocator),
116 readable_(TRANSPORT_STATE_NONE),
117 writable_(TRANSPORT_STATE_NONE),
118 was_writable_(false),
119 connect_requested_(false),
120 ice_role_(ICEROLE_UNKNOWN),
122 protocol_(ICEPROTO_HYBRID),
123 remote_ice_mode_(ICEMODE_FULL) {
126 Transport::~Transport() {
127 ASSERT(signaling_thread_->IsCurrent());
131 void Transport::SetIceRole(IceRole role) {
132 worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
135 void Transport::SetIdentity(talk_base::SSLIdentity* identity) {
136 worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity));
139 bool Transport::GetIdentity(talk_base::SSLIdentity** identity) {
140 // The identity is set on the worker thread, so for safety it must also be
141 // acquired on the worker thread.
142 return worker_thread_->Invoke<bool>(
143 Bind(&Transport::GetIdentity_w, this, identity));
146 bool Transport::GetRemoteCertificate(talk_base::SSLCertificate** cert) {
147 // Channels can be deleted on the worker thread, so for safety the remote
148 // certificate is acquired on the worker thread.
149 return worker_thread_->Invoke<bool>(
150 Bind(&Transport::GetRemoteCertificate_w, this, cert));
153 bool Transport::GetRemoteCertificate_w(talk_base::SSLCertificate** cert) {
154 ASSERT(worker_thread()->IsCurrent());
155 if (channels_.empty())
158 ChannelMap::iterator iter = channels_.begin();
159 return iter->second->GetRemoteCertificate(cert);
162 bool Transport::SetLocalTransportDescription(
163 const TransportDescription& description,
164 ContentAction action,
165 std::string* error_desc) {
166 return worker_thread_->Invoke<bool>(Bind(
167 &Transport::SetLocalTransportDescription_w, this,
168 description, action, error_desc));
171 bool Transport::SetRemoteTransportDescription(
172 const TransportDescription& description,
173 ContentAction action,
174 std::string* error_desc) {
175 return worker_thread_->Invoke<bool>(Bind(
176 &Transport::SetRemoteTransportDescription_w, this,
177 description, action, error_desc));
180 TransportChannelImpl* Transport::CreateChannel(int component) {
181 return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
182 &Transport::CreateChannel_w, this, component));
185 TransportChannelImpl* Transport::CreateChannel_w(int component) {
186 ASSERT(worker_thread()->IsCurrent());
187 TransportChannelImpl *impl;
188 talk_base::CritScope cs(&crit_);
190 // Create the entry if it does not exist.
191 bool impl_exists = false;
192 if (channels_.find(component) == channels_.end()) {
193 impl = CreateTransportChannel(component);
194 channels_[component] = ChannelMapEntry(impl);
196 impl = channels_[component].get();
200 // Increase the ref count.
201 channels_[component].AddRef();
205 // If this is an existing channel, we should just return it without
206 // connecting to all the signal again.
210 // Push down our transport state to the new channel.
211 impl->SetIceRole(ice_role_);
212 impl->SetIceTiebreaker(tiebreaker_);
213 // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
214 // below Apply**Description_w calls can fail.
215 if (local_description_)
216 ApplyLocalTransportDescription_w(impl, NULL);
217 if (remote_description_)
218 ApplyRemoteTransportDescription_w(impl, NULL);
219 if (local_description_ && remote_description_)
220 ApplyNegotiatedTransportDescription_w(impl, NULL);
222 impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
223 impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
224 impl->SignalRequestSignaling.connect(
225 this, &Transport::OnChannelRequestSignaling);
226 impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady);
227 impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange);
228 impl->SignalCandidatesAllocationDone.connect(
229 this, &Transport::OnChannelCandidatesAllocationDone);
230 impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
231 impl->SignalConnectionRemoved.connect(
232 this, &Transport::OnChannelConnectionRemoved);
234 if (connect_requested_) {
236 if (channels_.size() == 1) {
237 // If this is the first channel, then indicate that we have started
239 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
245 TransportChannelImpl* Transport::GetChannel(int component) {
246 talk_base::CritScope cs(&crit_);
247 ChannelMap::iterator iter = channels_.find(component);
248 return (iter != channels_.end()) ? iter->second.get() : NULL;
251 bool Transport::HasChannels() {
252 talk_base::CritScope cs(&crit_);
253 return !channels_.empty();
256 void Transport::DestroyChannel(int component) {
257 worker_thread_->Invoke<void>(Bind(
258 &Transport::DestroyChannel_w, this, component));
261 void Transport::DestroyChannel_w(int component) {
262 ASSERT(worker_thread()->IsCurrent());
264 TransportChannelImpl* impl = NULL;
266 talk_base::CritScope cs(&crit_);
267 ChannelMap::iterator iter = channels_.find(component);
268 if (iter == channels_.end())
271 iter->second.DecRef();
272 if (!iter->second.ref()) {
273 impl = iter->second.get();
274 channels_.erase(iter);
278 if (connect_requested_ && channels_.empty()) {
279 // We're no longer attempting to connect.
280 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
284 // Check in case the deleted channel was the only non-writable channel.
285 OnChannelWritableState(impl);
286 DestroyTransportChannel(impl);
290 void Transport::ConnectChannels() {
291 ASSERT(signaling_thread()->IsCurrent());
292 worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
295 void Transport::ConnectChannels_w() {
296 ASSERT(worker_thread()->IsCurrent());
297 if (connect_requested_ || channels_.empty())
299 connect_requested_ = true;
300 signaling_thread()->Post(
301 this, MSG_CANDIDATEREADY, NULL);
303 if (!local_description_) {
304 // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
305 // As Transport must know TD is offer or answer and cricket::Transport
306 // doesn't have the capability to decide it. This should be set by the
308 // Session must generate local TD before remote candidates pushed when
309 // initiate request initiated by the remote.
310 LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has "
311 << "been set. Will generate one.";
312 TransportDescription desc(NS_GINGLE_P2P, std::vector<std::string>(),
313 talk_base::CreateRandomString(ICE_UFRAG_LENGTH),
314 talk_base::CreateRandomString(ICE_PWD_LENGTH),
315 ICEMODE_FULL, CONNECTIONROLE_NONE, NULL,
317 SetLocalTransportDescription_w(desc, CA_OFFER, NULL);
320 CallChannels_w(&TransportChannelImpl::Connect);
321 if (!channels_.empty()) {
322 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
326 void Transport::OnConnecting_s() {
327 ASSERT(signaling_thread()->IsCurrent());
328 SignalConnecting(this);
331 void Transport::DestroyAllChannels() {
332 ASSERT(signaling_thread()->IsCurrent());
333 worker_thread_->Invoke<void>(
334 Bind(&Transport::DestroyAllChannels_w, this));
335 worker_thread()->Clear(this);
336 signaling_thread()->Clear(this);
340 void Transport::DestroyAllChannels_w() {
341 ASSERT(worker_thread()->IsCurrent());
342 std::vector<TransportChannelImpl*> impls;
344 talk_base::CritScope cs(&crit_);
345 for (ChannelMap::iterator iter = channels_.begin();
346 iter != channels_.end();
348 iter->second.DecRef();
349 if (!iter->second.ref())
350 impls.push_back(iter->second.get());
356 for (size_t i = 0; i < impls.size(); ++i)
357 DestroyTransportChannel(impls[i]);
360 void Transport::ResetChannels() {
361 ASSERT(signaling_thread()->IsCurrent());
362 worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this));
365 void Transport::ResetChannels_w() {
366 ASSERT(worker_thread()->IsCurrent());
368 // We are no longer attempting to connect
369 connect_requested_ = false;
371 // Clear out the old messages, they aren't relevant
372 talk_base::CritScope cs(&crit_);
373 ready_candidates_.clear();
375 // Reset all of the channels
376 CallChannels_w(&TransportChannelImpl::Reset);
379 void Transport::OnSignalingReady() {
380 ASSERT(signaling_thread()->IsCurrent());
381 if (destroyed_) return;
383 worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
385 // Notify the subclass.
386 OnTransportSignalingReady();
389 void Transport::CallChannels_w(TransportChannelFunc func) {
390 ASSERT(worker_thread()->IsCurrent());
391 talk_base::CritScope cs(&crit_);
392 for (ChannelMap::iterator iter = channels_.begin();
393 iter != channels_.end();
395 ((iter->second.get())->*func)();
399 bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) {
401 if (cand.address().IsNil() || cand.address().IsAny()) {
402 *error = "candidate has address of zero";
406 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
407 int port = cand.address().port();
409 if ((port != 80) && (port != 443)) {
410 *error = "candidate has port below 1024, but not 80 or 443";
414 if (cand.address().IsPrivateIP()) {
415 *error = "candidate has port of 80 or 443 with private IP address";
424 bool Transport::GetStats(TransportStats* stats) {
425 ASSERT(signaling_thread()->IsCurrent());
426 return worker_thread_->Invoke<bool>(Bind(
427 &Transport::GetStats_w, this, stats));
430 bool Transport::GetStats_w(TransportStats* stats) {
431 ASSERT(worker_thread()->IsCurrent());
432 stats->content_name = content_name();
433 stats->channel_stats.clear();
434 for (ChannelMap::iterator iter = channels_.begin();
435 iter != channels_.end();
437 TransportChannelStats substats;
438 substats.component = iter->second->component();
439 if (!iter->second->GetStats(&substats.connection_infos)) {
442 stats->channel_stats.push_back(substats);
447 bool Transport::GetSslRole(talk_base::SSLRole* ssl_role) const {
448 return worker_thread_->Invoke<bool>(Bind(
449 &Transport::GetSslRole_w, this, ssl_role));
452 void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) {
453 for (std::vector<Candidate>::const_iterator iter = candidates.begin();
454 iter != candidates.end();
456 OnRemoteCandidate(*iter);
460 void Transport::OnRemoteCandidate(const Candidate& candidate) {
461 ASSERT(signaling_thread()->IsCurrent());
462 if (destroyed_) return;
464 if (!HasChannel(candidate.component())) {
465 LOG(LS_WARNING) << "Ignoring candidate for unknown component "
466 << candidate.component();
470 ChannelParams* params = new ChannelParams(new Candidate(candidate));
471 worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params);
474 void Transport::OnRemoteCandidate_w(const Candidate& candidate) {
475 ASSERT(worker_thread()->IsCurrent());
476 ChannelMap::iterator iter = channels_.find(candidate.component());
477 // It's ok for a channel to go away while this message is in transit.
478 if (iter != channels_.end()) {
479 iter->second->OnCandidate(candidate);
483 void Transport::OnChannelReadableState(TransportChannel* channel) {
484 ASSERT(worker_thread()->IsCurrent());
485 signaling_thread()->Post(this, MSG_READSTATE, NULL);
488 void Transport::OnChannelReadableState_s() {
489 ASSERT(signaling_thread()->IsCurrent());
490 TransportState readable = GetTransportState_s(true);
491 if (readable_ != readable) {
492 readable_ = readable;
493 SignalReadableState(this);
497 void Transport::OnChannelWritableState(TransportChannel* channel) {
498 ASSERT(worker_thread()->IsCurrent());
499 signaling_thread()->Post(this, MSG_WRITESTATE, NULL);
502 void Transport::OnChannelWritableState_s() {
503 ASSERT(signaling_thread()->IsCurrent());
504 TransportState writable = GetTransportState_s(false);
505 if (writable_ != writable) {
506 was_writable_ = (writable_ == TRANSPORT_STATE_ALL);
507 writable_ = writable;
508 SignalWritableState(this);
512 TransportState Transport::GetTransportState_s(bool read) {
513 ASSERT(signaling_thread()->IsCurrent());
514 talk_base::CritScope cs(&crit_);
516 bool all = !channels_.empty();
517 for (ChannelMap::iterator iter = channels_.begin();
518 iter != channels_.end();
520 bool b = (read ? iter->second->readable() :
521 iter->second->writable());
526 return TRANSPORT_STATE_ALL;
528 return TRANSPORT_STATE_SOME;
530 return TRANSPORT_STATE_NONE;
534 void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) {
535 ASSERT(worker_thread()->IsCurrent());
536 ChannelParams* params = new ChannelParams(channel->component());
537 signaling_thread()->Post(this, MSG_REQUESTSIGNALING, params);
540 void Transport::OnChannelRequestSignaling_s(int component) {
541 ASSERT(signaling_thread()->IsCurrent());
542 LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates";
543 // Resetting ICE state for the channel.
545 talk_base::CritScope cs(&crit_);
546 ChannelMap::iterator iter = channels_.find(component);
547 if (iter != channels_.end())
548 iter->second.set_candidates_allocated(false);
550 SignalRequestSignaling(this);
553 void Transport::OnChannelCandidateReady(TransportChannelImpl* channel,
554 const Candidate& candidate) {
555 ASSERT(worker_thread()->IsCurrent());
556 talk_base::CritScope cs(&crit_);
557 ready_candidates_.push_back(candidate);
559 // We hold any messages until the client lets us connect.
560 if (connect_requested_) {
561 signaling_thread()->Post(
562 this, MSG_CANDIDATEREADY, NULL);
566 void Transport::OnChannelCandidateReady_s() {
567 ASSERT(signaling_thread()->IsCurrent());
568 ASSERT(connect_requested_);
570 std::vector<Candidate> candidates;
572 talk_base::CritScope cs(&crit_);
573 candidates.swap(ready_candidates_);
576 // we do the deleting of Candidate* here to keep the new above and
577 // delete below close to each other
578 if (!candidates.empty()) {
579 SignalCandidatesReady(this, candidates);
583 void Transport::OnChannelRouteChange(TransportChannel* channel,
584 const Candidate& remote_candidate) {
585 ASSERT(worker_thread()->IsCurrent());
586 ChannelParams* params = new ChannelParams(new Candidate(remote_candidate));
587 params->channel = static_cast<cricket::TransportChannelImpl*>(channel);
588 signaling_thread()->Post(this, MSG_ROUTECHANGE, params);
591 void Transport::OnChannelRouteChange_s(const TransportChannel* channel,
592 const Candidate& remote_candidate) {
593 ASSERT(signaling_thread()->IsCurrent());
594 SignalRouteChange(this, remote_candidate.component(), remote_candidate);
597 void Transport::OnChannelCandidatesAllocationDone(
598 TransportChannelImpl* channel) {
599 ASSERT(worker_thread()->IsCurrent());
600 talk_base::CritScope cs(&crit_);
601 ChannelMap::iterator iter = channels_.find(channel->component());
602 ASSERT(iter != channels_.end());
603 LOG(LS_INFO) << "Transport: " << content_name_ << ", component "
604 << channel->component() << " allocation complete";
605 iter->second.set_candidates_allocated(true);
607 // If all channels belonging to this Transport got signal, then
608 // forward this signal to upper layer.
609 // Can this signal arrive before all transport channels are created?
610 for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
611 if (!iter->second.candidates_allocated())
614 signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE);
617 void Transport::OnChannelCandidatesAllocationDone_s() {
618 ASSERT(signaling_thread()->IsCurrent());
619 LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
620 SignalCandidatesAllocationDone(this);
623 void Transport::OnRoleConflict(TransportChannelImpl* channel) {
624 signaling_thread_->Post(this, MSG_ROLECONFLICT);
627 void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
628 ASSERT(worker_thread()->IsCurrent());
629 // Determine if the Transport should move to Completed or Failed. These
630 // states are only available in the Controlling ICE role.
631 if (channel->GetIceRole() != ICEROLE_CONTROLLING) {
635 ChannelMap::iterator iter = channels_.find(channel->component());
636 ASSERT(iter != channels_.end());
637 // Completed and Failed can only occur after candidate allocation has stopped.
638 if (!iter->second.candidates_allocated()) {
642 size_t connections = channel->GetConnectionCount();
643 if (connections == 0) {
644 // A Transport has failed if any of its channels have no remaining
646 signaling_thread_->Post(this, MSG_FAILED);
647 } else if (connections == 1 && completed()) {
648 signaling_thread_->Post(this, MSG_COMPLETED);
652 bool Transport::completed() const {
653 // A Transport's ICE process is completed if all of its channels are writable,
654 // have finished allocating candidates, and have pruned all but one of their
656 if (!all_channels_writable())
659 ChannelMap::const_iterator iter;
660 for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
661 const TransportChannelImpl* channel = iter->second.get();
662 if (!(channel->GetConnectionCount() == 1 &&
663 channel->GetIceRole() == ICEROLE_CONTROLLING &&
664 iter->second.candidates_allocated())) {
671 void Transport::SetIceRole_w(IceRole role) {
672 talk_base::CritScope cs(&crit_);
674 for (ChannelMap::iterator iter = channels_.begin();
675 iter != channels_.end(); ++iter) {
676 iter->second->SetIceRole(ice_role_);
680 void Transport::SetRemoteIceMode_w(IceMode mode) {
681 talk_base::CritScope cs(&crit_);
682 remote_ice_mode_ = mode;
683 // Shouldn't channels be created after this method executed?
684 for (ChannelMap::iterator iter = channels_.begin();
685 iter != channels_.end(); ++iter) {
686 iter->second->SetRemoteIceMode(remote_ice_mode_);
690 bool Transport::SetLocalTransportDescription_w(
691 const TransportDescription& desc,
692 ContentAction action,
693 std::string* error_desc) {
695 talk_base::CritScope cs(&crit_);
696 local_description_.reset(new TransportDescription(desc));
698 for (ChannelMap::iterator iter = channels_.begin();
699 iter != channels_.end(); ++iter) {
700 ret &= ApplyLocalTransportDescription_w(iter->second.get(), error_desc);
705 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
706 if (action == CA_PRANSWER || action == CA_ANSWER) {
707 ret &= NegotiateTransportDescription_w(action, error_desc);
712 bool Transport::SetRemoteTransportDescription_w(
713 const TransportDescription& desc,
714 ContentAction action,
715 std::string* error_desc) {
717 talk_base::CritScope cs(&crit_);
718 remote_description_.reset(new TransportDescription(desc));
720 for (ChannelMap::iterator iter = channels_.begin();
721 iter != channels_.end(); ++iter) {
722 ret &= ApplyRemoteTransportDescription_w(iter->second.get(), error_desc);
725 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
726 if (action == CA_PRANSWER || action == CA_ANSWER) {
727 ret = NegotiateTransportDescription_w(CA_OFFER, error_desc);
732 bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch,
733 std::string* error_desc) {
734 // If existing protocol_type is HYBRID, we may have not chosen the final
735 // protocol type, so update the channel protocol type from the
736 // local description. Otherwise, skip updating the protocol type.
737 // We check for HYBRID to avoid accidental changes; in the case of a
738 // session renegotiation, the new offer will have the google-ice ICE option,
739 // so we need to make sure we don't switch back from ICE mode to HYBRID
740 // when this happens.
741 // There are some other ways we could have solved this, but this is the
742 // simplest. The ultimate solution will be to get rid of GICE altogether.
743 IceProtocolType protocol_type;
744 if (ch->GetIceProtocolType(&protocol_type) &&
745 protocol_type == ICEPROTO_HYBRID) {
746 ch->SetIceProtocolType(
747 TransportProtocolFromDescription(local_description()));
749 ch->SetIceCredentials(local_description_->ice_ufrag,
750 local_description_->ice_pwd);
754 bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
755 std::string* error_desc) {
756 ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
757 remote_description_->ice_pwd);
761 bool Transport::ApplyNegotiatedTransportDescription_w(
762 TransportChannelImpl* channel, std::string* error_desc) {
763 channel->SetIceProtocolType(protocol_);
764 channel->SetRemoteIceMode(remote_ice_mode_);
768 bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
769 std::string* error_desc) {
770 // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
772 const TransportDescription* offer;
773 const TransportDescription* answer;
775 if (local_role == CA_OFFER) {
776 offer = local_description_.get();
777 answer = remote_description_.get();
779 offer = remote_description_.get();
780 answer = local_description_.get();
783 TransportProtocol offer_proto = TransportProtocolFromDescription(offer);
784 TransportProtocol answer_proto = TransportProtocolFromDescription(answer);
786 // If offered protocol is gice/ice, then we expect to receive matching
787 // protocol in answer, anything else is treated as an error.
788 // HYBRID is not an option when offered specific protocol.
789 // If offered protocol is HYBRID and answered protocol is HYBRID then
790 // gice is preferred protocol.
791 // TODO(mallinath) - Answer from local or remote should't have both ice
792 // and gice support. It should always pick which protocol it wants to use.
793 // Once WebRTC stops supporting gice (for backward compatibility), HYBRID in
794 // answer must be treated as error.
795 if ((offer_proto == ICEPROTO_GOOGLE || offer_proto == ICEPROTO_RFC5245) &&
796 (offer_proto != answer_proto)) {
797 std::ostringstream desc;
798 desc << "Offer and answer protocol mismatch: "
799 << IceProtoToString(offer_proto)
801 << IceProtoToString(answer_proto);
802 return BadTransportDescription(desc.str(), error_desc);
804 protocol_ = answer_proto == ICEPROTO_HYBRID ? ICEPROTO_GOOGLE : answer_proto;
806 // If transport is in ICEROLE_CONTROLLED and remote end point supports only
807 // ice_lite, this local end point should take CONTROLLING role.
808 if (ice_role_ == ICEROLE_CONTROLLED &&
809 remote_description_->ice_mode == ICEMODE_LITE) {
810 SetIceRole_w(ICEROLE_CONTROLLING);
813 // Update remote ice_mode to all existing channels.
814 remote_ice_mode_ = remote_description_->ice_mode;
816 // Now that we have negotiated everything, push it downward.
817 // Note that we cache the result so that if we have race conditions
818 // between future SetRemote/SetLocal invocations and new channel
819 // creation, we have the negotiation state saved until a new
820 // negotiation happens.
821 for (ChannelMap::iterator iter = channels_.begin();
822 iter != channels_.end();
824 if (!ApplyNegotiatedTransportDescription_w(iter->second.get(), error_desc))
830 void Transport::OnMessage(talk_base::Message* msg) {
831 switch (msg->message_id) {
832 case MSG_ONSIGNALINGREADY:
833 CallChannels_w(&TransportChannelImpl::OnSignalingReady);
835 case MSG_ONREMOTECANDIDATE: {
836 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
837 OnRemoteCandidate_w(*params->candidate);
845 OnChannelReadableState_s();
848 OnChannelWritableState_s();
850 case MSG_REQUESTSIGNALING: {
851 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
852 OnChannelRequestSignaling_s(params->component);
856 case MSG_CANDIDATEREADY:
857 OnChannelCandidateReady_s();
859 case MSG_ROUTECHANGE: {
860 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
861 OnChannelRouteChange_s(params->channel, *params->candidate);
865 case MSG_CANDIDATEALLOCATIONCOMPLETE:
866 OnChannelCandidatesAllocationDone_s();
868 case MSG_ROLECONFLICT:
869 SignalRoleConflict();
872 SignalCompleted(this);
880 bool TransportParser::ParseAddress(const buzz::XmlElement* elem,
881 const buzz::QName& address_name,
882 const buzz::QName& port_name,
883 talk_base::SocketAddress* address,
885 if (!elem->HasAttr(address_name))
886 return BadParse("address does not have " + address_name.LocalPart(), error);
887 if (!elem->HasAttr(port_name))
888 return BadParse("address does not have " + port_name.LocalPart(), error);
890 address->SetIP(elem->Attr(address_name));
891 std::istringstream ist(elem->Attr(port_name));
894 address->SetPort(port);
899 // We're GICE if the namespace is NS_GOOGLE_P2P, or if NS_JINGLE_ICE_UDP is
900 // used and the GICE ice-option is set.
901 TransportProtocol TransportProtocolFromDescription(
902 const TransportDescription* desc) {
903 ASSERT(desc != NULL);
904 if (desc->transport_type == NS_JINGLE_ICE_UDP) {
905 return (desc->HasOption(ICE_OPTION_GICE)) ?
906 ICEPROTO_HYBRID : ICEPROTO_RFC5245;
908 return ICEPROTO_GOOGLE;
911 } // namespace cricket