ice_transport_channel.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/protocol/ice_transport_channel.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/callback.h"
  10. #include "base/task/single_thread_task_runner.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "components/webrtc/net_address_utils.h"
  13. #include "net/base/net_errors.h"
  14. #include "remoting/protocol/channel_socket_adapter.h"
  15. #include "remoting/protocol/port_allocator_factory.h"
  16. #include "remoting/protocol/transport_context.h"
  17. #include "third_party/webrtc/p2p/base/p2p_constants.h"
  18. #include "third_party/webrtc/p2p/base/p2p_transport_channel.h"
  19. #include "third_party/webrtc/p2p/base/packet_transport_internal.h"
  20. #include "third_party/webrtc/p2p/base/port.h"
  21. namespace remoting {
  22. namespace protocol {
  23. namespace {
  24. const int kIceUfragLength = 16;
  25. // Utility function to map a cricket::Candidate string type to a
  26. // TransportRoute::RouteType enum value.
  27. TransportRoute::RouteType CandidateTypeToTransportRouteType(
  28. const std::string& candidate_type) {
  29. if (candidate_type == "local") {
  30. return TransportRoute::DIRECT;
  31. } else if (candidate_type == "stun" || candidate_type == "prflx") {
  32. return TransportRoute::STUN;
  33. } else if (candidate_type == "relay") {
  34. return TransportRoute::RELAY;
  35. } else {
  36. LOG(FATAL) << "Unknown candidate type: " << candidate_type;
  37. return TransportRoute::DIRECT;
  38. }
  39. }
  40. } // namespace
  41. IceTransportChannel::IceTransportChannel(
  42. scoped_refptr<TransportContext> transport_context)
  43. : transport_context_(transport_context),
  44. ice_username_fragment_(rtc::CreateRandomString(kIceUfragLength)),
  45. connect_attempts_left_(
  46. transport_context->network_settings().ice_reconnect_attempts) {
  47. DCHECK(!ice_username_fragment_.empty());
  48. }
  49. IceTransportChannel::~IceTransportChannel() {
  50. DCHECK(delegate_);
  51. DCHECK(thread_checker_.CalledOnValidThread());
  52. delegate_->OnChannelDeleted(this);
  53. auto task_runner = base::ThreadTaskRunnerHandle::Get();
  54. if (channel_)
  55. task_runner->DeleteSoon(FROM_HERE, channel_.release());
  56. if (port_allocator_)
  57. task_runner->DeleteSoon(FROM_HERE, port_allocator_.release());
  58. }
  59. void IceTransportChannel::Connect(const std::string& name,
  60. Delegate* delegate,
  61. ConnectedCallback callback) {
  62. DCHECK(thread_checker_.CalledOnValidThread());
  63. DCHECK(!name.empty());
  64. DCHECK(delegate);
  65. DCHECK(!callback.is_null());
  66. DCHECK(name_.empty());
  67. name_ = name;
  68. delegate_ = delegate;
  69. callback_ = std::move(callback);
  70. port_allocator_ =
  71. transport_context_->port_allocator_factory()->CreatePortAllocator(
  72. transport_context_, nullptr);
  73. // Create P2PTransportChannel, attach signal handlers and connect it.
  74. // TODO(sergeyu): Specify correct component ID for the channel.
  75. channel_ = std::make_unique<cricket::P2PTransportChannel>(
  76. std::string(), 0, port_allocator_.get());
  77. std::string ice_password = rtc::CreateRandomString(cricket::ICE_PWD_LENGTH);
  78. channel_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
  79. channel_->SetIceRole((transport_context_->role() == TransportRole::CLIENT)
  80. ? cricket::ICEROLE_CONTROLLING
  81. : cricket::ICEROLE_CONTROLLED);
  82. delegate_->OnChannelIceCredentials(this, ice_username_fragment_,
  83. ice_password);
  84. channel_->SetIceCredentials(ice_username_fragment_, ice_password);
  85. channel_->SignalCandidateGathered.connect(
  86. this, &IceTransportChannel::OnCandidateGathered);
  87. channel_->SignalRouteChange.connect(
  88. this, &IceTransportChannel::OnRouteChange);
  89. channel_->SignalWritableState.connect(
  90. this, &IceTransportChannel::OnWritableState);
  91. channel_->set_incoming_only(!(transport_context_->network_settings().flags &
  92. NetworkSettings::NAT_TRAVERSAL_OUTGOING));
  93. channel_->Connect();
  94. channel_->MaybeStartGathering();
  95. // Pass pending ICE credentials and candidates to the channel.
  96. if (!remote_ice_username_fragment_.empty()) {
  97. channel_->SetRemoteIceCredentials(remote_ice_username_fragment_,
  98. remote_ice_password_);
  99. }
  100. while (!pending_candidates_.empty()) {
  101. channel_->AddRemoteCandidate(pending_candidates_.front());
  102. pending_candidates_.pop_front();
  103. }
  104. --connect_attempts_left_;
  105. // Start reconnection timer.
  106. reconnect_timer_.Start(FROM_HERE,
  107. transport_context_->network_settings().ice_timeout,
  108. this, &IceTransportChannel::TryReconnect);
  109. base::ThreadTaskRunnerHandle::Get()->PostTask(
  110. FROM_HERE, base::BindOnce(&IceTransportChannel::NotifyConnected,
  111. weak_factory_.GetWeakPtr()));
  112. }
  113. void IceTransportChannel::NotifyConnected() {
  114. // Create P2PDatagramSocket adapter for the P2PTransportChannel.
  115. std::unique_ptr<TransportChannelSocketAdapter> socket(
  116. new TransportChannelSocketAdapter(channel_.get()));
  117. socket->SetOnDestroyedCallback(base::BindOnce(
  118. &IceTransportChannel::OnChannelDestroyed, base::Unretained(this)));
  119. std::move(callback_).Run(std::move(socket));
  120. }
  121. void IceTransportChannel::SetRemoteCredentials(const std::string& ufrag,
  122. const std::string& password) {
  123. DCHECK(thread_checker_.CalledOnValidThread());
  124. remote_ice_username_fragment_ = ufrag;
  125. remote_ice_password_ = password;
  126. if (channel_)
  127. channel_->SetRemoteIceCredentials(ufrag, password);
  128. }
  129. void IceTransportChannel::AddRemoteCandidate(
  130. const cricket::Candidate& candidate) {
  131. DCHECK(thread_checker_.CalledOnValidThread());
  132. // To enforce the no-relay setting, it's not enough to not produce relay
  133. // candidates. It's also necessary to discard remote relay candidates.
  134. bool relay_allowed = (transport_context_->network_settings().flags &
  135. NetworkSettings::NAT_TRAVERSAL_RELAY) != 0;
  136. if (!relay_allowed && candidate.type() == cricket::RELAY_PORT_TYPE)
  137. return;
  138. if (channel_) {
  139. channel_->AddRemoteCandidate(candidate);
  140. } else {
  141. pending_candidates_.push_back(candidate);
  142. }
  143. }
  144. const std::string& IceTransportChannel::name() const {
  145. DCHECK(thread_checker_.CalledOnValidThread());
  146. return name_;
  147. }
  148. bool IceTransportChannel::is_connected() const {
  149. DCHECK(thread_checker_.CalledOnValidThread());
  150. return callback_.is_null();
  151. }
  152. void IceTransportChannel::OnCandidateGathered(
  153. cricket::IceTransportInternal* ice_transport,
  154. const cricket::Candidate& candidate) {
  155. DCHECK(thread_checker_.CalledOnValidThread());
  156. delegate_->OnChannelCandidate(this, candidate);
  157. }
  158. void IceTransportChannel::OnRouteChange(
  159. cricket::IceTransportInternal* ice_transport,
  160. const cricket::Candidate& candidate) {
  161. // Ignore notifications if the channel is not writable.
  162. if (channel_->writable())
  163. NotifyRouteChanged();
  164. }
  165. void IceTransportChannel::OnWritableState(
  166. rtc::PacketTransportInternal* transport) {
  167. DCHECK_EQ(transport,
  168. static_cast<rtc::PacketTransportInternal*>(channel_.get()));
  169. if (transport->writable()) {
  170. connect_attempts_left_ =
  171. transport_context_->network_settings().ice_reconnect_attempts;
  172. reconnect_timer_.Stop();
  173. // Route change notifications are ignored when the |channel_| is not
  174. // writable. Notify the event handler about the current route once the
  175. // channel is writable.
  176. NotifyRouteChanged();
  177. } else {
  178. reconnect_timer_.Reset();
  179. TryReconnect();
  180. }
  181. }
  182. void IceTransportChannel::OnChannelDestroyed() {
  183. // The connection socket is being deleted, so delete the transport too.
  184. delete this;
  185. }
  186. void IceTransportChannel::NotifyRouteChanged() {
  187. TransportRoute route;
  188. DCHECK(channel_->best_connection());
  189. const cricket::Connection* connection = channel_->best_connection();
  190. // A connection has both a local and a remote candidate. For our purposes, the
  191. // route type is determined by the most indirect candidate type. For example:
  192. // it's possible for the local candidate be a "relay" type, while the remote
  193. // candidate is "local". In this case, we still want to report a RELAY route
  194. // type.
  195. static_assert(TransportRoute::DIRECT < TransportRoute::STUN &&
  196. TransportRoute::STUN < TransportRoute::RELAY,
  197. "Route type enum values are ordered by 'indirectness'");
  198. route.type = std::max(
  199. CandidateTypeToTransportRouteType(connection->local_candidate().type()),
  200. CandidateTypeToTransportRouteType(connection->remote_candidate().type()));
  201. if (!webrtc::SocketAddressToIPEndPoint(
  202. connection->remote_candidate().address(), &route.remote_address)) {
  203. LOG(FATAL) << "Failed to convert peer IP address.";
  204. }
  205. const cricket::Candidate& local_candidate =
  206. channel_->best_connection()->local_candidate();
  207. if (!webrtc::SocketAddressToIPEndPoint(local_candidate.address(),
  208. &route.local_address)) {
  209. LOG(FATAL) << "Failed to convert local IP address.";
  210. }
  211. delegate_->OnChannelRouteChange(this, route);
  212. }
  213. void IceTransportChannel::TryReconnect() {
  214. DCHECK(!channel_->writable());
  215. if (connect_attempts_left_ <= 0) {
  216. reconnect_timer_.Stop();
  217. // Notify the caller that ICE connection has failed - normally that will
  218. // terminate Jingle connection (i.e. the transport will be destroyed).
  219. delegate_->OnChannelFailed(this);
  220. return;
  221. }
  222. --connect_attempts_left_;
  223. // Restart ICE by resetting ICE password.
  224. std::string ice_password = rtc::CreateRandomString(cricket::ICE_PWD_LENGTH);
  225. delegate_->OnChannelIceCredentials(this, ice_username_fragment_,
  226. ice_password);
  227. channel_->SetIceCredentials(ice_username_fragment_, ice_password);
  228. }
  229. } // namespace protocol
  230. } // namespace remoting