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 15namespace net { 16 17// SyncHostResolverBridge::Core ---------------------------------------------- 18 19class 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 74SyncHostResolverBridge::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 85int 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 97void 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 112void 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 119int 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 133void 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 152SyncHostResolverBridge::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 159SyncHostResolverBridge::~SyncHostResolverBridge() { 160 DCHECK(core_->HasShutdown()); 161} 162 163int 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 174void SyncHostResolverBridge::CancelRequest(RequestHandle req) { 175 NOTREACHED(); 176} 177 178void SyncHostResolverBridge::AddObserver(Observer* observer) { 179 NOTREACHED(); 180} 181 182void SyncHostResolverBridge::RemoveObserver(Observer* observer) { 183 NOTREACHED(); 184} 185 186void SyncHostResolverBridge::Shutdown() { 187 DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); 188 core_->Shutdown(); 189} 190 191} // namespace net 192