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