Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/talk/p2p/base/transport.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 25.5 KB
Line 
1/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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.
15 *
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.
26 */
27
28#include "talk/p2p/base/transport.h"
29
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"
40
41namespace cricket {
42
43using talk_base::Bind;
44
45enum {
46  MSG_ONSIGNALINGREADY = 1,
47  MSG_ONREMOTECANDIDATE,
48  MSG_READSTATE,
49  MSG_WRITESTATE,
50  MSG_REQUESTSIGNALING,
51  MSG_CANDIDATEREADY,
52  MSG_ROUTECHANGE,
53  MSG_CONNECTING,
54  MSG_CANDIDATEALLOCATIONCOMPLETE,
55  MSG_ROLECONFLICT,
56};
57
58struct ChannelParams : public talk_base::MessageData {
59  ChannelParams() : channel(NULL), candidate(NULL) {}
60  explicit ChannelParams(int component)
61      : component(component), channel(NULL), candidate(NULL) {}
62  explicit ChannelParams(Candidate* candidate)
63      : channel(NULL), candidate(candidate) {
64  }
65
66  ~ChannelParams() {
67    delete candidate;
68  }
69
70  std::string name;
71  int component;
72  TransportChannelImpl* channel;
73  Candidate* candidate;
74};
75
76Transport::Transport(talk_base::Thread* signaling_thread,
77                     talk_base::Thread* worker_thread,
78                     const std::string& content_name,
79                     const std::string& type,
80                     PortAllocator* allocator)
81  : signaling_thread_(signaling_thread),
82    worker_thread_(worker_thread),
83    content_name_(content_name),
84    type_(type),
85    allocator_(allocator),
86    destroyed_(false),
87    readable_(TRANSPORT_STATE_NONE),
88    writable_(TRANSPORT_STATE_NONE),
89    was_writable_(false),
90    connect_requested_(false),
91    ice_role_(ICEROLE_UNKNOWN),
92    tiebreaker_(0),
93    protocol_(ICEPROTO_HYBRID),
94    remote_ice_mode_(ICEMODE_FULL) {
95}
96
97Transport::~Transport() {
98  ASSERT(signaling_thread_->IsCurrent());
99  ASSERT(destroyed_);
100}
101
102void Transport::SetIceRole(IceRole role) {
103  worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
104}
105
106void Transport::SetIdentity(talk_base::SSLIdentity* identity) {
107  worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity));
108}
109
110bool Transport::GetIdentity(talk_base::SSLIdentity** identity) {
111  // The identity is set on the worker thread, so for safety it must also be
112  // acquired on the worker thread.
113  return worker_thread_->Invoke<bool>(
114      Bind(&Transport::GetIdentity_w, this, identity));
115}
116
117bool Transport::GetRemoteCertificate(talk_base::SSLCertificate** cert) {
118  // Channels can be deleted on the worker thread, so for safety the remote
119  // certificate is acquired on the worker thread.
120  return worker_thread_->Invoke<bool>(
121      Bind(&Transport::GetRemoteCertificate_w, this, cert));
122}
123
124bool Transport::GetRemoteCertificate_w(talk_base::SSLCertificate** cert) {
125  ASSERT(worker_thread()->IsCurrent());
126  if (channels_.empty())
127    return false;
128
129  ChannelMap::iterator iter = channels_.begin();
130  return iter->second->GetRemoteCertificate(cert);
131}
132
133bool Transport::SetLocalTransportDescription(
134    const TransportDescription& description, ContentAction action) {
135  return worker_thread_->Invoke<bool>(Bind(
136      &Transport::SetLocalTransportDescription_w, this, description, action));
137}
138
139bool Transport::SetRemoteTransportDescription(
140    const TransportDescription& description, ContentAction action) {
141  return worker_thread_->Invoke<bool>(Bind(
142      &Transport::SetRemoteTransportDescription_w, this, description, action));
143}
144
145TransportChannelImpl* Transport::CreateChannel(int component) {
146  return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
147      &Transport::CreateChannel_w, this, component));
148}
149
150TransportChannelImpl* Transport::CreateChannel_w(int component) {
151  ASSERT(worker_thread()->IsCurrent());
152  TransportChannelImpl *impl;
153  talk_base::CritScope cs(&crit_);
154
155  // Create the entry if it does not exist.
156  bool impl_exists = false;
157  if (channels_.find(component) == channels_.end()) {
158    impl = CreateTransportChannel(component);
159    channels_[component] = ChannelMapEntry(impl);
160  } else {
161    impl = channels_[component].get();
162    impl_exists = true;
163  }
164
165  // Increase the ref count.
166  channels_[component].AddRef();
167  destroyed_ = false;
168
169  if (impl_exists) {
170    // If this is an existing channel, we should just return it without
171    // connecting to all the signal again.
172    return impl;
173  }
174
175  // Push down our transport state to the new channel.
176  impl->SetIceRole(ice_role_);
177  impl->SetIceTiebreaker(tiebreaker_);
178  if (local_description_) {
179    ApplyLocalTransportDescription_w(impl);
180    if (remote_description_) {
181      ApplyRemoteTransportDescription_w(impl);
182      ApplyNegotiatedTransportDescription_w(impl);
183    }
184  }
185
186  impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
187  impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
188  impl->SignalRequestSignaling.connect(
189      this, &Transport::OnChannelRequestSignaling);
190  impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady);
191  impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange);
192  impl->SignalCandidatesAllocationDone.connect(
193      this, &Transport::OnChannelCandidatesAllocationDone);
194  impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
195
196  if (connect_requested_) {
197    impl->Connect();
198    if (channels_.size() == 1) {
199      // If this is the first channel, then indicate that we have started
200      // connecting.
201      signaling_thread()->Post(this, MSG_CONNECTING, NULL);
202    }
203  }
204  return impl;
205}
206
207TransportChannelImpl* Transport::GetChannel(int component) {
208  talk_base::CritScope cs(&crit_);
209  ChannelMap::iterator iter = channels_.find(component);
210  return (iter != channels_.end()) ? iter->second.get() : NULL;
211}
212
213bool Transport::HasChannels() {
214  talk_base::CritScope cs(&crit_);
215  return !channels_.empty();
216}
217
218void Transport::DestroyChannel(int component) {
219  worker_thread_->Invoke<void>(Bind(
220      &Transport::DestroyChannel_w, this, component));
221}
222
223void Transport::DestroyChannel_w(int component) {
224  ASSERT(worker_thread()->IsCurrent());
225
226  TransportChannelImpl* impl = NULL;
227  {
228    talk_base::CritScope cs(&crit_);
229    ChannelMap::iterator iter = channels_.find(component);
230    if (iter == channels_.end())
231      return;
232
233    iter->second.DecRef();
234    if (!iter->second.ref()) {
235      impl = iter->second.get();
236      channels_.erase(iter);
237    }
238  }
239
240  if (connect_requested_ && channels_.empty()) {
241    // We're no longer attempting to connect.
242    signaling_thread()->Post(this, MSG_CONNECTING, NULL);
243  }
244
245  if (impl) {
246    // Check in case the deleted channel was the only non-writable channel.
247    OnChannelWritableState(impl);
248    DestroyTransportChannel(impl);
249  }
250}
251
252void Transport::ConnectChannels() {
253  ASSERT(signaling_thread()->IsCurrent());
254  worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
255}
256
257void Transport::ConnectChannels_w() {
258  ASSERT(worker_thread()->IsCurrent());
259  if (connect_requested_ || channels_.empty())
260    return;
261  connect_requested_ = true;
262  signaling_thread()->Post(
263      this, MSG_CANDIDATEREADY, NULL);
264
265  if (!local_description_) {
266    // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
267    // As Transport must know TD is offer or answer and cricket::Transport
268    // doesn't have the capability to decide it. This should be set by the
269    // Session.
270    // Session must generate local TD before remote candidates pushed when
271    // initiate request initiated by the remote.
272    LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has "
273                 << "been set. Will generate one.";
274    TransportDescription desc(NS_GINGLE_P2P, std::vector<std::string>(),
275                              talk_base::CreateRandomString(ICE_UFRAG_LENGTH),
276                              talk_base::CreateRandomString(ICE_PWD_LENGTH),
277                              ICEMODE_FULL, CONNECTIONROLE_NONE, NULL,
278                              Candidates());
279    SetLocalTransportDescription_w(desc, CA_OFFER);
280  }
281
282  CallChannels_w(&TransportChannelImpl::Connect);
283  if (!channels_.empty()) {
284    signaling_thread()->Post(this, MSG_CONNECTING, NULL);
285  }
286}
287
288void Transport::OnConnecting_s() {
289  ASSERT(signaling_thread()->IsCurrent());
290  SignalConnecting(this);
291}
292
293void Transport::DestroyAllChannels() {
294  ASSERT(signaling_thread()->IsCurrent());
295  worker_thread_->Invoke<void>(
296      Bind(&Transport::DestroyAllChannels_w, this));
297  worker_thread()->Clear(this);
298  signaling_thread()->Clear(this);
299  destroyed_ = true;
300}
301
302void Transport::DestroyAllChannels_w() {
303  ASSERT(worker_thread()->IsCurrent());
304  std::vector<TransportChannelImpl*> impls;
305  {
306    talk_base::CritScope cs(&crit_);
307    for (ChannelMap::iterator iter = channels_.begin();
308         iter != channels_.end();
309         ++iter) {
310      iter->second.DecRef();
311      if (!iter->second.ref())
312        impls.push_back(iter->second.get());
313      }
314    }
315  channels_.clear();
316
317
318  for (size_t i = 0; i < impls.size(); ++i)
319    DestroyTransportChannel(impls[i]);
320}
321
322void Transport::ResetChannels() {
323  ASSERT(signaling_thread()->IsCurrent());
324  worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this));
325}
326
327void Transport::ResetChannels_w() {
328  ASSERT(worker_thread()->IsCurrent());
329
330  // We are no longer attempting to connect
331  connect_requested_ = false;
332
333  // Clear out the old messages, they aren't relevant
334  talk_base::CritScope cs(&crit_);
335  ready_candidates_.clear();
336
337  // Reset all of the channels
338  CallChannels_w(&TransportChannelImpl::Reset);
339}
340
341void Transport::OnSignalingReady() {
342  ASSERT(signaling_thread()->IsCurrent());
343  if (destroyed_) return;
344
345  worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
346
347  // Notify the subclass.
348  OnTransportSignalingReady();
349}
350
351void Transport::CallChannels_w(TransportChannelFunc func) {
352  ASSERT(worker_thread()->IsCurrent());
353  talk_base::CritScope cs(&crit_);
354  for (ChannelMap::iterator iter = channels_.begin();
355       iter != channels_.end();
356       ++iter) {
357    ((iter->second.get())->*func)();
358  }
359}
360
361bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) {
362  // No address zero.
363  if (cand.address().IsNil() || cand.address().IsAny()) {
364    *error = "candidate has address of zero";
365    return false;
366  }
367
368  // Disallow all ports below 1024, except for 80 and 443 on public addresses.
369  int port = cand.address().port();
370  if (port < 1024) {
371    if ((port != 80) && (port != 443)) {
372      *error = "candidate has port below 1024, but not 80 or 443";
373      return false;
374    }
375
376    if (cand.address().IsPrivateIP()) {
377      *error = "candidate has port of 80 or 443 with private IP address";
378      return false;
379    }
380  }
381
382  return true;
383}
384
385
386bool Transport::GetStats(TransportStats* stats) {
387  ASSERT(signaling_thread()->IsCurrent());
388  return worker_thread_->Invoke<bool>(Bind(
389      &Transport::GetStats_w, this, stats));
390}
391
392bool Transport::GetStats_w(TransportStats* stats) {
393  ASSERT(worker_thread()->IsCurrent());
394  stats->content_name = content_name();
395  stats->channel_stats.clear();
396  for (ChannelMap::iterator iter = channels_.begin();
397       iter != channels_.end();
398       ++iter) {
399    TransportChannelStats substats;
400    substats.component = iter->second->component();
401    if (!iter->second->GetStats(&substats.connection_infos)) {
402      return false;
403    }
404    stats->channel_stats.push_back(substats);
405  }
406  return true;
407}
408
409bool Transport::GetSslRole(talk_base::SSLRole* ssl_role) const {
410  return worker_thread_->Invoke<bool>(Bind(
411      &Transport::GetSslRole_w, this, ssl_role));
412}
413
414void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) {
415  for (std::vector<Candidate>::const_iterator iter = candidates.begin();
416       iter != candidates.end();
417       ++iter) {
418    OnRemoteCandidate(*iter);
419  }
420}
421
422void Transport::OnRemoteCandidate(const Candidate& candidate) {
423  ASSERT(signaling_thread()->IsCurrent());
424  if (destroyed_) return;
425
426  if (!HasChannel(candidate.component())) {
427    LOG(LS_WARNING) << "Ignoring candidate for unknown component "
428                    << candidate.component();
429    return;
430  }
431
432  ChannelParams* params = new ChannelParams(new Candidate(candidate));
433  worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params);
434}
435
436void Transport::OnRemoteCandidate_w(const Candidate& candidate) {
437  ASSERT(worker_thread()->IsCurrent());
438  ChannelMap::iterator iter = channels_.find(candidate.component());
439  // It's ok for a channel to go away while this message is in transit.
440  if (iter != channels_.end()) {
441    iter->second->OnCandidate(candidate);
442  }
443}
444
445void Transport::OnChannelReadableState(TransportChannel* channel) {
446  ASSERT(worker_thread()->IsCurrent());
447  signaling_thread()->Post(this, MSG_READSTATE, NULL);
448}
449
450void Transport::OnChannelReadableState_s() {
451  ASSERT(signaling_thread()->IsCurrent());
452  TransportState readable = GetTransportState_s(true);
453  if (readable_ != readable) {
454    readable_ = readable;
455    SignalReadableState(this);
456  }
457}
458
459void Transport::OnChannelWritableState(TransportChannel* channel) {
460  ASSERT(worker_thread()->IsCurrent());
461  signaling_thread()->Post(this, MSG_WRITESTATE, NULL);
462}
463
464void Transport::OnChannelWritableState_s() {
465  ASSERT(signaling_thread()->IsCurrent());
466  TransportState writable = GetTransportState_s(false);
467  if (writable_ != writable) {
468    was_writable_ = (writable_ == TRANSPORT_STATE_ALL);
469    writable_ = writable;
470    SignalWritableState(this);
471  }
472}
473
474TransportState Transport::GetTransportState_s(bool read) {
475  ASSERT(signaling_thread()->IsCurrent());
476  talk_base::CritScope cs(&crit_);
477  bool any = false;
478  bool all = !channels_.empty();
479  for (ChannelMap::iterator iter = channels_.begin();
480       iter != channels_.end();
481       ++iter) {
482    bool b = (read ? iter->second->readable() :
483      iter->second->writable());
484    any = any || b;
485    all = all && b;
486  }
487  if (all) {
488    return TRANSPORT_STATE_ALL;
489  } else if (any) {
490    return TRANSPORT_STATE_SOME;
491  } else {
492    return TRANSPORT_STATE_NONE;
493  }
494}
495
496void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) {
497  ASSERT(worker_thread()->IsCurrent());
498  ChannelParams* params = new ChannelParams(channel->component());
499  signaling_thread()->Post(this, MSG_REQUESTSIGNALING, params);
500}
501
502void Transport::OnChannelRequestSignaling_s(int component) {
503  ASSERT(signaling_thread()->IsCurrent());
504  LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates";
505  // Resetting ICE state for the channel.
506  {
507    talk_base::CritScope cs(&crit_);
508    ChannelMap::iterator iter = channels_.find(component);
509    if (iter != channels_.end())
510      iter->second.set_candidates_allocated(false);
511  }
512  SignalRequestSignaling(this);
513}
514
515void Transport::OnChannelCandidateReady(TransportChannelImpl* channel,
516                                        const Candidate& candidate) {
517  ASSERT(worker_thread()->IsCurrent());
518  talk_base::CritScope cs(&crit_);
519  ready_candidates_.push_back(candidate);
520
521  // We hold any messages until the client lets us connect.
522  if (connect_requested_) {
523    signaling_thread()->Post(
524        this, MSG_CANDIDATEREADY, NULL);
525  }
526}
527
528void Transport::OnChannelCandidateReady_s() {
529  ASSERT(signaling_thread()->IsCurrent());
530  ASSERT(connect_requested_);
531
532  std::vector<Candidate> candidates;
533  {
534    talk_base::CritScope cs(&crit_);
535    candidates.swap(ready_candidates_);
536  }
537
538  // we do the deleting of Candidate* here to keep the new above and
539  // delete below close to each other
540  if (!candidates.empty()) {
541    SignalCandidatesReady(this, candidates);
542  }
543}
544
545void Transport::OnChannelRouteChange(TransportChannel* channel,
546                                     const Candidate& remote_candidate) {
547  ASSERT(worker_thread()->IsCurrent());
548  ChannelParams* params = new ChannelParams(new Candidate(remote_candidate));
549  params->channel = static_cast<cricket::TransportChannelImpl*>(channel);
550  signaling_thread()->Post(this, MSG_ROUTECHANGE, params);
551}
552
553void Transport::OnChannelRouteChange_s(const TransportChannel* channel,
554                                       const Candidate& remote_candidate) {
555  ASSERT(signaling_thread()->IsCurrent());
556  SignalRouteChange(this, remote_candidate.component(), remote_candidate);
557}
558
559void Transport::OnChannelCandidatesAllocationDone(
560    TransportChannelImpl* channel) {
561  ASSERT(worker_thread()->IsCurrent());
562  talk_base::CritScope cs(&crit_);
563  ChannelMap::iterator iter = channels_.find(channel->component());
564  ASSERT(iter != channels_.end());
565  LOG(LS_INFO) << "Transport: " << content_name_ << ", component "
566               << channel->component() << " allocation complete";
567  iter->second.set_candidates_allocated(true);
568
569  // If all channels belonging to this Transport got signal, then
570  // forward this signal to upper layer.
571  // Can this signal arrive before all transport channels are created?
572  for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
573    if (!iter->second.candidates_allocated())
574      return;
575  }
576  signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE);
577}
578
579void Transport::OnChannelCandidatesAllocationDone_s() {
580  ASSERT(signaling_thread()->IsCurrent());
581  LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
582  SignalCandidatesAllocationDone(this);
583}
584
585void Transport::OnRoleConflict(TransportChannelImpl* channel) {
586  signaling_thread_->Post(this, MSG_ROLECONFLICT);
587}
588
589void Transport::SetIceRole_w(IceRole role) {
590  talk_base::CritScope cs(&crit_);
591  ice_role_ = role;
592  for (ChannelMap::iterator iter = channels_.begin();
593       iter != channels_.end(); ++iter) {
594    iter->second->SetIceRole(ice_role_);
595  }
596}
597
598void Transport::SetRemoteIceMode_w(IceMode mode) {
599  talk_base::CritScope cs(&crit_);
600  remote_ice_mode_ = mode;
601  // Shouldn't channels be created after this method executed?
602  for (ChannelMap::iterator iter = channels_.begin();
603       iter != channels_.end(); ++iter) {
604    iter->second->SetRemoteIceMode(remote_ice_mode_);
605  }
606}
607
608bool Transport::SetLocalTransportDescription_w(
609    const TransportDescription& desc, ContentAction action) {
610  bool ret = true;
611  talk_base::CritScope cs(&crit_);
612  local_description_.reset(new TransportDescription(desc));
613
614  for (ChannelMap::iterator iter = channels_.begin();
615       iter != channels_.end(); ++iter) {
616    ret &= ApplyLocalTransportDescription_w(iter->second.get());
617  }
618  if (!ret)
619    return false;
620
621  // If PRANSWER/ANSWER is set, we should decide transport protocol type.
622  if (action == CA_PRANSWER || action == CA_ANSWER) {
623    ret &= NegotiateTransportDescription_w(action);
624  }
625  return ret;
626}
627
628bool Transport::SetRemoteTransportDescription_w(
629    const TransportDescription& desc, ContentAction action) {
630  bool ret = true;
631  talk_base::CritScope cs(&crit_);
632  remote_description_.reset(new TransportDescription(desc));
633
634  for (ChannelMap::iterator iter = channels_.begin();
635       iter != channels_.end(); ++iter) {
636    ret &= ApplyRemoteTransportDescription_w(iter->second.get());
637  }
638
639  // If PRANSWER/ANSWER is set, we should decide transport protocol type.
640  if (action == CA_PRANSWER || action == CA_ANSWER) {
641    ret = NegotiateTransportDescription_w(CA_OFFER);
642  }
643  return ret;
644}
645
646bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch) {
647  ch->SetIceCredentials(local_description_->ice_ufrag,
648                        local_description_->ice_pwd);
649  return true;
650}
651
652bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch) {
653  ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
654                              remote_description_->ice_pwd);
655  return true;
656}
657
658bool Transport::ApplyNegotiatedTransportDescription_w(
659    TransportChannelImpl* channel) {
660  channel->SetIceProtocolType(protocol_);
661  channel->SetRemoteIceMode(remote_ice_mode_);
662  return true;
663}
664
665bool Transport::NegotiateTransportDescription_w(ContentAction local_role) {
666  // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
667  // P2PTransport.
668  const TransportDescription* offer;
669  const TransportDescription* answer;
670
671  if (local_role == CA_OFFER) {
672    offer = local_description_.get();
673    answer = remote_description_.get();
674  } else {
675    offer = remote_description_.get();
676    answer = local_description_.get();
677  }
678
679  TransportProtocol offer_proto = TransportProtocolFromDescription(offer);
680  TransportProtocol answer_proto = TransportProtocolFromDescription(answer);
681
682  // If offered protocol is gice/ice, then we expect to receive matching
683  // protocol in answer, anything else is treated as an error.
684  // HYBRID is not an option when offered specific protocol.
685  // If offered protocol is HYBRID and answered protocol is HYBRID then
686  // gice is preferred protocol.
687  // TODO(mallinath) - Answer from local or remote should't have both ice
688  // and gice support. It should always pick which protocol it wants to use.
689  // Once WebRTC stops supporting gice (for backward compatibility), HYBRID in
690  // answer must be treated as error.
691  if ((offer_proto == ICEPROTO_GOOGLE || offer_proto == ICEPROTO_RFC5245) &&
692      (offer_proto != answer_proto)) {
693    return false;
694  }
695  protocol_ = answer_proto == ICEPROTO_HYBRID ? ICEPROTO_GOOGLE : answer_proto;
696
697  // If transport is in ICEROLE_CONTROLLED and remote end point supports only
698  // ice_lite, this local end point should take CONTROLLING role.
699  if (ice_role_ == ICEROLE_CONTROLLED &&
700      remote_description_->ice_mode == ICEMODE_LITE) {
701    SetIceRole_w(ICEROLE_CONTROLLING);
702  }
703
704  // Update remote ice_mode to all existing channels.
705  remote_ice_mode_ = remote_description_->ice_mode;
706
707  // Now that we have negotiated everything, push it downward.
708  // Note that we cache the result so that if we have race conditions
709  // between future SetRemote/SetLocal invocations and new channel
710  // creation, we have the negotiation state saved until a new
711  // negotiation happens.
712  for (ChannelMap::iterator iter = channels_.begin();
713       iter != channels_.end();
714       ++iter) {
715    if (!ApplyNegotiatedTransportDescription_w(iter->second.get()))
716      return false;
717  }
718  return true;
719}
720
721void Transport::OnMessage(talk_base::Message* msg) {
722  switch (msg->message_id) {
723    case MSG_ONSIGNALINGREADY:
724      CallChannels_w(&TransportChannelImpl::OnSignalingReady);
725      break;
726    case MSG_ONREMOTECANDIDATE: {
727        ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
728        OnRemoteCandidate_w(*params->candidate);
729        delete params;
730      }
731      break;
732    case MSG_CONNECTING:
733      OnConnecting_s();
734      break;
735    case MSG_READSTATE:
736      OnChannelReadableState_s();
737      break;
738    case MSG_WRITESTATE:
739      OnChannelWritableState_s();
740      break;
741    case MSG_REQUESTSIGNALING: {
742        ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
743        OnChannelRequestSignaling_s(params->component);
744        delete params;
745      }
746      break;
747    case MSG_CANDIDATEREADY:
748      OnChannelCandidateReady_s();
749      break;
750    case MSG_ROUTECHANGE: {
751        ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
752        OnChannelRouteChange_s(params->channel, *params->candidate);
753        delete params;
754      }
755      break;
756    case MSG_CANDIDATEALLOCATIONCOMPLETE:
757      OnChannelCandidatesAllocationDone_s();
758      break;
759    case MSG_ROLECONFLICT:
760      SignalRoleConflict();
761      break;
762  }
763}
764
765bool TransportParser::ParseAddress(const buzz::XmlElement* elem,
766                                   const buzz::QName& address_name,
767                                   const buzz::QName& port_name,
768                                   talk_base::SocketAddress* address,
769                                   ParseError* error) {
770  if (!elem->HasAttr(address_name))
771    return BadParse("address does not have " + address_name.LocalPart(), error);
772  if (!elem->HasAttr(port_name))
773    return BadParse("address does not have " + port_name.LocalPart(), error);
774
775  address->SetIP(elem->Attr(address_name));
776  std::istringstream ist(elem->Attr(port_name));
777  int port = 0;
778  ist >> port;
779  address->SetPort(port);
780
781  return true;
782}
783
784// We're GICE if the namespace is NS_GOOGLE_P2P, or if NS_JINGLE_ICE_UDP is
785// used and the GICE ice-option is set.
786TransportProtocol TransportProtocolFromDescription(
787    const TransportDescription* desc) {
788  ASSERT(desc != NULL);
789  if (desc->transport_type == NS_JINGLE_ICE_UDP) {
790    return (desc->HasOption(ICE_OPTION_GICE)) ?
791        ICEPROTO_HYBRID : ICEPROTO_RFC5245;
792  }
793  return ICEPROTO_GOOGLE;
794}
795
796}  // namespace cricket
Note: See TracBrowser for help on using the repository browser.