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