Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/dns/nsHostResolver.h
Line
Count
Source (jump to first uncovered line)
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 "prnetdb.h"
11
#include "PLDHashTable.h"
12
#include "mozilla/CondVar.h"
13
#include "mozilla/Mutex.h"
14
#include "nsISupportsImpl.h"
15
#include "nsIDNSListener.h"
16
#include "nsIDNSService.h"
17
#include "nsTArray.h"
18
#include "GetAddrInfo.h"
19
#include "mozilla/net/DNS.h"
20
#include "mozilla/net/DashboardTypes.h"
21
#include "mozilla/Atomics.h"
22
#include "mozilla/LinkedList.h"
23
#include "mozilla/TimeStamp.h"
24
#include "mozilla/UniquePtr.h"
25
#include "nsRefPtrHashtable.h"
26
#include "nsIThreadPool.h"
27
28
class nsHostResolver;
29
class nsResolveHostCallback;
30
namespace mozilla { namespace net {
31
class TRR;
32
enum ResolverMode {
33
  MODE_NATIVEONLY, // 0 - TRR OFF (by default)
34
  MODE_PARALLEL,   // 1 - race and use the first response
35
  MODE_TRRFIRST,   // 2 - fallback to native on TRR failure
36
  MODE_TRRONLY,    // 3 - don't even fallback
37
  MODE_SHADOW,     // 4 - race for stats, but always use native result
38
  MODE_TRROFF      // 5 - identical to MODE_NATIVEONLY but explicitly selected
39
};
40
} }
41
42
0
#define TRR_DISABLED(x) (((x) == MODE_NATIVEONLY) || ((x) == MODE_TRROFF))
43
44
extern mozilla::Atomic<bool, mozilla::Relaxed> gNativeIsLocalhost;
45
46
0
#define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY  3
47
0
#define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5
48
0
#define MAX_NON_PRIORITY_REQUESTS 150
49
50
0
#define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \
51
0
                              MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY)
52
53
struct nsHostKey
54
{
55
    const nsCString host;
56
    uint16_t type;
57
    uint16_t flags;
58
    uint16_t af;
59
    bool     pb;
60
    const nsCString originSuffix;
61
    explicit nsHostKey(const nsACString& host, uint16_t  type, uint16_t flags,
62
                       uint16_t af, bool pb, const nsACString& originSuffix);
63
    bool operator==(const nsHostKey& other) const;
64
    size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
65
    PLDHashNumber Hash() const;
66
};
67
68
/**
69
 * nsHostRecord - ref counted object type stored in host resolver cache.
70
 */
71
class nsHostRecord :
72
    public mozilla::LinkedListElement<RefPtr<nsHostRecord>>,
73
    public nsHostKey
74
{
75
    typedef mozilla::Mutex Mutex;
76
77
public:
78
    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostRecord)
79
80
    /* a fully resolved host record has either a non-null |addr_info| or |addr|
81
     * field.  if |addr_info| is null, it implies that the |host| is an IP
82
     * address literal.  in which case, |addr| contains the parsed address.
83
     * otherwise, if |addr_info| is non-null, then it contains one or many
84
     * IP addresses corresponding to the given host name.  if both |addr_info|
85
     * and |addr| are null, then the given host has not yet been fully resolved.
86
     * |af| is the address family of the record we are querying for.
87
     */
88
89
    /* the lock protects |addr_info| and |addr_info_gencnt| because they
90
     * are mutable and accessed by the resolver worker thread and the
91
     * nsDNSService2 class.  |addr| doesn't change after it has been
92
     * assigned a value.  only the resolver worker thread modifies
93
     * nsHostRecord (and only in nsHostResolver::CompleteLookup);
94
     * the other threads just read it.  therefore the resolver worker
95
     * thread doesn't need to lock when reading |addr_info|.
96
     */
97
    Mutex        addr_info_lock;
98
    int          addr_info_gencnt; /* generation count of |addr_info| */
99
    mozilla::net::AddrInfo *addr_info;
100
    mozilla::UniquePtr<mozilla::net::NetAddr> addr;
101
    bool         negative;   /* True if this record is a cache of a failed lookup.
102
                                Negative cache entries are valid just like any other
103
                                (though never for more than 60 seconds), but a use
104
                                of that negative entry forces an asynchronous refresh. */
105
106
    enum ExpirationStatus {
107
        EXP_VALID,
108
        EXP_GRACE,
109
        EXP_EXPIRED,
110
    };
111
112
    ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const;
113
114
    // When the record began being valid. Used mainly for bookkeeping.
115
    mozilla::TimeStamp mValidStart;
116
117
    // When the record is no longer valid (it's time of expiration)
118
    mozilla::TimeStamp mValidEnd;
119
120
    // When the record enters its grace period. This must be before mValidEnd.
121
    // If a record is in its grace period (and not expired), it will be used
122
    // but a request to refresh it will be made.
123
    mozilla::TimeStamp mGraceStart;
124
125
    // When the lookups of this record started and their durations
126
    mozilla::TimeStamp mTrrStart;
127
    mozilla::TimeStamp mNativeStart;
128
    mozilla::TimeDuration mTrrDuration;
129
    mozilla::TimeDuration mNativeDuration;
130
131
    // Convenience function for setting the timestamps above (mValidStart,
132
    // mValidEnd, and mGraceStart). valid and grace are durations in seconds.
133
    void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid,
134
                       unsigned int grace);
135
    void CopyExpirationTimesAndFlagsFrom(const nsHostRecord *aFromHostRecord);
136
137
    // Checks if the record is usable (not expired and has a value)
138
    bool HasUsableResult(const mozilla::TimeStamp& now, uint16_t queryFlags = 0) const;
139
140
    // Mark hostrecord as not usable
141
    void Invalidate();
142
143
    // hold addr_info_lock when calling the blacklist functions
144
    bool   Blacklisted(mozilla::net::NetAddr *query);
145
    void   ResetBlacklist();
146
    void   ReportUnusable(mozilla::net::NetAddr *addr);
147
148
    size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
149
150
    enum DnsPriority {
151
        DNS_PRIORITY_LOW,
152
        DNS_PRIORITY_MEDIUM,
153
        DNS_PRIORITY_HIGH,
154
    };
155
    static DnsPriority GetPriority(uint16_t aFlags);
156
157
    bool RemoveOrRefresh(); // Mark records currently being resolved as needed
158
                            // to resolve again.
159
0
    bool IsTRR() { return mTRRUsed; }
160
    void ResolveComplete();
161
    void Cancel();
162
163
    mozilla::net::ResolverMode mResolverMode;
164
165
    nsTArray<nsCString> mRequestByTypeResult;
166
    Mutex mRequestByTypeResultLock;
167
168
private:
169
    friend class nsHostResolver;
170
171
    explicit nsHostRecord(const nsHostKey& key);
172
    mozilla::LinkedList<RefPtr<nsResolveHostCallback>> mCallbacks;
173
    nsAutoPtr<mozilla::net::AddrInfo> mFirstTRR; // partial TRR storage
174
    nsresult mFirstTRRresult;
175
176
    uint16_t  mResolving;  // counter of outstanding resolving calls
177
    uint8_t   mTRRSuccess; // number of successful TRR responses
178
    uint8_t   mNativeSuccess; // number of native lookup responses
179
180
    uint16_t    mNative : 1;     // true if this record is being resolved "natively",
181
                                 // which means that it is either on the pending queue
182
                                 // or owned by one of the worker threads. */
183
    uint16_t    mTRRUsed : 1;    // TRR was used on this record
184
    uint16_t    mNativeUsed : 1;
185
    uint16_t    onQueue : 1;    // true if pending and on the queue (not yet given to getaddrinfo())
186
    uint16_t    usingAnyThread : 1; // true if off queue and contributing to mActiveAnyThreadCount
187
    uint16_t    mDoomed : 1;    // explicitly expired
188
    uint16_t    mDidCallbacks : 1;
189
    uint16_t    mGetTtl : 1;
190
191
    // when the results from this resolve is returned, it is not to be
192
    // trusted, but instead a new resolve must be made!
193
    uint16_t    mResolveAgain : 1;
194
195
    enum {
196
        INIT, STARTED, OK, FAILED
197
    } mTrrAUsed, mTrrAAAAUsed;
198
199
    Mutex mTrrLock; // lock when accessing the mTrrA[AAA] pointers
200
    RefPtr<mozilla::net::TRR> mTrrA;
201
    RefPtr<mozilla::net::TRR> mTrrAAAA;
202
    RefPtr<mozilla::net::TRR> mTrrTxt;
203
204
    // The number of times ReportUnusable() has been called in the record's
205
    // lifetime.
206
    uint32_t mBlacklistedCount;
207
208
    // a list of addresses associated with this record that have been reported
209
    // as unusable. the list is kept as a set of strings to make it independent
210
    // of gencnt.
211
    nsTArray<nsCString> mBlacklistedItems;
212
213
   ~nsHostRecord();
214
};
215
216
/**
217
 * This class is used to notify listeners when a ResolveHost operation is
218
 * complete. Classes that derive it must implement threadsafe nsISupports
219
 * to be able to use RefPtr with this class.
220
 */
221
class nsResolveHostCallback
222
    : public mozilla::LinkedListElement<RefPtr<nsResolveHostCallback>>
223
    , public nsISupports
224
{
225
public:
226
    /**
227
     * OnResolveHostComplete
228
     *
229
     * this function is called to complete a host lookup initiated by
230
     * nsHostResolver::ResolveHost.  it may be invoked recursively from
231
     * ResolveHost or on an unspecified background thread.
232
     *
233
     * NOTE: it is the responsibility of the implementor of this method
234
     * to handle the callback in a thread safe manner.
235
     *
236
     * @param resolver
237
     *        nsHostResolver object associated with this result
238
     * @param record
239
     *        the host record containing the results of the lookup
240
     * @param status
241
     *        if successful, |record| contains non-null results
242
     */
243
    virtual void OnResolveHostComplete(nsHostResolver *resolver,
244
                                       nsHostRecord   *record,
245
                                       nsresult        status) = 0;
246
    /**
247
     * EqualsAsyncListener
248
     *
249
     * Determines if the listener argument matches the listener member var.
250
     * For subclasses not implementing a member listener, should return false.
251
     * For subclasses having a member listener, the function should check if
252
     * they are the same.  Used for cases where a pointer to an object
253
     * implementing nsResolveHostCallback is unknown, but a pointer to
254
     * the original listener is known.
255
     *
256
     * @param aListener
257
     *        nsIDNSListener object associated with the original request
258
     */
259
    virtual bool EqualsAsyncListener(nsIDNSListener *aListener) = 0;
260
261
    virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0;
262
protected:
263
0
    virtual ~nsResolveHostCallback() = default;
264
};
265
266
class AHostResolver
267
{
268
public:
269
6
    AHostResolver() = default;
270
0
    virtual ~AHostResolver() = default;
271
    NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
272
273
     enum LookupStatus {
274
        LOOKUP_OK,
275
        LOOKUP_RESOLVEAGAIN,
276
    };
277
278
    virtual LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) = 0;
279
    virtual LookupStatus CompleteLookupByType(nsHostRecord *, nsresult,
280
                                              const nsTArray<nsCString> *aResult,
281
                                              uint32_t aTtl, bool pb) = 0;
282
    virtual nsresult GetHostRecord(const nsACString &host,
283
                                   uint16_t flags, uint16_t af, bool pb,
284
                                   const nsCString &originSuffix,
285
                                   nsHostRecord **result)
286
0
    {
287
0
        return NS_ERROR_FAILURE;
288
0
    }
289
    virtual nsresult TrrLookup_unlocked(nsHostRecord *, mozilla::net::TRR *pushedTRR = nullptr)
290
0
    {
291
0
        return NS_ERROR_FAILURE;
292
0
    }
293
};
294
295
/**
296
 * nsHostResolver - an asynchronous host name resolver.
297
 */
298
class nsHostResolver : public nsISupports, public AHostResolver
299
{
300
    typedef mozilla::CondVar CondVar;
301
    typedef mozilla::Mutex Mutex;
302
303
public:
304
    NS_DECL_THREADSAFE_ISUPPORTS
305
306
    /**
307
     * creates an addref'd instance of a nsHostResolver object.
308
     */
309
    static nsresult Create(uint32_t maxCacheEntries, // zero disables cache
310
                           uint32_t defaultCacheEntryLifetime, // seconds
311
                           uint32_t defaultGracePeriod, // seconds
312
                           nsHostResolver **resolver);
313
314
    /**
315
     * Set (new) cache limits.
316
     */
317
    void SetCacheLimits(uint32_t maxCacheEntries, // zero disables cache
318
                        uint32_t defaultCacheEntryLifetime, // seconds
319
                        uint32_t defaultGracePeriod); // seconds
320
321
    /**
322
     * puts the resolver in the shutdown state, which will cause any pending
323
     * callbacks to be detached.  any future calls to ResolveHost will fail.
324
     */
325
    void Shutdown();
326
327
    /**
328
     * resolve the given hostname and originAttributes asynchronously.  the caller
329
     * can synthesize a synchronous host lookup using a lock and a cvar.  as noted
330
     * above the callback will occur re-entrantly from an unspecified thread.  the
331
     * host lookup cannot be canceled (cancelation can be layered above this by
332
     * having the callback implementation return without doing anything).
333
     */
334
    nsresult ResolveHost(const nsACString &hostname,
335
                         uint16_t                         type,
336
                         const mozilla::OriginAttributes &aOriginAttributes,
337
                         uint16_t                         flags,
338
                         uint16_t                         af,
339
                         nsResolveHostCallback           *callback);
340
341
    /**
342
     * removes the specified callback from the nsHostRecord for the given
343
     * hostname, originAttributes, flags, and address family.  these parameters
344
     * should correspond to the parameters passed to ResolveHost.  this function
345
     * executes the callback if the callback is still pending with the given status.
346
     */
347
    void DetachCallback(const nsACString &hostname,
348
                        uint16_t                         type,
349
                        const mozilla::OriginAttributes &aOriginAttributes,
350
                        uint16_t                         flags,
351
                        uint16_t                         af,
352
                        nsResolveHostCallback           *callback,
353
                        nsresult                         status);
354
355
    /**
356
     * Cancels an async request associated with the hostname, originAttributes, flags,
357
     * address family and listener.  Cancels first callback found which matches
358
     * these criteria.  These parameters should correspond to the parameters
359
     * passed to ResolveHost.  If this is the last callback associated with the
360
     * host record, it is removed from any request queues it might be on.
361
     */
362
    void CancelAsyncRequest(const nsACString &host,
363
                            uint16_t                         type,
364
                            const mozilla::OriginAttributes &aOriginAttributes,
365
                            uint16_t                         flags,
366
                            uint16_t                         af,
367
                            nsIDNSListener                  *aListener,
368
                            nsresult                         status);
369
    /**
370
     * values for the flags parameter passed to ResolveHost and DetachCallback
371
     * that may be bitwise OR'd together.
372
     *
373
     * NOTE: in this implementation, these flags correspond exactly in value
374
     *       to the flags defined on nsIDNSService.
375
     */
376
    enum {
377
        RES_BYPASS_CACHE = nsIDNSService::RESOLVE_BYPASS_CACHE,
378
        RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME,
379
        RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM,
380
        RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW,
381
        RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE,
382
        //RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used
383
        RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE,
384
        //RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used
385
        RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION,
386
        RES_DISABLE_TRR = nsIDNSService::RESOLVE_DISABLE_TRR,
387
        RES_REFRESH_CACHE = nsIDNSService::RESOLVE_REFRESH_CACHE
388
    };
389
390
    size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
391
392
    /**
393
     * Flush the DNS cache.
394
     */
395
    void FlushCache();
396
397
    LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) override;
398
    LookupStatus CompleteLookupByType(nsHostRecord *, nsresult,
399
                                      const nsTArray<nsCString> *aResult,
400
                                      uint32_t aTtl, bool pb) override;
401
    nsresult GetHostRecord(const nsACString &host,
402
                           uint16_t flags, uint16_t af, bool pb,
403
                           const nsCString &originSuffix,
404
                           nsHostRecord **result) override;
405
    nsresult TrrLookup_unlocked(nsHostRecord *, mozilla::net::TRR *pushedTRR = nullptr) override;
406
407
private:
408
   explicit nsHostResolver(uint32_t maxCacheEntries,
409
                           uint32_t defaultCacheEntryLifetime,
410
                           uint32_t defaultGracePeriod);
411
   virtual ~nsHostResolver();
412
413
    nsresult Init();
414
    // In debug builds it asserts that the element is in the list.
415
    void AssertOnQ(nsHostRecord *, mozilla::LinkedList<RefPtr<nsHostRecord>>&);
416
    mozilla::net::ResolverMode Mode();
417
    nsresult NativeLookup(nsHostRecord *);
418
    nsresult TrrLookup(nsHostRecord *, mozilla::net::TRR *pushedTRR = nullptr);
419
420
    // Kick-off a name resolve operation, using native resolver and/or TRR
421
    nsresult NameLookup(nsHostRecord *);
422
    bool     GetHostToLookup(nsHostRecord **m);
423
424
    // Removes the first element from the list and returns it AddRef-ed in aResult
425
    // Should not be called for an empty linked list.
426
    void     DeQueue(mozilla::LinkedList<RefPtr<nsHostRecord>>& aQ, nsHostRecord **aResult);
427
    // Cancels host records in the pending queue and also
428
    // calls CompleteLookup with the NS_ERROR_ABORT result code.
429
    void     ClearPendingQueue(mozilla::LinkedList<RefPtr<nsHostRecord>>& aPendingQ);
430
    nsresult ConditionallyCreateThread(nsHostRecord *rec);
431
432
    /**
433
     * Starts a new lookup in the background for entries that are in the grace
434
     * period with a failed connect or all cached entries are negative.
435
     */
436
    nsresult ConditionallyRefreshRecord(nsHostRecord *rec, const nsACString &host);
437
438
    void AddToEvictionQ(nsHostRecord* rec);
439
440
    void ThreadFunc();
441
442
    enum {
443
        METHOD_HIT = 1,
444
        METHOD_RENEWAL = 2,
445
        METHOD_NEGATIVE_HIT = 3,
446
        METHOD_LITERAL = 4,
447
        METHOD_OVERFLOW = 5,
448
        METHOD_NETWORK_FIRST = 6,
449
        METHOD_NETWORK_SHARED = 7
450
    };
451
452
    uint32_t      mMaxCacheEntries;
453
    uint32_t      mDefaultCacheLifetime; // granularity seconds
454
    uint32_t      mDefaultGracePeriod; // granularity seconds
455
    mutable Mutex mLock;    // mutable so SizeOfIncludingThis can be const
456
    CondVar       mIdleTaskCV;
457
    nsRefPtrHashtable<nsGenericHashKey<nsHostKey>, nsHostRecord> mRecordDB;
458
    mozilla::LinkedList<RefPtr<nsHostRecord>> mHighQ;
459
    mozilla::LinkedList<RefPtr<nsHostRecord>> mMediumQ;
460
    mozilla::LinkedList<RefPtr<nsHostRecord>> mLowQ;
461
    mozilla::LinkedList<RefPtr<nsHostRecord>> mEvictionQ;
462
    uint32_t      mEvictionQSize;
463
    PRTime        mCreationTime;
464
    mozilla::TimeDuration mLongIdleTimeout;
465
    mozilla::TimeDuration mShortIdleTimeout;
466
467
    RefPtr<nsIThreadPool> mResolverThreads;
468
469
    mozilla::Atomic<bool>     mShutdown;
470
    mozilla::Atomic<uint32_t> mNumIdleTasks;
471
    mozilla::Atomic<uint32_t> mActiveTaskCount;
472
    mozilla::Atomic<uint32_t> mActiveAnyThreadCount;
473
    mozilla::Atomic<uint32_t> mPendingCount;
474
475
    // Set the expiration time stamps appropriately.
476
    void PrepareRecordExpiration(nsHostRecord* rec) const;
477
478
public:
479
    /*
480
     * Called by the networking dashboard via the DnsService2
481
     */
482
    void GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *);
483
};
484
485
#endif // nsHostResolver_h__