|
1 /* vim:set ts=4 sw=4 sts=4 et cin: */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsHostResolver_h__ |
|
7 #define nsHostResolver_h__ |
|
8 |
|
9 #include "nscore.h" |
|
10 #include "prclist.h" |
|
11 #include "prnetdb.h" |
|
12 #include "pldhash.h" |
|
13 #include "mozilla/CondVar.h" |
|
14 #include "mozilla/Mutex.h" |
|
15 #include "nsISupportsImpl.h" |
|
16 #include "nsIDNSListener.h" |
|
17 #include "nsString.h" |
|
18 #include "nsTArray.h" |
|
19 #include "mozilla/net/DNS.h" |
|
20 #include "mozilla/net/DashboardTypes.h" |
|
21 #include "mozilla/TimeStamp.h" |
|
22 |
|
23 class nsHostResolver; |
|
24 class nsHostRecord; |
|
25 class nsResolveHostCallback; |
|
26 |
|
27 #define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 3 |
|
28 #define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5 |
|
29 #define MAX_NON_PRIORITY_REQUESTS 150 |
|
30 |
|
31 #define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \ |
|
32 MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY) |
|
33 |
|
34 struct nsHostKey |
|
35 { |
|
36 const char *host; |
|
37 uint16_t flags; |
|
38 uint16_t af; |
|
39 }; |
|
40 |
|
41 /** |
|
42 * nsHostRecord - ref counted object type stored in host resolver cache. |
|
43 */ |
|
44 class nsHostRecord : public PRCList, public nsHostKey |
|
45 { |
|
46 typedef mozilla::Mutex Mutex; |
|
47 |
|
48 public: |
|
49 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostRecord) |
|
50 |
|
51 /* instantiates a new host record */ |
|
52 static nsresult Create(const nsHostKey *key, nsHostRecord **record); |
|
53 |
|
54 /* a fully resolved host record has either a non-null |addr_info| or |addr| |
|
55 * field. if |addr_info| is null, it implies that the |host| is an IP |
|
56 * address literal. in which case, |addr| contains the parsed address. |
|
57 * otherwise, if |addr_info| is non-null, then it contains one or many |
|
58 * IP addresses corresponding to the given host name. if both |addr_info| |
|
59 * and |addr| are null, then the given host has not yet been fully resolved. |
|
60 * |af| is the address family of the record we are querying for. |
|
61 */ |
|
62 |
|
63 /* the lock protects |addr_info| and |addr_info_gencnt| because they |
|
64 * are mutable and accessed by the resolver worker thread and the |
|
65 * nsDNSService2 class. |addr| doesn't change after it has been |
|
66 * assigned a value. only the resolver worker thread modifies |
|
67 * nsHostRecord (and only in nsHostResolver::OnLookupComplete); |
|
68 * the other threads just read it. therefore the resolver worker |
|
69 * thread doesn't need to lock when reading |addr_info|. |
|
70 */ |
|
71 Mutex addr_info_lock; |
|
72 int addr_info_gencnt; /* generation count of |addr_info| */ |
|
73 mozilla::net::AddrInfo *addr_info; |
|
74 mozilla::net::NetAddr *addr; |
|
75 bool negative; /* True if this record is a cache of a failed lookup. |
|
76 Negative cache entries are valid just like any other |
|
77 (though never for more than 60 seconds), but a use |
|
78 of that negative entry forces an asynchronous refresh. */ |
|
79 |
|
80 mozilla::TimeStamp expiration; |
|
81 |
|
82 bool HasUsableResult(uint16_t queryFlags) const; |
|
83 |
|
84 // hold addr_info_lock when calling the blacklist functions |
|
85 bool Blacklisted(mozilla::net::NetAddr *query); |
|
86 void ResetBlacklist(); |
|
87 void ReportUnusable(mozilla::net::NetAddr *addr); |
|
88 |
|
89 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
90 |
|
91 private: |
|
92 friend class nsHostResolver; |
|
93 |
|
94 PRCList callbacks; /* list of callbacks */ |
|
95 |
|
96 bool resolving; /* true if this record is being resolved, which means |
|
97 * that it is either on the pending queue or owned by |
|
98 * one of the worker threads. */ |
|
99 |
|
100 bool onQueue; /* true if pending and on the queue (not yet given to getaddrinfo())*/ |
|
101 bool usingAnyThread; /* true if off queue and contributing to mActiveAnyThreadCount */ |
|
102 bool mDoomed; /* explicitly expired */ |
|
103 |
|
104 // a list of addresses associated with this record that have been reported |
|
105 // as unusable. the list is kept as a set of strings to make it independent |
|
106 // of gencnt. |
|
107 nsTArray<nsCString> mBlacklistedItems; |
|
108 |
|
109 nsHostRecord(const nsHostKey *key); /* use Create() instead */ |
|
110 ~nsHostRecord(); |
|
111 }; |
|
112 |
|
113 /** |
|
114 * ResolveHost callback object. It's PRCList members are used by |
|
115 * the nsHostResolver and should not be used by anything else. |
|
116 */ |
|
117 class NS_NO_VTABLE nsResolveHostCallback : public PRCList |
|
118 { |
|
119 public: |
|
120 /** |
|
121 * OnLookupComplete |
|
122 * |
|
123 * this function is called to complete a host lookup initiated by |
|
124 * nsHostResolver::ResolveHost. it may be invoked recursively from |
|
125 * ResolveHost or on an unspecified background thread. |
|
126 * |
|
127 * NOTE: it is the responsibility of the implementor of this method |
|
128 * to handle the callback in a thread safe manner. |
|
129 * |
|
130 * @param resolver |
|
131 * nsHostResolver object associated with this result |
|
132 * @param record |
|
133 * the host record containing the results of the lookup |
|
134 * @param status |
|
135 * if successful, |record| contains non-null results |
|
136 */ |
|
137 virtual void OnLookupComplete(nsHostResolver *resolver, |
|
138 nsHostRecord *record, |
|
139 nsresult status) = 0; |
|
140 /** |
|
141 * EqualsAsyncListener |
|
142 * |
|
143 * Determines if the listener argument matches the listener member var. |
|
144 * For subclasses not implementing a member listener, should return false. |
|
145 * For subclasses having a member listener, the function should check if |
|
146 * they are the same. Used for cases where a pointer to an object |
|
147 * implementing nsResolveHostCallback is unknown, but a pointer to |
|
148 * the original listener is known. |
|
149 * |
|
150 * @param aListener |
|
151 * nsIDNSListener object associated with the original request |
|
152 */ |
|
153 virtual bool EqualsAsyncListener(nsIDNSListener *aListener) = 0; |
|
154 |
|
155 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0; |
|
156 }; |
|
157 |
|
158 /** |
|
159 * nsHostResolver - an asynchronous host name resolver. |
|
160 */ |
|
161 class nsHostResolver |
|
162 { |
|
163 typedef mozilla::CondVar CondVar; |
|
164 typedef mozilla::Mutex Mutex; |
|
165 |
|
166 public: |
|
167 /** |
|
168 * host resolver instances are reference counted. |
|
169 */ |
|
170 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostResolver) |
|
171 |
|
172 /** |
|
173 * creates an addref'd instance of a nsHostResolver object. |
|
174 */ |
|
175 static nsresult Create(uint32_t maxCacheEntries, // zero disables cache |
|
176 uint32_t maxCacheLifetime, // seconds |
|
177 uint32_t lifetimeGracePeriod, // seconds |
|
178 nsHostResolver **resolver); |
|
179 |
|
180 /** |
|
181 * puts the resolver in the shutdown state, which will cause any pending |
|
182 * callbacks to be detached. any future calls to ResolveHost will fail. |
|
183 */ |
|
184 void Shutdown(); |
|
185 |
|
186 /** |
|
187 * resolve the given hostname asynchronously. the caller can synthesize |
|
188 * a synchronous host lookup using a lock and a cvar. as noted above |
|
189 * the callback will occur re-entrantly from an unspecified thread. the |
|
190 * host lookup cannot be canceled (cancelation can be layered above this |
|
191 * by having the callback implementation return without doing anything). |
|
192 */ |
|
193 nsresult ResolveHost(const char *hostname, |
|
194 uint16_t flags, |
|
195 uint16_t af, |
|
196 nsResolveHostCallback *callback); |
|
197 |
|
198 /** |
|
199 * removes the specified callback from the nsHostRecord for the given |
|
200 * hostname, flags, and address family. these parameters should correspond |
|
201 * to the parameters passed to ResolveHost. this function executes the |
|
202 * callback if the callback is still pending with the given status. |
|
203 */ |
|
204 void DetachCallback(const char *hostname, |
|
205 uint16_t flags, |
|
206 uint16_t af, |
|
207 nsResolveHostCallback *callback, |
|
208 nsresult status); |
|
209 |
|
210 /** |
|
211 * Cancels an async request associated with the hostname, flags, |
|
212 * address family and listener. Cancels first callback found which matches |
|
213 * these criteria. These parameters should correspond to the parameters |
|
214 * passed to ResolveHost. If this is the last callback associated with the |
|
215 * host record, it is removed from any request queues it might be on. |
|
216 */ |
|
217 void CancelAsyncRequest(const char *host, |
|
218 uint16_t flags, |
|
219 uint16_t af, |
|
220 nsIDNSListener *aListener, |
|
221 nsresult status); |
|
222 /** |
|
223 * values for the flags parameter passed to ResolveHost and DetachCallback |
|
224 * that may be bitwise OR'd together. |
|
225 * |
|
226 * NOTE: in this implementation, these flags correspond exactly in value |
|
227 * to the flags defined on nsIDNSService. |
|
228 */ |
|
229 enum { |
|
230 RES_BYPASS_CACHE = 1 << 0, |
|
231 RES_CANON_NAME = 1 << 1, |
|
232 RES_PRIORITY_MEDIUM = 1 << 2, |
|
233 RES_PRIORITY_LOW = 1 << 3, |
|
234 RES_SPECULATE = 1 << 4, |
|
235 //RES_DISABLE_IPV6 = 1 << 5, // Not used |
|
236 RES_OFFLINE = 1 << 6 |
|
237 }; |
|
238 |
|
239 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
240 |
|
241 private: |
|
242 nsHostResolver(uint32_t maxCacheEntries = 50, uint32_t maxCacheLifetime = 60, |
|
243 uint32_t lifetimeGracePeriod = 0); |
|
244 ~nsHostResolver(); |
|
245 |
|
246 nsresult Init(); |
|
247 nsresult IssueLookup(nsHostRecord *); |
|
248 bool GetHostToLookup(nsHostRecord **m); |
|
249 void OnLookupComplete(nsHostRecord *, nsresult, mozilla::net::AddrInfo *); |
|
250 void DeQueue(PRCList &aQ, nsHostRecord **aResult); |
|
251 void ClearPendingQueue(PRCList *aPendingQueue); |
|
252 nsresult ConditionallyCreateThread(nsHostRecord *rec); |
|
253 |
|
254 /** |
|
255 * Starts a new lookup in the background for entries that are in the grace |
|
256 * period with a failed connect or all cached entries are negative. |
|
257 */ |
|
258 nsresult ConditionallyRefreshRecord(nsHostRecord *rec, const char *host); |
|
259 |
|
260 static void MoveQueue(nsHostRecord *aRec, PRCList &aDestQ); |
|
261 |
|
262 static void ThreadFunc(void *); |
|
263 |
|
264 enum { |
|
265 METHOD_HIT = 1, |
|
266 METHOD_RENEWAL = 2, |
|
267 METHOD_NEGATIVE_HIT = 3, |
|
268 METHOD_LITERAL = 4, |
|
269 METHOD_OVERFLOW = 5, |
|
270 METHOD_NETWORK_FIRST = 6, |
|
271 METHOD_NETWORK_SHARED = 7 |
|
272 }; |
|
273 |
|
274 uint32_t mMaxCacheEntries; |
|
275 mozilla::TimeDuration mMaxCacheLifetime; // granularity seconds |
|
276 mozilla::TimeDuration mGracePeriod; // granularity seconds |
|
277 mutable Mutex mLock; // mutable so SizeOfIncludingThis can be const |
|
278 CondVar mIdleThreadCV; |
|
279 uint32_t mNumIdleThreads; |
|
280 uint32_t mThreadCount; |
|
281 uint32_t mActiveAnyThreadCount; |
|
282 PLDHashTable mDB; |
|
283 PRCList mHighQ; |
|
284 PRCList mMediumQ; |
|
285 PRCList mLowQ; |
|
286 PRCList mEvictionQ; |
|
287 uint32_t mEvictionQSize; |
|
288 uint32_t mPendingCount; |
|
289 PRTime mCreationTime; |
|
290 bool mShutdown; |
|
291 PRIntervalTime mLongIdleTimeout; |
|
292 PRIntervalTime mShortIdleTimeout; |
|
293 |
|
294 public: |
|
295 /* |
|
296 * Called by the networking dashboard via the DnsService2 |
|
297 */ |
|
298 void GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *); |
|
299 }; |
|
300 |
|
301 #endif // nsHostResolver_h__ |