// 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/lock.h" #include "base/message_loop.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 { 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 { AutoLock l(lock_); return HasShutdownLocked(); } // Called on |host_resolver_loop_|. void Shutdown(); private: friend class base::RefCountedThreadSafe; 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 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 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(); { 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; } { 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