summaryrefslogtreecommitdiffstats
path: root/netwerk/dns/nsHostResolver.h
blob: 798d0d00656125a21bafa0d11d9a8a9c43d73764 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
/* vim:set ts=4 sw=2 sts=2 et cin: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsHostResolver_h__
#define nsHostResolver_h__

#include "nscore.h"
#include "prnetdb.h"
#include "PLDHashTable.h"
#include "mozilla/CondVar.h"
#include "mozilla/DataMutex.h"
#include "mozilla/Mutex.h"
#include "nsISupportsImpl.h"
#include "nsIDNSListener.h"
#include "nsIDNSService.h"
#include "nsTArray.h"
#include "GetAddrInfo.h"
#include "mozilla/net/DNS.h"
#include "mozilla/net/DashboardTypes.h"
#include "mozilla/AtomicBitfields.h"
#include "mozilla/Atomics.h"
#include "mozilla/LinkedList.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "nsRefPtrHashtable.h"
#include "nsIThreadPool.h"
#include "mozilla/net/NetworkConnectivityService.h"
#include "nsIDNSByTypeRecord.h"
#include "mozilla/net/DNSByTypeRecord.h"
#include "mozilla/Maybe.h"

class nsHostResolver;
class nsResolveHostCallback;
namespace mozilla {
namespace net {
class TRR;
class TRRQuery;
enum ResolverMode {
  MODE_NATIVEONLY,  // 0 - TRR OFF (by default)
  MODE_RESERVED1,   // 1 - Reserved value. Used to be parallel resolve.
  MODE_TRRFIRST,    // 2 - fallback to native on TRR failure
  MODE_TRRONLY,     // 3 - don't even fallback
  MODE_RESERVED4,   // 4 - Reserved value. Used to be race TRR with native.
  MODE_TRROFF       // 5 - identical to MODE_NATIVEONLY but explicitly selected
};
}  // namespace net
}  // namespace mozilla

#define TRR_DISABLED(x) (((x) == MODE_NATIVEONLY) || ((x) == MODE_TRROFF))

extern mozilla::Atomic<bool, mozilla::Relaxed> gNativeIsLocalhost;

#define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 3
#define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5
#define MAX_NON_PRIORITY_REQUESTS 150

#define MAX_RESOLVER_THREADS               \
  (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \
   MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY)

struct nsHostKey {
  const nsCString host;
  const nsCString mTrrServer;
  uint16_t type;
  uint16_t flags;
  uint16_t af;
  bool pb;
  const nsCString originSuffix;
  explicit nsHostKey(const nsACString& host, const nsACString& aTrrServer,
                     uint16_t type, uint16_t flags, uint16_t af, bool pb,
                     const nsACString& originSuffix);
  bool operator==(const nsHostKey& other) const;
  size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
  PLDHashNumber Hash() const;
};

/**
 * nsHostRecord - ref counted object type stored in host resolver cache.
 */
class nsHostRecord : public mozilla::LinkedListElement<RefPtr<nsHostRecord>>,
                     public nsHostKey,
                     public nsISupports {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS

  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    return 0;
  }

  // Returns the TRR mode encoded by the flags
  nsIRequest::TRRMode TRRMode();

  // IMPORTANT: when adding new values, always add them to the end, otherwise
  // it will mess up telemetry.
  enum TRRSkippedReason : uint32_t {
    TRR_UNSET = 0,
    TRR_OK = 1,           // Only set when we actually got a positive TRR result
    TRR_NO_GSERVICE = 2,  // no gService
    TRR_PARENTAL_CONTROL = 3,         // parental control is on
    TRR_OFF_EXPLICIT = 4,             // user has set mode5
    TRR_REQ_MODE_DISABLED = 5,        // request  has disabled flags set
    TRR_MODE_NOT_ENABLED = 6,         // mode0
    TRR_FAILED = 7,                   // unknown failure
    TRR_MODE_UNHANDLED_DEFAULT = 8,   // Unhandled case in ComputeEffectiveMode
    TRR_MODE_UNHANDLED_DISABLED = 9,  // Unhandled case in ComputeEffectiveMode
    TRR_DISABLED_FLAG = 10,           // the DISABLE_TRR flag was set
    TRR_TIMEOUT = 11,                 // the TRR channel timed out
    TRR_CHANNEL_DNS_FAIL = 12,        // DoH server name failed to resolve
    TRR_IS_OFFLINE = 13,              // The browser is offline/no interfaces up
    TRR_NOT_CONFIRMED = 14,           // TRR confirmation is not done yet
    TRR_DID_NOT_MAKE_QUERY = 15,  // TrrLookup exited without doing a TRR query
    TRR_UNKNOWN_CHANNEL_FAILURE = 16,  // unknown channel failure reason
    TRR_HOST_BLOCKED_TEMPORARY = 17,   // host blocklisted
    TRR_SEND_FAILED = 18,          // The call to TRR::SendHTTPRequest failed
    TRR_NET_RESET = 19,            // NS_ERROR_NET_RESET
    TRR_NET_TIMEOUT = 20,          // NS_ERROR_NET_TIMEOUT
    TRR_NET_REFUSED = 21,          // NS_ERROR_CONNECTION_REFUSED
    TRR_NET_INTERRUPT = 22,        // NS_ERROR_NET_INTERRUPT
    TRR_NET_INADEQ_SEQURITY = 23,  // NS_ERROR_NET_INADEQUATE_SECURITY
    TRR_NO_ANSWERS = 24,           // TRR returned no answers
    TRR_DECODE_FAILED = 25,        // DohDecode failed
    TRR_EXCLUDED = 26,             // ExcludedFromTRR
    TRR_SERVER_RESPONSE_ERR = 27,  // Server responded with non-200 code
    TRR_RCODE_FAIL = 28,           // DNS response contains a non-NOERROR rcode
    TRR_NO_CONNECTIVITY = 29,      // Not confirmed because of no connectivity
  };

  // Records the first reason that caused TRR to be skipped or to fail.
  void RecordReason(TRRSkippedReason reason) {
    if (mTRRTRRSkippedReason == TRR_UNSET) {
      mTRRTRRSkippedReason = reason;
    }
  }

 protected:
  friend class nsHostResolver;
  friend class mozilla::net::TRR;
  friend class mozilla::net::TRRQuery;

  explicit nsHostRecord(const nsHostKey& key);
  virtual ~nsHostRecord() = default;

  // Mark hostrecord as not usable
  void Invalidate();

  enum ExpirationStatus {
    EXP_VALID,
    EXP_GRACE,
    EXP_EXPIRED,
  };

  ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const;

  // Convenience function for setting the timestamps above (mValidStart,
  // mValidEnd, and mGraceStart). valid and grace are durations in seconds.
  void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid,
                     unsigned int grace);
  void CopyExpirationTimesAndFlagsFrom(const nsHostRecord* aFromHostRecord);

  // Checks if the record is usable (not expired and has a value)
  bool HasUsableResult(const mozilla::TimeStamp& now,
                       uint16_t queryFlags = 0) const;

  enum DnsPriority {
    DNS_PRIORITY_LOW,
    DNS_PRIORITY_MEDIUM,
    DNS_PRIORITY_HIGH,
  };
  static DnsPriority GetPriority(uint16_t aFlags);

  virtual void Cancel();
  virtual bool HasUsableResultInternal() const { return false; }

  mozilla::LinkedList<RefPtr<nsResolveHostCallback>> mCallbacks;

  bool IsAddrRecord() const {
    return type == nsIDNSService::RESOLVE_TYPE_DEFAULT;
  }

  // When the record began being valid. Used mainly for bookkeeping.
  mozilla::TimeStamp mValidStart;

  // When the record is no longer valid (it's time of expiration)
  mozilla::TimeStamp mValidEnd;

  // When the record enters its grace period. This must be before mValidEnd.
  // If a record is in its grace period (and not expired), it will be used
  // but a request to refresh it will be made.
  mozilla::TimeStamp mGraceStart;

  // The computed TRR mode that is actually used by the request.
  // It is set in nsHostResolver::NameLookup and is based on the mode of the
  // default resolver and the TRRMode encoded in the flags.
  // The mode into account if the TRR service is disabled,
  // parental controls are on, domain matches exclusion list, etc.
  nsIRequest::TRRMode mEffectiveTRRMode;

  TRRSkippedReason mTRRTRRSkippedReason = TRR_UNSET;
  TRRSkippedReason mTRRAFailReason = TRR_UNSET;
  TRRSkippedReason mTRRAAAAFailReason = TRR_UNSET;

  mozilla::DataMutex<RefPtr<mozilla::net::TRRQuery>> mTRRQuery;

  mozilla::Atomic<int32_t>
      mResolving;  // counter of outstanding resolving calls

  uint8_t negative : 1; /* True if this record is a cache of a failed
                           lookup.  Negative cache entries are valid just
                           like any other (though never for more than 60
                           seconds), but a use of that negative entry
                           forces an asynchronous refresh. */
  uint8_t mDoomed : 1;  // explicitly expired
};

// b020e996-f6ab-45e5-9bf5-1da71dd0053a
#define ADDRHOSTRECORD_IID                           \
  {                                                  \
    0xb020e996, 0xf6ab, 0x45e5, {                    \
      0x9b, 0xf5, 0x1d, 0xa7, 0x1d, 0xd0, 0x05, 0x3a \
    }                                                \
  }

class AddrHostRecord final : public nsHostRecord {
  typedef mozilla::Mutex Mutex;

 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(ADDRHOSTRECORD_IID)
  NS_DECL_ISUPPORTS_INHERITED

  /* a fully resolved host record has either a non-null |addr_info| or |addr|
   * field.  if |addr_info| is null, it implies that the |host| is an IP
   * address literal.  in which case, |addr| contains the parsed address.
   * otherwise, if |addr_info| is non-null, then it contains one or many
   * IP addresses corresponding to the given host name.  if both |addr_info|
   * and |addr| are null, then the given host has not yet been fully resolved.
   * |af| is the address family of the record we are querying for.
   */

  /* the lock protects |addr_info| and |addr_info_gencnt| because they
   * are mutable and accessed by the resolver worker thread and the
   * nsDNSService2 class.  |addr| doesn't change after it has been
   * assigned a value.  only the resolver worker thread modifies
   * nsHostRecord (and only in nsHostResolver::CompleteLookup);
   * the other threads just read it.  therefore the resolver worker
   * thread doesn't need to lock when reading |addr_info|.
   */
  Mutex addr_info_lock;
  int addr_info_gencnt; /* generation count of |addr_info| */
  RefPtr<mozilla::net::AddrInfo> addr_info;
  mozilla::UniquePtr<mozilla::net::NetAddr> addr;

  // hold addr_info_lock when calling the blocklist functions
  bool Blocklisted(const mozilla::net::NetAddr* query);
  void ResetBlocklist();
  void ReportUnusable(const mozilla::net::NetAddr* aAddress);

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override;

  nsIRequest::TRRMode EffectiveTRRMode() const { return mEffectiveTRRMode; }

 private:
  friend class nsHostResolver;
  friend class mozilla::net::TRR;
  friend class mozilla::net::TRRQuery;

  explicit AddrHostRecord(const nsHostKey& key);
  ~AddrHostRecord();

  // Checks if the record is usable (not expired and has a value)
  bool HasUsableResultInternal() const override;

  bool RemoveOrRefresh(bool aTrrToo);  // Mark records currently being resolved
                                       // as needed to resolve again.

  void ResolveComplete();

  enum DnsPriority {
    DNS_PRIORITY_LOW,
    DNS_PRIORITY_MEDIUM,
    DNS_PRIORITY_HIGH,
  };
  static DnsPriority GetPriority(uint16_t aFlags);

  // true if pending and on the queue (not yet given to getaddrinfo())
  bool onQueue() { return LoadNative() && isInList(); }

  // When the lookups of this record started and their durations
  mozilla::TimeStamp mTrrStart;
  mozilla::TimeStamp mNativeStart;
  mozilla::TimeDuration mTrrDuration;
  mozilla::TimeDuration mNativeDuration;

  mozilla::Atomic<bool> mTRRUsed;  // TRR was used on this record
  uint8_t mTRRSuccess;             // number of successful TRR responses
  uint8_t mNativeSuccess;          // number of native lookup responses

  // clang-format off
  MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 8, (
    // true if this record is being resolved "natively", which means that
    // it is either on the pending queue or owned by one of the worker threads.
    (uint16_t, Native, 1),
    (uint16_t, NativeUsed, 1),
    // true if off queue and contributing to mActiveAnyThreadCount
    (uint16_t, UsingAnyThread, 1),
    (uint16_t, GetTtl, 1),
    (uint16_t, ResolveAgain, 1)
  ))
  // clang-format on

  // The number of times ReportUnusable() has been called in the record's
  // lifetime.
  uint32_t mUnusableCount = 0;

  // a list of addresses associated with this record that have been reported
  // as unusable. the list is kept as a set of strings to make it independent
  // of gencnt.
  nsTArray<nsCString> mUnusableItems;
};

NS_DEFINE_STATIC_IID_ACCESSOR(AddrHostRecord, ADDRHOSTRECORD_IID)

// 77b786a7-04be-44f2-987c-ab8aa96676e0
#define TYPEHOSTRECORD_IID                           \
  {                                                  \
    0x77b786a7, 0x04be, 0x44f2, {                    \
      0x98, 0x7c, 0xab, 0x8a, 0xa9, 0x66, 0x76, 0xe0 \
    }                                                \
  }

class TypeHostRecord final : public nsHostRecord,
                             public nsIDNSTXTRecord,
                             public nsIDNSHTTPSSVCRecord,
                             public mozilla::net::DNSHTTPSSVCRecordBase {
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(TYPEHOSTRECORD_IID)
  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_NSIDNSTXTRECORD
  NS_DECL_NSIDNSHTTPSSVCRECORD

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override;
  uint32_t GetType();
  mozilla::net::TypeRecordResultType GetResults();

 private:
  friend class nsHostResolver;
  friend class mozilla::net::TRRQuery;

  explicit TypeHostRecord(const nsHostKey& key);
  ~TypeHostRecord();

  // Checks if the record is usable (not expired and has a value)
  bool HasUsableResultInternal() const override;

  bool HasUsableResult();

  mozilla::net::TypeRecordResultType mResults = AsVariant(mozilla::Nothing());
  mozilla::Mutex mResultsLock;

  // When the lookups of this record started (for telemetry).
  mozilla::TimeStamp mStart;
  bool mAllRecordsExcluded = false;
};

NS_DEFINE_STATIC_IID_ACCESSOR(TypeHostRecord, TYPEHOSTRECORD_IID)

/**
 * This class is used to notify listeners when a ResolveHost operation is
 * complete. Classes that derive it must implement threadsafe nsISupports
 * to be able to use RefPtr with this class.
 */
class nsResolveHostCallback
    : public mozilla::LinkedListElement<RefPtr<nsResolveHostCallback>>,
      public nsISupports {
 public:
  /**
   * OnResolveHostComplete
   *
   * this function is called to complete a host lookup initiated by
   * nsHostResolver::ResolveHost.  it may be invoked recursively from
   * ResolveHost or on an unspecified background thread.
   *
   * NOTE: it is the responsibility of the implementor of this method
   * to handle the callback in a thread safe manner.
   *
   * @param resolver
   *        nsHostResolver object associated with this result
   * @param record
   *        the host record containing the results of the lookup
   * @param status
   *        if successful, |record| contains non-null results
   */
  virtual void OnResolveHostComplete(nsHostResolver* resolver,
                                     nsHostRecord* record, nsresult status) = 0;
  /**
   * EqualsAsyncListener
   *
   * Determines if the listener argument matches the listener member var.
   * For subclasses not implementing a member listener, should return false.
   * For subclasses having a member listener, the function should check if
   * they are the same.  Used for cases where a pointer to an object
   * implementing nsResolveHostCallback is unknown, but a pointer to
   * the original listener is known.
   *
   * @param aListener
   *        nsIDNSListener object associated with the original request
   */
  virtual bool EqualsAsyncListener(nsIDNSListener* aListener) = 0;

  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0;

 protected:
  virtual ~nsResolveHostCallback() = default;
};

class AHostResolver {
 public:
  AHostResolver() = default;
  virtual ~AHostResolver() = default;
  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING

  enum LookupStatus {
    LOOKUP_OK,
    LOOKUP_RESOLVEAGAIN,
  };

  virtual LookupStatus CompleteLookup(
      nsHostRecord*, nsresult, mozilla::net::AddrInfo*, bool pb,
      const nsACString& aOriginsuffix,
      nsHostRecord::TRRSkippedReason aReason) = 0;
  virtual LookupStatus CompleteLookupByType(
      nsHostRecord*, nsresult, mozilla::net::TypeRecordResultType& aResult,
      uint32_t aTtl, bool pb) = 0;
  virtual nsresult GetHostRecord(const nsACString& host,
                                 const nsACString& aTrrServer, uint16_t type,
                                 uint16_t flags, uint16_t af, bool pb,
                                 const nsCString& originSuffix,
                                 nsHostRecord** result) {
    return NS_ERROR_FAILURE;
  }
  virtual nsresult TrrLookup_unlocked(nsHostRecord*,
                                      mozilla::net::TRR* pushedTRR = nullptr) {
    return NS_ERROR_FAILURE;
  }
  virtual void MaybeRenewHostRecord(nsHostRecord* aRec) {}
};

/**
 * nsHostResolver - an asynchronous host name resolver.
 */
class nsHostResolver : public nsISupports, public AHostResolver {
  using CondVar = mozilla::CondVar;
  using Mutex = mozilla::Mutex;

 public:
  NS_DECL_THREADSAFE_ISUPPORTS

  /**
   * creates an addref'd instance of a nsHostResolver object.
   */
  static nsresult Create(uint32_t maxCacheEntries,  // zero disables cache
                         uint32_t defaultCacheEntryLifetime,  // seconds
                         uint32_t defaultGracePeriod,         // seconds
                         nsHostResolver** result);

  /**
   * Set (new) cache limits.
   */
  void SetCacheLimits(uint32_t maxCacheEntries,  // zero disables cache
                      uint32_t defaultCacheEntryLifetime,  // seconds
                      uint32_t defaultGracePeriod);        // seconds

  /**
   * puts the resolver in the shutdown state, which will cause any pending
   * callbacks to be detached.  any future calls to ResolveHost will fail.
   */
  void Shutdown();

  /**
   * resolve the given hostname and originAttributes asynchronously.  the caller
   * can synthesize a synchronous host lookup using a lock and a cvar.  as noted
   * above the callback will occur re-entrantly from an unspecified thread.  the
   * host lookup cannot be canceled (cancelation can be layered above this by
   * having the callback implementation return without doing anything).
   */
  nsresult ResolveHost(const nsACString& aHost, const nsACString& trrServer,
                       uint16_t type,
                       const mozilla::OriginAttributes& aOriginAttributes,
                       uint16_t flags, uint16_t af,
                       nsResolveHostCallback* callback);

  nsHostRecord* InitRecord(const nsHostKey& key);
  mozilla::net::NetworkConnectivityService* GetNCS() { return mNCS; }

  /**
   * return a resolved hard coded loopback dns record for the specified key
   */
  already_AddRefed<nsHostRecord> InitLoopbackRecord(const nsHostKey& key,
                                                    nsresult* aRv);

  /**
   * removes the specified callback from the nsHostRecord for the given
   * hostname, originAttributes, flags, and address family.  these parameters
   * should correspond to the parameters passed to ResolveHost.  this function
   * executes the callback if the callback is still pending with the given
   * status.
   */
  void DetachCallback(const nsACString& hostname, const nsACString& trrServer,
                      uint16_t type,
                      const mozilla::OriginAttributes& aOriginAttributes,
                      uint16_t flags, uint16_t af,
                      nsResolveHostCallback* callback, nsresult status);

  /**
   * Cancels an async request associated with the hostname, originAttributes,
   * flags, address family and listener.  Cancels first callback found which
   * matches these criteria.  These parameters should correspond to the
   * parameters passed to ResolveHost.  If this is the last callback associated
   * with the host record, it is removed from any request queues it might be on.
   */
  void CancelAsyncRequest(const nsACString& host, const nsACString& trrServer,
                          uint16_t type,
                          const mozilla::OriginAttributes& aOriginAttributes,
                          uint16_t flags, uint16_t af,
                          nsIDNSListener* aListener, nsresult status);
  /**
   * values for the flags parameter passed to ResolveHost and DetachCallback
   * that may be bitwise OR'd together.
   *
   * NOTE: in this implementation, these flags correspond exactly in value
   *       to the flags defined on nsIDNSService.
   */
  enum {
    RES_BYPASS_CACHE = nsIDNSService::RESOLVE_BYPASS_CACHE,
    RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME,
    RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM,
    RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW,
    RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE,
    // RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used
    RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE,
    // RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used
    RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION,
    RES_DISABLE_TRR = nsIDNSService::RESOLVE_DISABLE_TRR,
    RES_REFRESH_CACHE = nsIDNSService::RESOLVE_REFRESH_CACHE,
    RES_IP_HINT = nsIDNSService::RESOLVE_IP_HINT
  };

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

  /**
   * Flush the DNS cache.
   */
  void FlushCache(bool aTrrToo);

  LookupStatus CompleteLookup(nsHostRecord*, nsresult, mozilla::net::AddrInfo*,
                              bool pb, const nsACString& aOriginsuffix,
                              nsHostRecord::TRRSkippedReason aReason) override;
  LookupStatus CompleteLookupByType(nsHostRecord*, nsresult,
                                    mozilla::net::TypeRecordResultType& aResult,
                                    uint32_t aTtl, bool pb) override;
  nsresult GetHostRecord(const nsACString& host, const nsACString& trrServer,
                         uint16_t type, uint16_t flags, uint16_t af, bool pb,
                         const nsCString& originSuffix,
                         nsHostRecord** result) override;
  nsresult TrrLookup_unlocked(nsHostRecord*,
                              mozilla::net::TRR* pushedTRR = nullptr) override;
  static mozilla::net::ResolverMode Mode();

  virtual void MaybeRenewHostRecord(nsHostRecord* aRec) override;

 private:
  explicit nsHostResolver(uint32_t maxCacheEntries,
                          uint32_t defaultCacheEntryLifetime,
                          uint32_t defaultGracePeriod);
  virtual ~nsHostResolver();

  nsresult Init();
  // In debug builds it asserts that the element is in the list.
  void AssertOnQ(nsHostRecord*, mozilla::LinkedList<RefPtr<nsHostRecord>>&);
  static void ComputeEffectiveTRRMode(nsHostRecord* aRec);
  nsresult NativeLookup(nsHostRecord*);
  nsresult TrrLookup(nsHostRecord*, mozilla::net::TRR* pushedTRR = nullptr);

  // Kick-off a name resolve operation, using native resolver and/or TRR
  nsresult NameLookup(nsHostRecord*);
  bool GetHostToLookup(AddrHostRecord** result);
  void MaybeRenewHostRecordLocked(nsHostRecord* aRec);

  // Removes the first element from the list and returns it AddRef-ed in aResult
  // Should not be called for an empty linked list.
  void DeQueue(mozilla::LinkedList<RefPtr<nsHostRecord>>& aQ,
               AddrHostRecord** aResult);
  // Cancels host records in the pending queue and also
  // calls CompleteLookup with the NS_ERROR_ABORT result code.
  void ClearPendingQueue(mozilla::LinkedList<RefPtr<nsHostRecord>>& aPendingQ);
  nsresult ConditionallyCreateThread(nsHostRecord* rec);

  /**
   * Starts a new lookup in the background for entries that are in the grace
   * period with a failed connect or all cached entries are negative.
   */
  nsresult ConditionallyRefreshRecord(nsHostRecord* rec,
                                      const nsACString& host);

  void AddToEvictionQ(nsHostRecord* rec);

  void ThreadFunc();

  enum {
    METHOD_HIT = 1,
    METHOD_RENEWAL = 2,
    METHOD_NEGATIVE_HIT = 3,
    METHOD_LITERAL = 4,
    METHOD_OVERFLOW = 5,
    METHOD_NETWORK_FIRST = 6,
    METHOD_NETWORK_SHARED = 7
  };

  uint32_t mMaxCacheEntries;
  uint32_t mDefaultCacheLifetime;  // granularity seconds
  uint32_t mDefaultGracePeriod;    // granularity seconds
  mutable Mutex mLock;  // mutable so SizeOfIncludingThis can be const
  CondVar mIdleTaskCV;
  nsRefPtrHashtable<nsGenericHashKey<nsHostKey>, nsHostRecord> mRecordDB;
  mozilla::LinkedList<RefPtr<nsHostRecord>> mHighQ;
  mozilla::LinkedList<RefPtr<nsHostRecord>> mMediumQ;
  mozilla::LinkedList<RefPtr<nsHostRecord>> mLowQ;
  mozilla::LinkedList<RefPtr<nsHostRecord>> mEvictionQ;
  uint32_t mEvictionQSize;
  PRTime mCreationTime;
  mozilla::TimeDuration mLongIdleTimeout;
  mozilla::TimeDuration mShortIdleTimeout;

  RefPtr<nsIThreadPool> mResolverThreads;
  RefPtr<mozilla::net::NetworkConnectivityService> mNCS;

  mozilla::Atomic<bool> mShutdown;
  mozilla::Atomic<uint32_t> mNumIdleTasks;
  mozilla::Atomic<uint32_t> mActiveTaskCount;
  mozilla::Atomic<uint32_t> mActiveAnyThreadCount;
  mozilla::Atomic<uint32_t> mPendingCount;

  // Set the expiration time stamps appropriately.
  void PrepareRecordExpirationAddrRecord(AddrHostRecord* rec) const;

 public:
  /*
   * Called by the networking dashboard via the DnsService2
   */
  void GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries>*);
};

#endif  // nsHostResolver_h__