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