• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
HasShutdown() const28   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 
HasShutdownLocked() const39   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 
Core(HostResolver * host_resolver,MessageLoop * host_resolver_loop)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 
ResolveSynchronously(const HostResolver::RequestInfo & info,net::AddressList * addresses)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 
StartResolve(const HostResolver::RequestInfo & info,net::AddressList * addresses)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 
OnResolveCompletion(int result)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 
WaitForResolveCompletion()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 
Shutdown()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 
SyncHostResolverBridge(HostResolver * host_resolver,MessageLoop * host_resolver_loop)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 
~SyncHostResolverBridge()159 SyncHostResolverBridge::~SyncHostResolverBridge() {
160   DCHECK(core_->HasShutdown());
161 }
162 
Resolve(const RequestInfo & info,AddressList * addresses,CompletionCallback * callback,RequestHandle * out_req,const BoundNetLog & net_log)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 
CancelRequest(RequestHandle req)174 void SyncHostResolverBridge::CancelRequest(RequestHandle req) {
175   NOTREACHED();
176 }
177 
AddObserver(Observer * observer)178 void SyncHostResolverBridge::AddObserver(Observer* observer) {
179   NOTREACHED();
180 }
181 
RemoveObserver(Observer * observer)182 void SyncHostResolverBridge::RemoveObserver(Observer* observer) {
183   NOTREACHED();
184 }
185 
Shutdown()186 void SyncHostResolverBridge::Shutdown() {
187   DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
188   core_->Shutdown();
189 }
190 
191 }  // namespace net
192