Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2010 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 "net/proxy/sync_host_resolver_bridge.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/logging.h"
      9 #include "base/message_loop.h"
     10 #include "base/synchronization/lock.h"
     11 #include "base/synchronization/waitable_event.h"
     12 #include "net/base/net_errors.h"
     13 #include "net/base/net_log.h"
     14 
     15 namespace net {
     16 
     17 // SyncHostResolverBridge::Core ----------------------------------------------
     18 
     19 class SyncHostResolverBridge::Core
     20     : public base::RefCountedThreadSafe<SyncHostResolverBridge::Core> {
     21  public:
     22   Core(HostResolver* resolver, MessageLoop* host_resolver_loop);
     23 
     24   int ResolveSynchronously(const HostResolver::RequestInfo& info,
     25                            AddressList* addresses);
     26 
     27   // Returns true if Shutdown() has been called.
     28   bool HasShutdown() const {
     29     base::AutoLock l(lock_);
     30     return HasShutdownLocked();
     31   }
     32 
     33   // Called on |host_resolver_loop_|.
     34   void Shutdown();
     35 
     36  private:
     37   friend class base::RefCountedThreadSafe<SyncHostResolverBridge::Core>;
     38 
     39   bool HasShutdownLocked() const {
     40     return has_shutdown_;
     41   }
     42 
     43   // Called on |host_resolver_loop_|.
     44   void StartResolve(const HostResolver::RequestInfo& info,
     45                     AddressList* addresses);
     46 
     47   // Called on |host_resolver_loop_|.
     48   void OnResolveCompletion(int result);
     49 
     50   // Not called on |host_resolver_loop_|.
     51   int WaitForResolveCompletion();
     52 
     53   HostResolver* const host_resolver_;
     54   MessageLoop* const host_resolver_loop_;
     55   net::CompletionCallbackImpl<Core> callback_;
     56   // The result from the current request (set on |host_resolver_loop_|).
     57   int err_;
     58   // The currently outstanding request to |host_resolver_|, or NULL.
     59   HostResolver::RequestHandle outstanding_request_;
     60 
     61   // Event to notify completion of resolve request.  We always Signal() on
     62   // |host_resolver_loop_| and Wait() on a different thread.
     63   base::WaitableEvent event_;
     64 
     65   // True if Shutdown() has been called. Must hold |lock_| to access it.
     66   bool has_shutdown_;
     67 
     68   // Mutex to guard accesses to |has_shutdown_|.
     69       mutable base::Lock lock_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(Core);
     72 };
     73 
     74 SyncHostResolverBridge::Core::Core(HostResolver* host_resolver,
     75                                    MessageLoop* host_resolver_loop)
     76     : host_resolver_(host_resolver),
     77       host_resolver_loop_(host_resolver_loop),
     78       ALLOW_THIS_IN_INITIALIZER_LIST(
     79           callback_(this, &Core::OnResolveCompletion)),
     80       err_(0),
     81       outstanding_request_(NULL),
     82       event_(true, false),
     83       has_shutdown_(false) {}
     84 
     85 int SyncHostResolverBridge::Core::ResolveSynchronously(
     86     const HostResolver::RequestInfo& info,
     87     net::AddressList* addresses) {
     88   // Otherwise start an async resolve on the resolver's thread.
     89   host_resolver_loop_->PostTask(
     90       FROM_HERE,
     91       NewRunnableMethod(this, &Core::StartResolve,
     92                         info, addresses));
     93 
     94   return WaitForResolveCompletion();
     95 }
     96 
     97 void SyncHostResolverBridge::Core::StartResolve(
     98     const HostResolver::RequestInfo& info,
     99     net::AddressList* addresses) {
    100   DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
    101   DCHECK(!outstanding_request_);
    102 
    103   if (HasShutdown())
    104     return;
    105 
    106   int error = host_resolver_->Resolve(
    107       info, addresses, &callback_, &outstanding_request_, BoundNetLog());
    108   if (error != ERR_IO_PENDING)
    109     OnResolveCompletion(error);  // Completed synchronously.
    110 }
    111 
    112 void SyncHostResolverBridge::Core::OnResolveCompletion(int result) {
    113   DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
    114   err_ = result;
    115   outstanding_request_ = NULL;
    116   event_.Signal();
    117 }
    118 
    119 int SyncHostResolverBridge::Core::WaitForResolveCompletion() {
    120   DCHECK_NE(MessageLoop::current(), host_resolver_loop_);
    121   event_.Wait();
    122 
    123   {
    124     base::AutoLock l(lock_);
    125     if (HasShutdownLocked())
    126       return ERR_ABORTED;
    127     event_.Reset();
    128   }
    129 
    130   return err_;
    131 }
    132 
    133 void SyncHostResolverBridge::Core::Shutdown() {
    134   DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
    135 
    136   if (outstanding_request_) {
    137     host_resolver_->CancelRequest(outstanding_request_);
    138     outstanding_request_ = NULL;
    139   }
    140 
    141   {
    142     base::AutoLock l(lock_);
    143     has_shutdown_ = true;
    144   }
    145 
    146   // Wake up the PAC thread in case it was waiting for resolve completion.
    147   event_.Signal();
    148 }
    149 
    150 // SyncHostResolverBridge -----------------------------------------------------
    151 
    152 SyncHostResolverBridge::SyncHostResolverBridge(HostResolver* host_resolver,
    153                                                MessageLoop* host_resolver_loop)
    154     : host_resolver_loop_(host_resolver_loop),
    155       core_(new Core(host_resolver, host_resolver_loop)) {
    156   DCHECK(host_resolver_loop_);
    157 }
    158 
    159 SyncHostResolverBridge::~SyncHostResolverBridge() {
    160   DCHECK(core_->HasShutdown());
    161 }
    162 
    163 int SyncHostResolverBridge::Resolve(const RequestInfo& info,
    164                                     AddressList* addresses,
    165                                     CompletionCallback* callback,
    166                                     RequestHandle* out_req,
    167                                     const BoundNetLog& net_log) {
    168   DCHECK(!callback);
    169   DCHECK(!out_req);
    170 
    171   return core_->ResolveSynchronously(info, addresses);
    172 }
    173 
    174 void SyncHostResolverBridge::CancelRequest(RequestHandle req) {
    175   NOTREACHED();
    176 }
    177 
    178 void SyncHostResolverBridge::AddObserver(Observer* observer) {
    179   NOTREACHED();
    180 }
    181 
    182 void SyncHostResolverBridge::RemoveObserver(Observer* observer) {
    183   NOTREACHED();
    184 }
    185 
    186 void SyncHostResolverBridge::Shutdown() {
    187   DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
    188   core_->Shutdown();
    189 }
    190 
    191 }  // namespace net
    192