Home | History | Annotate | Download | only in protocol
      1 // Copyright 2014 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 
      5 #include "remoting/protocol/chromium_port_allocator.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/stl_util.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "net/http/http_status_code.h"
     11 #include "net/url_request/url_fetcher.h"
     12 #include "net/url_request/url_fetcher_delegate.h"
     13 #include "net/url_request/url_request_context_getter.h"
     14 #include "remoting/protocol/chromium_socket_factory.h"
     15 #include "remoting/protocol/network_settings.h"
     16 #include "url/gurl.h"
     17 
     18 namespace remoting {
     19 namespace protocol {
     20 
     21 namespace {
     22 
     23 class ChromiumPortAllocatorSession
     24     : public cricket::HttpPortAllocatorSessionBase,
     25       public net::URLFetcherDelegate {
     26  public:
     27   ChromiumPortAllocatorSession(
     28       cricket::HttpPortAllocatorBase* allocator,
     29       const std::string& content_name,
     30       int component,
     31       const std::string& ice_username_fragment,
     32       const std::string& ice_password,
     33       const std::vector<rtc::SocketAddress>& stun_hosts,
     34       const std::vector<std::string>& relay_hosts,
     35       const std::string& relay,
     36       const scoped_refptr<net::URLRequestContextGetter>& url_context);
     37   virtual ~ChromiumPortAllocatorSession();
     38 
     39   // cricket::HttpPortAllocatorBase overrides.
     40   virtual void ConfigReady(cricket::PortConfiguration* config) OVERRIDE;
     41   virtual void SendSessionRequest(const std::string& host, int port) OVERRIDE;
     42 
     43   // net::URLFetcherDelegate interface.
     44   virtual void OnURLFetchComplete(const net::URLFetcher* url_fetcher) OVERRIDE;
     45 
     46  private:
     47   scoped_refptr<net::URLRequestContextGetter> url_context_;
     48   std::set<const net::URLFetcher*> url_fetchers_;
     49 
     50   DISALLOW_COPY_AND_ASSIGN(ChromiumPortAllocatorSession);
     51 };
     52 
     53 ChromiumPortAllocatorSession::ChromiumPortAllocatorSession(
     54     cricket::HttpPortAllocatorBase* allocator,
     55     const std::string& content_name,
     56     int component,
     57     const std::string& ice_username_fragment,
     58     const std::string& ice_password,
     59     const std::vector<rtc::SocketAddress>& stun_hosts,
     60     const std::vector<std::string>& relay_hosts,
     61     const std::string& relay,
     62     const scoped_refptr<net::URLRequestContextGetter>& url_context)
     63     : HttpPortAllocatorSessionBase(allocator,
     64                                    content_name,
     65                                    component,
     66                                    ice_username_fragment,
     67                                    ice_password,
     68                                    stun_hosts,
     69                                    relay_hosts,
     70                                    relay,
     71                                    std::string()),
     72       url_context_(url_context) {}
     73 
     74 ChromiumPortAllocatorSession::~ChromiumPortAllocatorSession() {
     75   STLDeleteElements(&url_fetchers_);
     76 }
     77 
     78 void ChromiumPortAllocatorSession::ConfigReady(
     79     cricket::PortConfiguration* config) {
     80   // Filter out non-UDP relay ports, so that we don't try using TCP.
     81   for (cricket::PortConfiguration::RelayList::iterator relay =
     82            config->relays.begin(); relay != config->relays.end(); ++relay) {
     83     cricket::PortList filtered_ports;
     84     for (cricket::PortList::iterator port =
     85              relay->ports.begin(); port != relay->ports.end(); ++port) {
     86       if (port->proto == cricket::PROTO_UDP) {
     87         filtered_ports.push_back(*port);
     88       }
     89     }
     90     relay->ports = filtered_ports;
     91   }
     92   cricket::BasicPortAllocatorSession::ConfigReady(config);
     93 }
     94 
     95 void ChromiumPortAllocatorSession::SendSessionRequest(
     96     const std::string& host,
     97     int port) {
     98   GURL url("https://" + host + ":" + base::IntToString(port) +
     99            GetSessionRequestUrl() + "&sn=1");
    100   scoped_ptr<net::URLFetcher> url_fetcher(
    101       net::URLFetcher::Create(url, net::URLFetcher::GET, this));
    102   url_fetcher->SetRequestContext(url_context_.get());
    103   url_fetcher->AddExtraRequestHeader("X-Talk-Google-Relay-Auth: " +
    104                                      relay_token());
    105   url_fetcher->AddExtraRequestHeader("X-Google-Relay-Auth: " + relay_token());
    106   url_fetcher->AddExtraRequestHeader("X-Stream-Type: chromoting");
    107   url_fetcher->Start();
    108   url_fetchers_.insert(url_fetcher.release());
    109 }
    110 
    111 void ChromiumPortAllocatorSession::OnURLFetchComplete(
    112     const net::URLFetcher* source) {
    113   int response_code = source->GetResponseCode();
    114   std::string response;
    115   source->GetResponseAsString(&response);
    116 
    117   url_fetchers_.erase(source);
    118   delete source;
    119 
    120   if (response_code != net::HTTP_OK) {
    121     LOG(WARNING) << "Received error when allocating relay session: "
    122                  << response_code;
    123     TryCreateRelaySession();
    124     return;
    125   }
    126 
    127   ReceiveSessionResponse(response);
    128 }
    129 
    130 }  // namespace
    131 
    132 // static
    133 scoped_ptr<ChromiumPortAllocator> ChromiumPortAllocator::Create(
    134     const scoped_refptr<net::URLRequestContextGetter>& url_context,
    135     const NetworkSettings& network_settings) {
    136   scoped_ptr<rtc::NetworkManager> network_manager(
    137       new rtc::BasicNetworkManager());
    138   scoped_ptr<rtc::PacketSocketFactory> socket_factory(
    139       new ChromiumPacketSocketFactory());
    140   scoped_ptr<ChromiumPortAllocator> result(
    141       new ChromiumPortAllocator(url_context, network_manager.Pass(),
    142                             socket_factory.Pass()));
    143 
    144   // We always use PseudoTcp to provide a reliable channel. It provides poor
    145   // performance when combined with TCP-based transport, so we have to disable
    146   // TCP ports. ENABLE_SHARED_UFRAG flag is specified so that the same username
    147   // fragment is shared between all candidates for this channel.
    148   int flags = cricket::PORTALLOCATOR_DISABLE_TCP |
    149               cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
    150               cricket::PORTALLOCATOR_ENABLE_IPV6;
    151 
    152   if (!(network_settings.flags & NetworkSettings::NAT_TRAVERSAL_STUN))
    153     flags |= cricket::PORTALLOCATOR_DISABLE_STUN;
    154 
    155   if (!(network_settings.flags & NetworkSettings::NAT_TRAVERSAL_RELAY))
    156     flags |= cricket::PORTALLOCATOR_DISABLE_RELAY;
    157 
    158   result->set_flags(flags);
    159   result->SetPortRange(network_settings.min_port,
    160                        network_settings.max_port);
    161 
    162   return result.Pass();
    163 }
    164 
    165 ChromiumPortAllocator::ChromiumPortAllocator(
    166     const scoped_refptr<net::URLRequestContextGetter>& url_context,
    167     scoped_ptr<rtc::NetworkManager> network_manager,
    168     scoped_ptr<rtc::PacketSocketFactory> socket_factory)
    169     : HttpPortAllocatorBase(network_manager.get(),
    170                             socket_factory.get(),
    171                             std::string()),
    172       url_context_(url_context),
    173       network_manager_(network_manager.Pass()),
    174       socket_factory_(socket_factory.Pass()) {}
    175 
    176 ChromiumPortAllocator::~ChromiumPortAllocator() {
    177 }
    178 
    179 cricket::PortAllocatorSession* ChromiumPortAllocator::CreateSessionInternal(
    180     const std::string& content_name,
    181     int component,
    182     const std::string& ice_username_fragment,
    183     const std::string& ice_password) {
    184   return new ChromiumPortAllocatorSession(
    185       this, content_name, component, ice_username_fragment, ice_password,
    186       stun_hosts(), relay_hosts(), relay_token(), url_context_);
    187 }
    188 
    189 }  // namespace protocol
    190 }  // namespace remoting
    191