1 /* vim:set ts=4 sw=2 sts=2 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/. */
6 #ifndef nsHostRecord_h__
7 #define nsHostRecord_h__
9 #include "mozilla/AtomicBitfields.h"
10 #include "mozilla/DataMutex.h"
11 #include "mozilla/LinkedList.h"
12 #include "mozilla/net/HTTPSSVC.h"
13 #include "nsIDNSService.h"
14 #include "nsIDNSByTypeRecord.h"
15 #include "PLDHashTable.h"
16 #include "nsITRRSkipReason.h"
23 class HostRecordQueue
;
27 } // namespace mozilla
30 * This class is used to notify listeners when a ResolveHost operation is
31 * complete. Classes that derive it must implement threadsafe nsISupports
32 * to be able to use RefPtr with this class.
34 class nsResolveHostCallback
35 : public mozilla::LinkedListElement
<RefPtr
<nsResolveHostCallback
>>,
39 * OnResolveHostComplete
41 * this function is called to complete a host lookup initiated by
42 * nsHostResolver::ResolveHost. it may be invoked recursively from
43 * ResolveHost or on an unspecified background thread.
45 * NOTE: it is the responsibility of the implementor of this method
46 * to handle the callback in a thread safe manner.
49 * nsHostResolver object associated with this result
51 * the host record containing the results of the lookup
53 * if successful, |record| contains non-null results
55 virtual void OnResolveHostComplete(nsHostResolver
* resolver
,
56 nsHostRecord
* record
, nsresult status
) = 0;
60 * Determines if the listener argument matches the listener member var.
61 * For subclasses not implementing a member listener, should return false.
62 * For subclasses having a member listener, the function should check if
63 * they are the same. Used for cases where a pointer to an object
64 * implementing nsResolveHostCallback is unknown, but a pointer to
65 * the original listener is known.
68 * nsIDNSListener object associated with the original request
70 virtual bool EqualsAsyncListener(nsIDNSListener
* aListener
) = 0;
72 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf
) const = 0;
75 virtual ~nsResolveHostCallback() = default;
80 const nsCString mTrrServer
;
82 nsIDNSService::DNSFlags flags
= nsIDNSService::RESOLVE_DEFAULT_FLAGS
;
85 const nsCString originSuffix
;
86 explicit nsHostKey(const nsACString
& host
, const nsACString
& aTrrServer
,
87 uint16_t type
, nsIDNSService::DNSFlags flags
, uint16_t af
,
88 bool pb
, const nsACString
& originSuffix
);
89 bool operator==(const nsHostKey
& other
) const;
90 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
91 PLDHashNumber
Hash() const;
95 * nsHostRecord - ref counted object type stored in host resolver cache.
97 class nsHostRecord
: public mozilla::LinkedListElement
<RefPtr
<nsHostRecord
>>,
100 using TRRSkippedReason
= mozilla::net::TRRSkippedReason
;
103 NS_DECL_THREADSAFE_ISUPPORTS
105 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
109 // Returns the TRR mode encoded by the flags
110 nsIRequest::TRRMode
TRRMode();
112 // Records the first reason that caused TRR to be skipped or to fail.
113 void RecordReason(TRRSkippedReason reason
) {
114 if (mTRRSkippedReason
== TRRSkippedReason::TRR_UNSET
) {
115 mTRRSkippedReason
= reason
;
120 DNS_PRIORITY_LOW
= nsIDNSService::RESOLVE_PRIORITY_LOW
,
121 DNS_PRIORITY_MEDIUM
= nsIDNSService::RESOLVE_PRIORITY_MEDIUM
,
126 friend class nsHostResolver
;
127 friend class mozilla::net::HostRecordQueue
;
128 friend class mozilla::net::TRR
;
129 friend class mozilla::net::TRRQuery
;
131 explicit nsHostRecord(const nsHostKey
& key
);
132 virtual ~nsHostRecord() = default;
134 // Mark hostrecord as not usable
137 enum ExpirationStatus
{
143 ExpirationStatus
CheckExpiration(const mozilla::TimeStamp
& now
) const;
145 // Convenience function for setting the timestamps above (mValidStart,
146 // mValidEnd, and mGraceStart). valid and grace are durations in seconds.
147 void SetExpiration(const mozilla::TimeStamp
& now
, unsigned int valid
,
149 void CopyExpirationTimesAndFlagsFrom(const nsHostRecord
* aFromHostRecord
);
151 // Checks if the record is usable (not expired and has a value)
152 bool HasUsableResult(const mozilla::TimeStamp
& now
,
153 nsIDNSService::DNSFlags queryFlags
=
154 nsIDNSService::RESOLVE_DEFAULT_FLAGS
) const;
156 static DnsPriority
GetPriority(nsIDNSService::DNSFlags aFlags
);
158 virtual void Cancel();
159 virtual bool HasUsableResultInternal(
160 const mozilla::TimeStamp
& now
,
161 nsIDNSService::DNSFlags queryFlags
) const = 0;
162 virtual bool RefreshForNegativeResponse() const { return true; }
164 mozilla::LinkedList
<RefPtr
<nsResolveHostCallback
>> mCallbacks
;
166 bool IsAddrRecord() const {
167 return type
== nsIDNSService::RESOLVE_TYPE_DEFAULT
;
170 virtual void Reset() {
171 mTRRSkippedReason
= TRRSkippedReason::TRR_UNSET
;
172 mFirstTRRSkippedReason
= TRRSkippedReason::TRR_UNSET
;
175 mNativeSuccess
= false;
178 virtual void OnCompleteLookup() {}
180 virtual void ResolveComplete() = 0;
182 // When the record began being valid. Used mainly for bookkeeping.
183 mozilla::TimeStamp mValidStart
;
185 // When the record is no longer valid (it's time of expiration)
186 mozilla::TimeStamp mValidEnd
;
188 // When the record enters its grace period. This must be before mValidEnd.
189 // If a record is in its grace period (and not expired), it will be used
190 // but a request to refresh it will be made.
191 mozilla::TimeStamp mGraceStart
;
193 mozilla::TimeDuration mTrrDuration
;
195 mozilla::Atomic
<uint32_t, mozilla::Relaxed
> mTtl
{0};
197 // The computed TRR mode that is actually used by the request.
198 // It is set in nsHostResolver::NameLookup and is based on the mode of the
199 // default resolver and the TRRMode encoded in the flags.
200 // The mode into account if the TRR service is disabled,
201 // parental controls are on, domain matches exclusion list, etc.
202 mozilla::Atomic
<nsIRequest::TRRMode
> mEffectiveTRRMode
{
203 nsIRequest::TRR_DEFAULT_MODE
};
205 mozilla::Atomic
<TRRSkippedReason
> mTRRSkippedReason
{
206 TRRSkippedReason::TRR_UNSET
};
207 TRRSkippedReason mFirstTRRSkippedReason
= TRRSkippedReason::TRR_UNSET
;
209 mozilla::DataMutex
<RefPtr
<mozilla::net::TRRQuery
>> mTRRQuery
;
211 // counter of outstanding resolving calls
212 mozilla::Atomic
<int32_t> mResolving
{0};
214 // Number of times we've attempted TRR. Reset when we refresh.
215 // TRR is attempted at most twice - first attempt and retry.
216 mozilla::Atomic
<int32_t> mTrrAttempts
{0};
218 // True if this record is a cache of a failed lookup. Negative cache
219 // entries are valid just like any other (though never for more than 60
220 // seconds), but a use of that negative entry forces an asynchronous refresh.
221 bool negative
= false;
223 // Explicitly expired
224 bool mDoomed
= false;
226 // Whether this is resolved by TRR successfully or not.
227 bool mTRRSuccess
= false;
229 // Whether this is resolved by native resolver successfully or not.
230 bool mNativeSuccess
= false;
232 // When the lookups of this record started and their durations
233 mozilla::TimeStamp mNativeStart
;
234 mozilla::TimeDuration mNativeDuration
;
237 MOZ_ATOMIC_BITFIELDS(mAtomicBitfields
, 8, (
238 // true if this record is being resolved "natively", which means that
239 // it is either on the pending queue or owned by one of the worker threads.
240 (uint16_t, Native
, 1),
241 (uint16_t, NativeUsed
, 1),
242 // true if off queue and contributing to mActiveAnyThreadCount
243 (uint16_t, UsingAnyThread
, 1),
244 (uint16_t, GetTtl
, 1),
245 (uint16_t, ResolveAgain
, 1)
250 // b020e996-f6ab-45e5-9bf5-1da71dd0053a
251 #define ADDRHOSTRECORD_IID \
253 0xb020e996, 0xf6ab, 0x45e5, { \
254 0x9b, 0xf5, 0x1d, 0xa7, 0x1d, 0xd0, 0x05, 0x3a \
258 class AddrHostRecord final
: public nsHostRecord
{
259 using Mutex
= mozilla::Mutex
;
260 using DNSResolverType
= mozilla::net::DNSResolverType
;
263 NS_DECLARE_STATIC_IID_ACCESSOR(ADDRHOSTRECORD_IID
)
264 NS_DECL_ISUPPORTS_INHERITED
266 /* a fully resolved host record has either a non-null |addr_info| or |addr|
267 * field. if |addr_info| is null, it implies that the |host| is an IP
268 * address literal. in which case, |addr| contains the parsed address.
269 * otherwise, if |addr_info| is non-null, then it contains one or many
270 * IP addresses corresponding to the given host name. if both |addr_info|
271 * and |addr| are null, then the given host has not yet been fully resolved.
272 * |af| is the address family of the record we are querying for.
275 /* the lock protects |addr_info| and |addr_info_gencnt| because they
276 * are mutable and accessed by the resolver worker thread and the
277 * nsDNSService2 class. |addr| doesn't change after it has been
278 * assigned a value. only the resolver worker thread modifies
279 * nsHostRecord (and only in nsHostResolver::CompleteLookup);
280 * the other threads just read it. therefore the resolver worker
281 * thread doesn't need to lock when reading |addr_info|.
283 Mutex addr_info_lock MOZ_UNANNOTATED
{"AddrHostRecord.addr_info_lock"};
284 // generation count of |addr_info|
285 int addr_info_gencnt
= 0;
286 RefPtr
<mozilla::net::AddrInfo
> addr_info
;
287 mozilla::UniquePtr
<mozilla::net::NetAddr
> addr
;
289 // hold addr_info_lock when calling the blocklist functions
290 bool Blocklisted(const mozilla::net::NetAddr
* query
);
291 void ResetBlocklist();
292 void ReportUnusable(const mozilla::net::NetAddr
* aAddress
);
294 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const override
;
296 nsIRequest::TRRMode
EffectiveTRRMode() const { return mEffectiveTRRMode
; }
297 nsITRRSkipReason::value
TrrSkipReason() const { return mTRRSkippedReason
; }
299 nsresult
GetTtl(uint32_t* aResult
);
302 friend class nsHostResolver
;
303 friend class mozilla::net::HostRecordQueue
;
304 friend class mozilla::net::TRR
;
305 friend class mozilla::net::TRRQuery
;
307 explicit AddrHostRecord(const nsHostKey
& key
);
310 // Checks if the record is usable (not expired and has a value)
311 bool HasUsableResultInternal(
312 const mozilla::TimeStamp
& now
,
313 nsIDNSService::DNSFlags queryFlags
) const override
;
315 bool RemoveOrRefresh(bool aTrrToo
); // Mark records currently being resolved
316 // as needed to resolve again.
318 // Saves the skip reason of a first-attempt TRR lookup and clears
319 // it to prepare for a retry attempt.
320 void NotifyRetryingTrr();
322 static DnsPriority
GetPriority(nsIDNSService::DNSFlags aFlags
);
324 // true if pending and on the queue (not yet given to getaddrinfo())
325 bool onQueue() { return LoadNative() && isInList(); }
327 virtual void Reset() override
{
328 nsHostRecord::Reset();
329 StoreNativeUsed(false);
330 mResolverType
= DNSResolverType::Native
;
333 virtual void OnCompleteLookup() override
{
334 nsHostRecord::OnCompleteLookup();
335 // This should always be cleared when a request is completed.
339 void ResolveComplete() override
;
341 // TRR was used on this record
342 mozilla::Atomic
<DNSResolverType
> mResolverType
{DNSResolverType::Native
};
344 // The number of times ReportUnusable() has been called in the record's
346 uint32_t mUnusableCount
= 0;
348 // a list of addresses associated with this record that have been reported
349 // as unusable. the list is kept as a set of strings to make it independent
351 nsTArray
<nsCString
> mUnusableItems
;
354 NS_DEFINE_STATIC_IID_ACCESSOR(AddrHostRecord
, ADDRHOSTRECORD_IID
)
356 // 77b786a7-04be-44f2-987c-ab8aa96676e0
357 #define TYPEHOSTRECORD_IID \
359 0x77b786a7, 0x04be, 0x44f2, { \
360 0x98, 0x7c, 0xab, 0x8a, 0xa9, 0x66, 0x76, 0xe0 \
364 class TypeHostRecord final
: public nsHostRecord
,
365 public nsIDNSTXTRecord
,
366 public nsIDNSHTTPSSVCRecord
,
367 public mozilla::net::DNSHTTPSSVCRecordBase
{
369 NS_DECLARE_STATIC_IID_ACCESSOR(TYPEHOSTRECORD_IID
)
370 NS_DECL_ISUPPORTS_INHERITED
371 NS_DECL_NSIDNSTXTRECORD
372 NS_DECL_NSIDNSHTTPSSVCRECORD
374 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const override
;
376 mozilla::net::TypeRecordResultType
GetResults();
379 friend class nsHostResolver
;
380 friend class mozilla::net::TRR
;
381 friend class mozilla::net::TRRQuery
;
383 explicit TypeHostRecord(const nsHostKey
& key
);
386 // Checks if the record is usable (not expired and has a value)
387 bool HasUsableResultInternal(
388 const mozilla::TimeStamp
& now
,
389 nsIDNSService::DNSFlags queryFlags
) const override
;
390 bool RefreshForNegativeResponse() const override
;
392 void ResolveComplete() override
;
394 mozilla::net::TypeRecordResultType mResults
= AsVariant(mozilla::Nothing());
395 mozilla::Mutex mResultsLock MOZ_UNANNOTATED
{"TypeHostRecord.mResultsLock"};
397 mozilla::Maybe
<nsCString
> mOriginHost
;
398 bool mAllRecordsExcluded
= false;
401 NS_DEFINE_STATIC_IID_ACCESSOR(TypeHostRecord
, TYPEHOSTRECORD_IID
)
403 static inline bool IsHighPriority(nsIDNSService::DNSFlags flags
) {
404 return !(flags
& (nsHostRecord::DNS_PRIORITY_LOW
|
405 nsHostRecord::DNS_PRIORITY_MEDIUM
));
408 static inline bool IsMediumPriority(nsIDNSService::DNSFlags flags
) {
409 return flags
& nsHostRecord::DNS_PRIORITY_MEDIUM
;
412 static inline bool IsLowPriority(nsIDNSService::DNSFlags flags
) {
413 return flags
& nsHostRecord::DNS_PRIORITY_LOW
;
416 #endif // nsHostRecord_h__