OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/bind.h" | |
8 #include "base/compiler_specific.h" | |
9 #include "base/logging.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/synchronization/lock.h" | |
12 #include "base/synchronization/waitable_event.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/base/net_log.h" | |
15 | |
16 namespace net { | |
17 | |
18 // SyncHostResolverBridge::Core ---------------------------------------------- | |
19 | |
20 class SyncHostResolverBridge::Core | |
21 : public base::RefCountedThreadSafe<SyncHostResolverBridge::Core> { | |
22 public: | |
23 Core(HostResolver* resolver, MessageLoop* host_resolver_loop); | |
24 | |
25 int ResolveSynchronously(const HostResolver::RequestInfo& info, | |
26 AddressList* addresses, | |
27 const BoundNetLog& net_log); | |
28 | |
29 // Returns true if Shutdown() has been called. | |
30 bool HasShutdown() const { | |
31 base::AutoLock l(lock_); | |
32 return HasShutdownLocked(); | |
33 } | |
34 | |
35 // Called on |host_resolver_loop_|. | |
36 void Shutdown(); | |
37 | |
38 private: | |
39 friend class base::RefCountedThreadSafe<SyncHostResolverBridge::Core>; | |
40 ~Core() {} | |
41 | |
42 bool HasShutdownLocked() const { | |
43 return has_shutdown_; | |
44 } | |
45 | |
46 // Called on |host_resolver_loop_|. | |
47 void StartResolve(const HostResolver::RequestInfo& info, | |
48 AddressList* addresses, | |
49 const BoundNetLog& net_log); | |
50 | |
51 // Called on |host_resolver_loop_|. | |
52 void OnResolveCompletion(int result); | |
53 | |
54 // Not called on |host_resolver_loop_|. | |
55 int WaitForResolveCompletion(); | |
56 | |
57 HostResolver* const host_resolver_; | |
58 MessageLoop* const host_resolver_loop_; | |
59 // The result from the current request (set on |host_resolver_loop_|). | |
60 int err_; | |
61 // The currently outstanding request to |host_resolver_|, or NULL. | |
62 HostResolver::RequestHandle outstanding_request_; | |
63 | |
64 // Event to notify completion of resolve request. We always Signal() on | |
65 // |host_resolver_loop_| and Wait() on a different thread. | |
66 base::WaitableEvent event_; | |
67 | |
68 // True if Shutdown() has been called. Must hold |lock_| to access it. | |
69 bool has_shutdown_; | |
70 | |
71 // Mutex to guard accesses to |has_shutdown_|. | |
72 mutable base::Lock lock_; | |
73 | |
74 DISALLOW_COPY_AND_ASSIGN(Core); | |
75 }; | |
76 | |
77 SyncHostResolverBridge::Core::Core(HostResolver* host_resolver, | |
78 MessageLoop* host_resolver_loop) | |
79 : host_resolver_(host_resolver), | |
80 host_resolver_loop_(host_resolver_loop), | |
81 err_(0), | |
82 outstanding_request_(NULL), | |
83 event_(true, false), | |
84 has_shutdown_(false) {} | |
85 | |
86 int SyncHostResolverBridge::Core::ResolveSynchronously( | |
87 const HostResolver::RequestInfo& info, | |
88 net::AddressList* addresses, | |
89 const BoundNetLog& net_log) { | |
90 // Otherwise start an async resolve on the resolver's thread. | |
91 host_resolver_loop_->PostTask( | |
92 FROM_HERE, | |
93 base::Bind(&Core::StartResolve, this, info, addresses, net_log)); | |
94 | |
95 return WaitForResolveCompletion(); | |
96 } | |
97 | |
98 void SyncHostResolverBridge::Core::StartResolve( | |
99 const HostResolver::RequestInfo& info, | |
100 net::AddressList* addresses, | |
101 const BoundNetLog& net_log) { | |
102 DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); | |
103 DCHECK(!outstanding_request_); | |
104 | |
105 if (HasShutdown()) | |
106 return; | |
107 | |
108 int error = host_resolver_->Resolve( | |
109 info, addresses, base::Bind(&Core::OnResolveCompletion, this), | |
110 &outstanding_request_, net_log); | |
111 if (error != ERR_IO_PENDING) | |
112 OnResolveCompletion(error); // Completed synchronously. | |
113 } | |
114 | |
115 void SyncHostResolverBridge::Core::OnResolveCompletion(int result) { | |
116 DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); | |
117 err_ = result; | |
118 outstanding_request_ = NULL; | |
119 event_.Signal(); | |
120 } | |
121 | |
122 int SyncHostResolverBridge::Core::WaitForResolveCompletion() { | |
123 DCHECK_NE(MessageLoop::current(), host_resolver_loop_); | |
124 event_.Wait(); | |
125 | |
126 { | |
127 base::AutoLock l(lock_); | |
128 if (HasShutdownLocked()) | |
129 return ERR_ABORTED; | |
130 event_.Reset(); | |
131 } | |
132 | |
133 return err_; | |
134 } | |
135 | |
136 void SyncHostResolverBridge::Core::Shutdown() { | |
137 DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); | |
138 | |
139 if (outstanding_request_) { | |
140 host_resolver_->CancelRequest(outstanding_request_); | |
141 outstanding_request_ = NULL; | |
142 } | |
143 | |
144 { | |
145 base::AutoLock l(lock_); | |
146 has_shutdown_ = true; | |
147 } | |
148 | |
149 // Wake up the PAC thread in case it was waiting for resolve completion. | |
150 event_.Signal(); | |
151 } | |
152 | |
153 // SyncHostResolverBridge ----------------------------------------------------- | |
154 | |
155 SyncHostResolverBridge::SyncHostResolverBridge(HostResolver* host_resolver, | |
156 MessageLoop* host_resolver_loop) | |
157 : host_resolver_loop_(host_resolver_loop), | |
158 core_(new Core(host_resolver, host_resolver_loop)) { | |
159 DCHECK(host_resolver_loop_); | |
160 } | |
161 | |
162 SyncHostResolverBridge::~SyncHostResolverBridge() { | |
163 DCHECK(core_->HasShutdown()); | |
164 } | |
165 | |
166 int SyncHostResolverBridge::Resolve(const HostResolver::RequestInfo& info, | |
167 AddressList* addresses, | |
168 const BoundNetLog& net_log) { | |
169 return core_->ResolveSynchronously(info, addresses, net_log); | |
170 } | |
171 | |
172 void SyncHostResolverBridge::Shutdown() { | |
173 DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); | |
174 core_->Shutdown(); | |
175 } | |
176 | |
177 } // namespace net | |
OLD | NEW |