Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / netwerk / dns / TRRQuery.cpp
blob7602f586a7102097ac04224a0b4341498a7374d0
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "TRRQuery.h"
7 #include "mozilla/StaticPrefs_network.h"
8 #include "mozilla/Telemetry.h"
9 #include "nsQueryObject.h"
10 #include "TRR.h"
11 #include "TRRService.h"
12 // Put DNSLogging.h at the end to avoid LOG being overwritten by other headers.
13 #include "DNSLogging.h"
15 namespace mozilla {
16 namespace net {
18 static already_AddRefed<AddrInfo> merge_rrset(AddrInfo* rrto,
19 AddrInfo* rrfrom) {
20 MOZ_ASSERT(rrto && rrfrom);
21 // Each of the arguments are all-IPv4 or all-IPv6 hence judging
22 // by the first element. This is true only for TRR resolutions.
23 bool isIPv6 = rrfrom->Addresses().Length() > 0 &&
24 rrfrom->Addresses()[0].raw.family == PR_AF_INET6;
26 nsTArray<NetAddr> addresses;
27 if (isIPv6) {
28 addresses = rrfrom->Addresses().Clone();
29 addresses.AppendElements(rrto->Addresses());
30 } else {
31 addresses = rrto->Addresses().Clone();
32 addresses.AppendElements(rrfrom->Addresses());
34 auto builder = rrto->Build();
35 builder.SetAddresses(std::move(addresses));
36 return builder.Finish();
39 void TRRQuery::Cancel(nsresult aStatus) {
40 MutexAutoLock trrlock(mTrrLock);
41 if (mTrrA) {
42 mTrrA->Cancel(aStatus);
44 if (mTrrAAAA) {
45 mTrrAAAA->Cancel(aStatus);
47 if (mTrrByType) {
48 mTrrByType->Cancel(aStatus);
52 void TRRQuery::MarkSendingTRR(TRR* trr, enum TrrType rectype, MutexAutoLock&) {
53 if (rectype == TRRTYPE_A) {
54 MOZ_ASSERT(!mTrrA);
55 mTrrA = trr;
56 mTrrAUsed = STARTED;
57 } else if (rectype == TRRTYPE_AAAA) {
58 MOZ_ASSERT(!mTrrAAAA);
59 mTrrAAAA = trr;
60 mTrrAAAAUsed = STARTED;
61 } else {
62 LOG(("TrrLookup called with bad type set: %d\n", rectype));
63 MOZ_ASSERT(0);
67 void TRRQuery::PrepareQuery(enum TrrType aRecType,
68 nsTArray<RefPtr<TRR>>& aRequestsToSend) {
69 LOG(("TRR Resolve %s type %d\n", mRecord->host.get(), (int)aRecType));
70 RefPtr<TRR> trr = new TRR(this, mRecord, aRecType);
73 MutexAutoLock trrlock(mTrrLock);
74 MarkSendingTRR(trr, aRecType, trrlock);
75 aRequestsToSend.AppendElement(trr);
79 bool TRRQuery::SendQueries(nsTArray<RefPtr<TRR>>& aRequestsToSend) {
80 bool madeQuery = false;
81 mTRRRequestCounter = aRequestsToSend.Length();
82 for (const auto& request : aRequestsToSend) {
83 if (NS_SUCCEEDED(TRRService::Get()->DispatchTRRRequest(request))) {
84 madeQuery = true;
85 } else {
86 mTRRRequestCounter--;
87 MutexAutoLock trrlock(mTrrLock);
88 if (request == mTrrA) {
89 mTrrA = nullptr;
90 mTrrAUsed = INIT;
92 if (request == mTrrAAAA) {
93 mTrrAAAA = nullptr;
94 mTrrAAAAUsed = INIT;
98 aRequestsToSend.Clear();
99 return madeQuery;
102 nsresult TRRQuery::DispatchLookup(TRR* pushedTRR) {
103 mTrrStart = TimeStamp::Now();
105 if (!mRecord->IsAddrRecord()) {
106 return DispatchByTypeLookup(pushedTRR);
109 RefPtr<AddrHostRecord> addrRec = do_QueryObject(mRecord);
110 MOZ_ASSERT(addrRec);
111 if (!addrRec) {
112 return NS_ERROR_UNEXPECTED;
115 mTrrAUsed = INIT;
116 mTrrAAAAUsed = INIT;
118 // Always issue both A and AAAA.
119 // When both are complete we filter out the unneeded results.
120 enum TrrType rectype = (mRecord->af == AF_INET6) ? TRRTYPE_AAAA : TRRTYPE_A;
122 if (pushedTRR) {
123 MutexAutoLock trrlock(mTrrLock);
124 rectype = pushedTRR->Type();
125 MarkSendingTRR(pushedTRR, rectype, trrlock);
126 return NS_OK;
129 // Need to dispatch TRR requests after |mTrrA| and |mTrrAAAA| are set
130 // properly so as to avoid the race when CompleteLookup() is called at the
131 // same time.
132 nsTArray<RefPtr<TRR>> requestsToSend;
133 if ((mRecord->af == AF_UNSPEC || mRecord->af == AF_INET6) &&
134 !StaticPrefs::network_dns_disableIPv6()) {
135 PrepareQuery(TRRTYPE_AAAA, requestsToSend);
137 if (mRecord->af == AF_UNSPEC || mRecord->af == AF_INET) {
138 PrepareQuery(TRRTYPE_A, requestsToSend);
141 if (SendQueries(requestsToSend)) {
142 return NS_OK;
145 return NS_ERROR_UNKNOWN_HOST;
148 nsresult TRRQuery::DispatchByTypeLookup(TRR* pushedTRR) {
149 RefPtr<TypeHostRecord> typeRec = do_QueryObject(mRecord);
150 MOZ_ASSERT(typeRec);
151 if (!typeRec) {
152 return NS_ERROR_UNEXPECTED;
155 enum TrrType rectype;
157 // XXX this could use a more extensible approach.
158 if (mRecord->type == nsIDNSService::RESOLVE_TYPE_TXT) {
159 rectype = TRRTYPE_TXT;
160 } else if (mRecord->type == nsIDNSService::RESOLVE_TYPE_HTTPSSVC) {
161 rectype = TRRTYPE_HTTPSSVC;
162 } else if (pushedTRR) {
163 rectype = pushedTRR->Type();
164 } else {
165 MOZ_ASSERT(false, "Not an expected request type");
166 return NS_ERROR_UNKNOWN_HOST;
169 LOG(("TRR Resolve %s type %d\n", typeRec->host.get(), (int)rectype));
170 RefPtr<TRR> trr = pushedTRR ? pushedTRR : new TRR(this, mRecord, rectype);
172 if (pushedTRR || NS_SUCCEEDED(TRRService::Get()->DispatchTRRRequest(trr))) {
173 MutexAutoLock trrlock(mTrrLock);
174 MOZ_ASSERT(!mTrrByType);
175 mTrrByType = trr;
176 return NS_OK;
179 return NS_ERROR_UNKNOWN_HOST;
182 AHostResolver::LookupStatus TRRQuery::CompleteLookup(
183 nsHostRecord* rec, nsresult status, AddrInfo* aNewRRSet, bool pb,
184 const nsACString& aOriginsuffix, nsHostRecord::TRRSkippedReason aReason,
185 TRR* aTRRRequest) {
186 if (rec != mRecord) {
187 LOG(("TRRQuery::CompleteLookup - Pushed record. Go to resolver"));
188 return mHostResolver->CompleteLookup(rec, status, aNewRRSet, pb,
189 aOriginsuffix, aReason, aTRRRequest);
192 LOG(("TRRQuery::CompleteLookup > host: %s", rec->host.get()));
194 RefPtr<AddrInfo> newRRSet(aNewRRSet);
195 DNSResolverType resolverType = newRRSet->ResolverType();
197 MutexAutoLock trrlock(mTrrLock);
198 if (newRRSet->TRRType() == TRRTYPE_A) {
199 MOZ_ASSERT(mTrrA);
200 mTRRAFailReason = aReason;
201 mTrrA = nullptr;
202 mTrrAUsed = NS_SUCCEEDED(status) ? OK : FAILED;
203 MOZ_ASSERT(!mAddrInfoA);
204 mAddrInfoA = newRRSet;
205 mAResult = status;
206 LOG(("A query status: 0x%x", static_cast<uint32_t>(status)));
207 } else if (newRRSet->TRRType() == TRRTYPE_AAAA) {
208 MOZ_ASSERT(mTrrAAAA);
209 mTRRAAAAFailReason = aReason;
210 mTrrAAAA = nullptr;
211 mTrrAAAAUsed = NS_SUCCEEDED(status) ? OK : FAILED;
212 MOZ_ASSERT(!mAddrInfoAAAA);
213 mAddrInfoAAAA = newRRSet;
214 mAAAAResult = status;
215 LOG(("AAAA query status: 0x%x", static_cast<uint32_t>(status)));
216 } else {
217 MOZ_ASSERT(0);
221 if (NS_SUCCEEDED(status)) {
222 mTRRSuccess++;
223 if (mTRRSuccess == 1) {
224 // Store the duration on first succesful TRR response. We
225 // don't know that there will be a second response nor can we
226 // tell which of two has useful data.
227 mTrrDuration = TimeStamp::Now() - mTrrStart;
231 bool pendingRequest = false;
232 if (mTRRRequestCounter) {
233 mTRRRequestCounter--;
234 pendingRequest = (mTRRRequestCounter != 0);
235 } else {
236 MOZ_DIAGNOSTIC_ASSERT(false, "Request counter is messed up");
238 if (pendingRequest) { // There are other outstanding requests
239 LOG(("CompleteLookup: waiting for all responses!\n"));
240 return LOOKUP_OK;
243 if (mRecord->af == AF_UNSPEC) {
244 // merge successful records
245 if (mTrrAUsed == OK) {
246 LOG(("Have A response"));
247 newRRSet = mAddrInfoA;
248 status = mAResult;
249 if (mTrrAAAAUsed == OK) {
250 LOG(("Merging A and AAAA responses"));
251 newRRSet = merge_rrset(newRRSet, mAddrInfoAAAA);
253 } else {
254 newRRSet = mAddrInfoAAAA;
255 status = mAAAAResult;
258 if (NS_FAILED(status) && (mAAAAResult == NS_ERROR_DEFINITIVE_UNKNOWN_HOST ||
259 mAResult == NS_ERROR_DEFINITIVE_UNKNOWN_HOST)) {
260 status = NS_ERROR_DEFINITIVE_UNKNOWN_HOST;
262 } else {
263 // If this is a failed AAAA request, but the server only has a A record,
264 // then we should not fallback to Do53. Instead we also send a A request
265 // and return NS_ERROR_DEFINITIVE_UNKNOWN_HOST if that succeeds.
266 if (NS_FAILED(status) && status != NS_ERROR_DEFINITIVE_UNKNOWN_HOST &&
267 (mTrrAUsed == INIT || mTrrAAAAUsed == INIT)) {
268 if (newRRSet->TRRType() == TRRTYPE_A) {
269 LOG(("A lookup failed. Checking if AAAA record exists"));
270 nsTArray<RefPtr<TRR>> requestsToSend;
271 PrepareQuery(TRRTYPE_AAAA, requestsToSend);
272 if (SendQueries(requestsToSend)) {
273 LOG(("Sent AAAA request"));
274 return LOOKUP_OK;
276 } else if (newRRSet->TRRType() == TRRTYPE_AAAA) {
277 LOG(("AAAA lookup failed. Checking if A record exists"));
278 nsTArray<RefPtr<TRR>> requestsToSend;
279 PrepareQuery(TRRTYPE_A, requestsToSend);
280 if (SendQueries(requestsToSend)) {
281 LOG(("Sent A request"));
282 return LOOKUP_OK;
284 } else {
285 MOZ_ASSERT(false, "Unexpected family");
288 bool otherSucceeded =
289 mRecord->af == AF_INET6 ? mTrrAUsed == OK : mTrrAAAAUsed == OK;
290 LOG(("TRRQuery::CompleteLookup other request succeeded"));
292 if (mRecord->af == AF_INET) {
293 // return only A record
294 newRRSet = mAddrInfoA;
295 status = mAResult;
296 if (NS_FAILED(status) &&
297 (otherSucceeded || mAAAAResult == NS_ERROR_DEFINITIVE_UNKNOWN_HOST)) {
298 LOG(("status set to NS_ERROR_DEFINITIVE_UNKNOWN_HOST"));
299 status = NS_ERROR_DEFINITIVE_UNKNOWN_HOST;
302 } else if (mRecord->af == AF_INET6) {
303 // return only AAAA record
304 newRRSet = mAddrInfoAAAA;
305 status = mAAAAResult;
307 if (NS_FAILED(status) &&
308 (otherSucceeded || mAResult == NS_ERROR_DEFINITIVE_UNKNOWN_HOST)) {
309 LOG(("status set to NS_ERROR_DEFINITIVE_UNKNOWN_HOST"));
310 status = NS_ERROR_DEFINITIVE_UNKNOWN_HOST;
313 } else {
314 MOZ_ASSERT(false, "Unexpected AF");
315 return LOOKUP_OK;
318 // If this record failed, but there is a record for the other AF
319 // we prevent fallback to the native resolver.
322 if (mTRRSuccess && mHostResolver->GetNCS() &&
323 (mHostResolver->GetNCS()->GetNAT64() ==
324 nsINetworkConnectivityService::OK) &&
325 newRRSet) {
326 newRRSet = mHostResolver->GetNCS()->MapNAT64IPs(newRRSet);
329 if (resolverType == DNSResolverType::TRR) {
330 if (mTrrAUsed == OK) {
331 AccumulateCategoricalKeyed(
332 TRRService::ProviderKey(),
333 Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrAOK);
334 } else if (mTrrAUsed == FAILED) {
335 AccumulateCategoricalKeyed(
336 TRRService::ProviderKey(),
337 Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrAFail);
340 if (mTrrAAAAUsed == OK) {
341 AccumulateCategoricalKeyed(
342 TRRService::ProviderKey(),
343 Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrAAAAOK);
344 } else if (mTrrAAAAUsed == FAILED) {
345 AccumulateCategoricalKeyed(
346 TRRService::ProviderKey(),
347 Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrAAAAFail);
351 mAddrInfoAAAA = nullptr;
352 mAddrInfoA = nullptr;
354 MOZ_DIAGNOSTIC_ASSERT(!mCalledCompleteLookup,
355 "must not call CompleteLookup more than once");
356 mCalledCompleteLookup = true;
357 return mHostResolver->CompleteLookup(rec, status, newRRSet, pb, aOriginsuffix,
358 aReason, aTRRRequest);
361 AHostResolver::LookupStatus TRRQuery::CompleteLookupByType(
362 nsHostRecord* rec, nsresult status,
363 mozilla::net::TypeRecordResultType& aResult,
364 mozilla::net::TRRSkippedReason aReason, uint32_t aTtl, bool pb) {
365 if (rec != mRecord) {
366 LOG(("TRRQuery::CompleteLookup - Pushed record. Go to resolver"));
367 return mHostResolver->CompleteLookupByType(rec, status, aResult, aReason,
368 aTtl, pb);
372 MutexAutoLock trrlock(mTrrLock);
373 mTrrByType = nullptr;
376 // Unlike the address record, we store the duration regardless of the status.
377 mTrrDuration = TimeStamp::Now() - mTrrStart;
379 MOZ_DIAGNOSTIC_ASSERT(!mCalledCompleteLookup,
380 "must not call CompleteLookup more than once");
381 mCalledCompleteLookup = true;
382 return mHostResolver->CompleteLookupByType(rec, status, aResult, aReason,
383 aTtl, pb);
386 } // namespace net
387 } // namespace mozilla