Line data Source code
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 "PLDHashTable.h"
13 : #include "mozilla/CondVar.h"
14 : #include "mozilla/Mutex.h"
15 : #include "nsISupportsImpl.h"
16 : #include "nsIDNSListener.h"
17 : #include "nsIDNSService.h"
18 : #include "nsString.h"
19 : #include "nsTArray.h"
20 : #include "GetAddrInfo.h"
21 : #include "mozilla/net/DNS.h"
22 : #include "mozilla/net/DashboardTypes.h"
23 : #include "mozilla/TimeStamp.h"
24 :
25 : class nsHostResolver;
26 : class nsHostRecord;
27 : class nsResolveHostCallback;
28 :
29 : #define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 3
30 : #define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5
31 : #define MAX_NON_PRIORITY_REQUESTS 150
32 :
33 : #define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \
34 : MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY)
35 :
36 3 : struct nsHostKey
37 : {
38 : const char *host;
39 : uint16_t flags;
40 : uint16_t af;
41 : const char *netInterface;
42 : const char *originSuffix;
43 : };
44 :
45 : /**
46 : * nsHostRecord - ref counted object type stored in host resolver cache.
47 : */
48 : class nsHostRecord : public PRCList, public nsHostKey
49 : {
50 : typedef mozilla::Mutex Mutex;
51 :
52 : public:
53 15 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostRecord)
54 :
55 : /* instantiates a new host record */
56 : static nsresult Create(const nsHostKey *key, nsHostRecord **record);
57 :
58 : /* a fully resolved host record has either a non-null |addr_info| or |addr|
59 : * field. if |addr_info| is null, it implies that the |host| is an IP
60 : * address literal. in which case, |addr| contains the parsed address.
61 : * otherwise, if |addr_info| is non-null, then it contains one or many
62 : * IP addresses corresponding to the given host name. if both |addr_info|
63 : * and |addr| are null, then the given host has not yet been fully resolved.
64 : * |af| is the address family of the record we are querying for.
65 : */
66 :
67 : /* the lock protects |addr_info| and |addr_info_gencnt| because they
68 : * are mutable and accessed by the resolver worker thread and the
69 : * nsDNSService2 class. |addr| doesn't change after it has been
70 : * assigned a value. only the resolver worker thread modifies
71 : * nsHostRecord (and only in nsHostResolver::OnLookupComplete);
72 : * the other threads just read it. therefore the resolver worker
73 : * thread doesn't need to lock when reading |addr_info|.
74 : */
75 : Mutex addr_info_lock;
76 : int addr_info_gencnt; /* generation count of |addr_info| */
77 : mozilla::net::AddrInfo *addr_info;
78 : mozilla::net::NetAddr *addr;
79 : bool negative; /* True if this record is a cache of a failed lookup.
80 : Negative cache entries are valid just like any other
81 : (though never for more than 60 seconds), but a use
82 : of that negative entry forces an asynchronous refresh. */
83 :
84 : enum ExpirationStatus {
85 : EXP_VALID,
86 : EXP_GRACE,
87 : EXP_EXPIRED,
88 : };
89 :
90 : ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const;
91 :
92 : // When the record began being valid. Used mainly for bookkeeping.
93 : mozilla::TimeStamp mValidStart;
94 :
95 : // When the record is no longer valid (it's time of expiration)
96 : mozilla::TimeStamp mValidEnd;
97 :
98 : // When the record enters its grace period. This must be before mValidEnd.
99 : // If a record is in its grace period (and not expired), it will be used
100 : // but a request to refresh it will be made.
101 : mozilla::TimeStamp mGraceStart;
102 :
103 : // Convenience function for setting the timestamps above (mValidStart,
104 : // mValidEnd, and mGraceStart). valid and grace are durations in seconds.
105 : void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid,
106 : unsigned int grace);
107 : void CopyExpirationTimesAndFlagsFrom(const nsHostRecord *aFromHostRecord);
108 :
109 : // Checks if the record is usable (not expired and has a value)
110 : bool HasUsableResult(const mozilla::TimeStamp& now, uint16_t queryFlags = 0) const;
111 :
112 : // hold addr_info_lock when calling the blacklist functions
113 : bool Blacklisted(mozilla::net::NetAddr *query);
114 : void ResetBlacklist();
115 : void ReportUnusable(mozilla::net::NetAddr *addr);
116 :
117 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
118 :
119 : enum DnsPriority {
120 : DNS_PRIORITY_LOW,
121 : DNS_PRIORITY_MEDIUM,
122 : DNS_PRIORITY_HIGH,
123 : };
124 : static DnsPriority GetPriority(uint16_t aFlags);
125 :
126 : bool RemoveOrRefresh(); // Mark records currently being resolved as needed
127 : // to resolve again.
128 :
129 : private:
130 : friend class nsHostResolver;
131 :
132 :
133 : PRCList callbacks; /* list of callbacks */
134 :
135 : bool resolving; /* true if this record is being resolved, which means
136 : * that it is either on the pending queue or owned by
137 : * one of the worker threads. */
138 :
139 : bool onQueue; /* true if pending and on the queue (not yet given to getaddrinfo())*/
140 : bool usingAnyThread; /* true if off queue and contributing to mActiveAnyThreadCount */
141 : bool mDoomed; /* explicitly expired */
142 :
143 : #if TTL_AVAILABLE
144 : bool mGetTtl;
145 : #endif
146 :
147 : // The number of times ReportUnusable() has been called in the record's
148 : // lifetime.
149 : uint32_t mBlacklistedCount;
150 :
151 : // when the results from this resolve is returned, it is not to be
152 : // trusted, but instead a new resolve must be made!
153 : bool mResolveAgain;
154 :
155 : // a list of addresses associated with this record that have been reported
156 : // as unusable. the list is kept as a set of strings to make it independent
157 : // of gencnt.
158 : nsTArray<nsCString> mBlacklistedItems;
159 :
160 : explicit nsHostRecord(const nsHostKey *key); /* use Create() instead */
161 : ~nsHostRecord();
162 : };
163 :
164 : /**
165 : * ResolveHost callback object. It's PRCList members are used by
166 : * the nsHostResolver and should not be used by anything else.
167 : */
168 3 : class NS_NO_VTABLE nsResolveHostCallback : public PRCList
169 : {
170 : public:
171 : /**
172 : * OnLookupComplete
173 : *
174 : * this function is called to complete a host lookup initiated by
175 : * nsHostResolver::ResolveHost. it may be invoked recursively from
176 : * ResolveHost or on an unspecified background thread.
177 : *
178 : * NOTE: it is the responsibility of the implementor of this method
179 : * to handle the callback in a thread safe manner.
180 : *
181 : * @param resolver
182 : * nsHostResolver object associated with this result
183 : * @param record
184 : * the host record containing the results of the lookup
185 : * @param status
186 : * if successful, |record| contains non-null results
187 : */
188 : virtual void OnLookupComplete(nsHostResolver *resolver,
189 : nsHostRecord *record,
190 : nsresult status) = 0;
191 : /**
192 : * EqualsAsyncListener
193 : *
194 : * Determines if the listener argument matches the listener member var.
195 : * For subclasses not implementing a member listener, should return false.
196 : * For subclasses having a member listener, the function should check if
197 : * they are the same. Used for cases where a pointer to an object
198 : * implementing nsResolveHostCallback is unknown, but a pointer to
199 : * the original listener is known.
200 : *
201 : * @param aListener
202 : * nsIDNSListener object associated with the original request
203 : */
204 : virtual bool EqualsAsyncListener(nsIDNSListener *aListener) = 0;
205 :
206 : virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0;
207 : };
208 :
209 : /**
210 : * nsHostResolver - an asynchronous host name resolver.
211 : */
212 1 : class nsHostResolver
213 : {
214 : typedef mozilla::CondVar CondVar;
215 : typedef mozilla::Mutex Mutex;
216 :
217 : public:
218 : /**
219 : * host resolver instances are reference counted.
220 : */
221 23 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostResolver)
222 :
223 : /**
224 : * creates an addref'd instance of a nsHostResolver object.
225 : */
226 : static nsresult Create(uint32_t maxCacheEntries, // zero disables cache
227 : uint32_t defaultCacheEntryLifetime, // seconds
228 : uint32_t defaultGracePeriod, // seconds
229 : nsHostResolver **resolver);
230 :
231 : /**
232 : * puts the resolver in the shutdown state, which will cause any pending
233 : * callbacks to be detached. any future calls to ResolveHost will fail.
234 : */
235 : void Shutdown();
236 :
237 : /**
238 : * resolve the given hostname and originAttributes asynchronously. the caller
239 : * can synthesize a synchronous host lookup using a lock and a cvar. as noted
240 : * above the callback will occur re-entrantly from an unspecified thread. the
241 : * host lookup cannot be canceled (cancelation can be layered above this by
242 : * having the callback implementation return without doing anything).
243 : */
244 : nsresult ResolveHost(const char *hostname,
245 : const mozilla::OriginAttributes &aOriginAttributes,
246 : uint16_t flags,
247 : uint16_t af,
248 : const char *netInterface,
249 : nsResolveHostCallback *callback);
250 :
251 : /**
252 : * removes the specified callback from the nsHostRecord for the given
253 : * hostname, originAttributes, flags, and address family. these parameters
254 : * should correspond to the parameters passed to ResolveHost. this function
255 : * executes the callback if the callback is still pending with the given status.
256 : */
257 : void DetachCallback(const char *hostname,
258 : const mozilla::OriginAttributes &aOriginAttributes,
259 : uint16_t flags,
260 : uint16_t af,
261 : const char *netInterface,
262 : nsResolveHostCallback *callback,
263 : nsresult status);
264 :
265 : /**
266 : * Cancels an async request associated with the hostname, originAttributes, flags,
267 : * address family and listener. Cancels first callback found which matches
268 : * these criteria. These parameters should correspond to the parameters
269 : * passed to ResolveHost. If this is the last callback associated with the
270 : * host record, it is removed from any request queues it might be on.
271 : */
272 : void CancelAsyncRequest(const char *host,
273 : const mozilla::OriginAttributes &aOriginAttributes,
274 : uint16_t flags,
275 : uint16_t af,
276 : const char *netInterface,
277 : nsIDNSListener *aListener,
278 : nsresult status);
279 : /**
280 : * values for the flags parameter passed to ResolveHost and DetachCallback
281 : * that may be bitwise OR'd together.
282 : *
283 : * NOTE: in this implementation, these flags correspond exactly in value
284 : * to the flags defined on nsIDNSService.
285 : */
286 : enum {
287 : RES_BYPASS_CACHE = nsIDNSService::RESOLVE_BYPASS_CACHE,
288 : RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME,
289 : RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM,
290 : RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW,
291 : RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE,
292 : //RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used
293 : RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE,
294 : //RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used
295 : RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION
296 : };
297 :
298 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
299 :
300 : /**
301 : * Flush the DNS cache.
302 : */
303 : void FlushCache();
304 :
305 : private:
306 : explicit nsHostResolver(uint32_t maxCacheEntries,
307 : uint32_t defaultCacheEntryLifetime,
308 : uint32_t defaultGracePeriod);
309 : ~nsHostResolver();
310 :
311 : nsresult Init();
312 : nsresult IssueLookup(nsHostRecord *);
313 : bool GetHostToLookup(nsHostRecord **m);
314 :
315 : enum LookupStatus {
316 : LOOKUP_OK,
317 : LOOKUP_RESOLVEAGAIN,
318 : };
319 :
320 : LookupStatus OnLookupComplete(nsHostRecord *, nsresult, mozilla::net::AddrInfo *);
321 : void DeQueue(PRCList &aQ, nsHostRecord **aResult);
322 : void ClearPendingQueue(PRCList *aPendingQueue);
323 : nsresult ConditionallyCreateThread(nsHostRecord *rec);
324 :
325 : /**
326 : * Starts a new lookup in the background for entries that are in the grace
327 : * period with a failed connect or all cached entries are negative.
328 : */
329 : nsresult ConditionallyRefreshRecord(nsHostRecord *rec, const char *host);
330 :
331 : static void MoveQueue(nsHostRecord *aRec, PRCList &aDestQ);
332 :
333 : static void ThreadFunc(void *);
334 :
335 : enum {
336 : METHOD_HIT = 1,
337 : METHOD_RENEWAL = 2,
338 : METHOD_NEGATIVE_HIT = 3,
339 : METHOD_LITERAL = 4,
340 : METHOD_OVERFLOW = 5,
341 : METHOD_NETWORK_FIRST = 6,
342 : METHOD_NETWORK_SHARED = 7
343 : };
344 :
345 : uint32_t mMaxCacheEntries;
346 : uint32_t mDefaultCacheLifetime; // granularity seconds
347 : uint32_t mDefaultGracePeriod; // granularity seconds
348 : mutable Mutex mLock; // mutable so SizeOfIncludingThis can be const
349 : CondVar mIdleThreadCV;
350 : PLDHashTable mDB;
351 : PRCList mHighQ;
352 : PRCList mMediumQ;
353 : PRCList mLowQ;
354 : PRCList mEvictionQ;
355 : uint32_t mEvictionQSize;
356 : PRTime mCreationTime;
357 : PRIntervalTime mLongIdleTimeout;
358 : PRIntervalTime mShortIdleTimeout;
359 :
360 : mozilla::Atomic<bool> mShutdown;
361 : mozilla::Atomic<uint32_t> mNumIdleThreads;
362 : mozilla::Atomic<uint32_t> mThreadCount;
363 : mozilla::Atomic<uint32_t> mActiveAnyThreadCount;
364 : mozilla::Atomic<uint32_t> mPendingCount;
365 :
366 : // Set the expiration time stamps appropriately.
367 : void PrepareRecordExpiration(nsHostRecord* rec) const;
368 :
369 : public:
370 : /*
371 : * Called by the networking dashboard via the DnsService2
372 : */
373 : void GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *);
374 : };
375 :
376 : #endif // nsHostResolver_h__
|