普通文本  |  192行  |  5.49 KB

// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/proxy/sync_host_resolver_bridge.h"

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"

namespace net {

// SyncHostResolverBridge::Core ----------------------------------------------

class SyncHostResolverBridge::Core
    : public base::RefCountedThreadSafe<SyncHostResolverBridge::Core> {
 public:
  Core(HostResolver* resolver, MessageLoop* host_resolver_loop);

  int ResolveSynchronously(const HostResolver::RequestInfo& info,
                           AddressList* addresses);

  // Returns true if Shutdown() has been called.
  bool HasShutdown() const {
    base::AutoLock l(lock_);
    return HasShutdownLocked();
  }

  // Called on |host_resolver_loop_|.
  void Shutdown();

 private:
  friend class base::RefCountedThreadSafe<SyncHostResolverBridge::Core>;

  bool HasShutdownLocked() const {
    return has_shutdown_;
  }

  // Called on |host_resolver_loop_|.
  void StartResolve(const HostResolver::RequestInfo& info,
                    AddressList* addresses);

  // Called on |host_resolver_loop_|.
  void OnResolveCompletion(int result);

  // Not called on |host_resolver_loop_|.
  int WaitForResolveCompletion();

  HostResolver* const host_resolver_;
  MessageLoop* const host_resolver_loop_;
  net::CompletionCallbackImpl<Core> callback_;
  // The result from the current request (set on |host_resolver_loop_|).
  int err_;
  // The currently outstanding request to |host_resolver_|, or NULL.
  HostResolver::RequestHandle outstanding_request_;

  // Event to notify completion of resolve request.  We always Signal() on
  // |host_resolver_loop_| and Wait() on a different thread.
  base::WaitableEvent event_;

  // True if Shutdown() has been called. Must hold |lock_| to access it.
  bool has_shutdown_;

  // Mutex to guard accesses to |has_shutdown_|.
      mutable base::Lock lock_;

  DISALLOW_COPY_AND_ASSIGN(Core);
};

SyncHostResolverBridge::Core::Core(HostResolver* host_resolver,
                                   MessageLoop* host_resolver_loop)
    : host_resolver_(host_resolver),
      host_resolver_loop_(host_resolver_loop),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          callback_(this, &Core::OnResolveCompletion)),
      err_(0),
      outstanding_request_(NULL),
      event_(true, false),
      has_shutdown_(false) {}

int SyncHostResolverBridge::Core::ResolveSynchronously(
    const HostResolver::RequestInfo& info,
    net::AddressList* addresses) {
  // Otherwise start an async resolve on the resolver's thread.
  host_resolver_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &Core::StartResolve,
                        info, addresses));

  return WaitForResolveCompletion();
}

void SyncHostResolverBridge::Core::StartResolve(
    const HostResolver::RequestInfo& info,
    net::AddressList* addresses) {
  DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
  DCHECK(!outstanding_request_);

  if (HasShutdown())
    return;

  int error = host_resolver_->Resolve(
      info, addresses, &callback_, &outstanding_request_, BoundNetLog());
  if (error != ERR_IO_PENDING)
    OnResolveCompletion(error);  // Completed synchronously.
}

void SyncHostResolverBridge::Core::OnResolveCompletion(int result) {
  DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
  err_ = result;
  outstanding_request_ = NULL;
  event_.Signal();
}

int SyncHostResolverBridge::Core::WaitForResolveCompletion() {
  DCHECK_NE(MessageLoop::current(), host_resolver_loop_);
  event_.Wait();

  {
    base::AutoLock l(lock_);
    if (HasShutdownLocked())
      return ERR_ABORTED;
    event_.Reset();
  }

  return err_;
}

void SyncHostResolverBridge::Core::Shutdown() {
  DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);

  if (outstanding_request_) {
    host_resolver_->CancelRequest(outstanding_request_);
    outstanding_request_ = NULL;
  }

  {
    base::AutoLock l(lock_);
    has_shutdown_ = true;
  }

  // Wake up the PAC thread in case it was waiting for resolve completion.
  event_.Signal();
}

// SyncHostResolverBridge -----------------------------------------------------

SyncHostResolverBridge::SyncHostResolverBridge(HostResolver* host_resolver,
                                               MessageLoop* host_resolver_loop)
    : host_resolver_loop_(host_resolver_loop),
      core_(new Core(host_resolver, host_resolver_loop)) {
  DCHECK(host_resolver_loop_);
}

SyncHostResolverBridge::~SyncHostResolverBridge() {
  DCHECK(core_->HasShutdown());
}

int SyncHostResolverBridge::Resolve(const RequestInfo& info,
                                    AddressList* addresses,
                                    CompletionCallback* callback,
                                    RequestHandle* out_req,
                                    const BoundNetLog& net_log) {
  DCHECK(!callback);
  DCHECK(!out_req);

  return core_->ResolveSynchronously(info, addresses);
}

void SyncHostResolverBridge::CancelRequest(RequestHandle req) {
  NOTREACHED();
}

void SyncHostResolverBridge::AddObserver(Observer* observer) {
  NOTREACHED();
}

void SyncHostResolverBridge::RemoveObserver(Observer* observer) {
  NOTREACHED();
}

void SyncHostResolverBridge::Shutdown() {
  DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
  core_->Shutdown();
}

}  // namespace net