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