1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set sw=4 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDNSService2.h"
8 #include "nsIDNSRecord.h"
9 #include "nsIDNSListener.h"
10 #include "nsICancelable.h"
11 #include "nsIPrefService.h"
12 #include "nsIPrefBranch.h"
13 #include "nsIServiceManager.h"
14 #include "nsIXPConnect.h"
15 #include "nsProxyRelease.h"
16 #include "nsReadableUtils.h"
18 #include "nsAutoPtr.h"
21 #include "nsDNSPrefetch.h"
22 #include "nsThreadUtils.h"
23 #include "nsIProtocolProxyService.h"
29 #include "nsIOService.h"
30 #include "nsCharSeparatedTokenizer.h"
31 #include "nsNetAddr.h"
32 #include "nsProxyRelease.h"
34 #include "mozilla/Attributes.h"
35 #include "mozilla/VisualEventTracer.h"
36 #include "mozilla/net/NeckoCommon.h"
37 #include "mozilla/net/ChildDNSService.h"
38 #include "mozilla/net/DNSListenerProxy.h"
40 using namespace mozilla
;
41 using namespace mozilla::net
;
43 static const char kPrefDnsCacheEntries
[] = "network.dnsCacheEntries";
44 static const char kPrefDnsCacheExpiration
[] = "network.dnsCacheExpiration";
45 static const char kPrefDnsCacheGrace
[] = "network.dnsCacheExpirationGracePeriod";
46 static const char kPrefIPv4OnlyDomains
[] = "network.dns.ipv4OnlyDomains";
47 static const char kPrefDisableIPv6
[] = "network.dns.disableIPv6";
48 static const char kPrefDisablePrefetch
[] = "network.dns.disablePrefetch";
49 static const char kPrefDnsLocalDomains
[] = "network.dns.localDomains";
50 static const char kPrefDnsNotifyResolution
[] = "network.dns.notifyResolution";
52 //-----------------------------------------------------------------------------
54 class nsDNSRecord
: public nsIDNSRecord
57 NS_DECL_THREADSAFE_ISUPPORTS
60 explicit nsDNSRecord(nsHostRecord
*hostRecord
)
61 : mHostRecord(hostRecord
)
67 virtual ~nsDNSRecord() {}
69 nsRefPtr
<nsHostRecord
> mHostRecord
;
70 NetAddrElement
*mIter
;
71 int mIterGenCnt
; // the generation count of
72 // mHostRecord->addr_info when we
77 NS_IMPL_ISUPPORTS(nsDNSRecord
, nsIDNSRecord
)
80 nsDNSRecord::GetCanonicalName(nsACString
&result
)
82 // this method should only be called if we have a CNAME
83 NS_ENSURE_TRUE(mHostRecord
->flags
& nsHostResolver::RES_CANON_NAME
,
84 NS_ERROR_NOT_AVAILABLE
);
86 // if the record is for an IP address literal, then the canonical
87 // host name is the IP address literal.
90 MutexAutoLock
lock(mHostRecord
->addr_info_lock
);
91 if (mHostRecord
->addr_info
)
92 cname
= mHostRecord
->addr_info
->mCanonicalName
?
93 mHostRecord
->addr_info
->mCanonicalName
:
94 mHostRecord
->addr_info
->mHostName
;
96 cname
= mHostRecord
->host
;
103 nsDNSRecord::GetNextAddr(uint16_t port
, NetAddr
*addr
)
106 return NS_ERROR_NOT_AVAILABLE
;
109 mHostRecord
->addr_info_lock
.Lock();
110 if (mHostRecord
->addr_info
) {
111 if (mIterGenCnt
!= mHostRecord
->addr_info_gencnt
) {
112 // mHostRecord->addr_info has changed, restart the iteration.
114 mIterGenCnt
= mHostRecord
->addr_info_gencnt
;
117 bool startedFresh
= !mIter
;
121 mIter
= mHostRecord
->addr_info
->mAddresses
.getFirst();
123 mIter
= mIter
->getNext();
126 while (mIter
&& mHostRecord
->Blacklisted(&mIter
->mAddress
));
128 if (!mIter
&& startedFresh
) {
129 // If everything was blacklisted we want to reset the blacklist (and
130 // likely relearn it) and return the first address. That is better
132 mHostRecord
->ResetBlacklist();
133 mIter
= mHostRecord
->addr_info
->mAddresses
.getFirst();
137 memcpy(addr
, &mIter
->mAddress
, sizeof(NetAddr
));
140 mHostRecord
->addr_info_lock
.Unlock();
144 return NS_ERROR_NOT_AVAILABLE
;
148 mHostRecord
->addr_info_lock
.Unlock();
150 if (!mHostRecord
->addr
) {
151 // Both mHostRecord->addr_info and mHostRecord->addr are null.
152 // This can happen if mHostRecord->addr_info expired and the
153 // attempt to reresolve it failed.
154 return NS_ERROR_NOT_AVAILABLE
;
156 memcpy(addr
, mHostRecord
->addr
, sizeof(NetAddr
));
162 if (addr
->raw
.family
== AF_INET
) {
163 addr
->inet
.port
= port
;
165 else if (addr
->raw
.family
== AF_INET6
) {
166 addr
->inet6
.port
= port
;
173 nsDNSRecord::GetScriptableNextAddr(uint16_t port
, nsINetAddr
* *result
)
176 nsresult rv
= GetNextAddr(port
, &addr
);
177 if (NS_FAILED(rv
)) return rv
;
179 NS_ADDREF(*result
= new nsNetAddr(&addr
));
185 nsDNSRecord::GetNextAddrAsString(nsACString
&result
)
188 nsresult rv
= GetNextAddr(0, &addr
);
189 if (NS_FAILED(rv
)) return rv
;
191 char buf
[kIPv6CStrBufSize
];
192 if (NetAddrToString(&addr
, buf
, sizeof(buf
))) {
196 NS_ERROR("NetAddrToString failed unexpectedly");
197 return NS_ERROR_FAILURE
; // conversion failed for some reason
201 nsDNSRecord::HasMore(bool *result
)
208 NetAddrElement
*iterCopy
= mIter
;
211 *result
= NS_SUCCEEDED(GetNextAddr(0, &addr
));
220 nsDNSRecord::Rewind()
229 nsDNSRecord::ReportUnusable(uint16_t aPort
)
231 // right now we don't use the port in the blacklist
233 MutexAutoLock
lock(mHostRecord
->addr_info_lock
);
235 // Check that we are using a real addr_info (as opposed to a single
236 // constant address), and that the generation count is valid. Otherwise,
237 // ignore the report.
239 if (mHostRecord
->addr_info
&&
240 mIterGenCnt
== mHostRecord
->addr_info_gencnt
&&
242 mHostRecord
->ReportUnusable(&mIter
->mAddress
);
248 //-----------------------------------------------------------------------------
250 class nsDNSAsyncRequest MOZ_FINAL
: public nsResolveHostCallback
251 , public nsICancelable
253 ~nsDNSAsyncRequest() {}
256 NS_DECL_THREADSAFE_ISUPPORTS
257 NS_DECL_NSICANCELABLE
259 nsDNSAsyncRequest(nsHostResolver
*res
,
260 const nsACString
&host
,
261 nsIDNSListener
*listener
,
266 , mListener(listener
)
270 void OnLookupComplete(nsHostResolver
*, nsHostRecord
*, nsresult
);
271 // Returns TRUE if the DNS listener arg is the same as the member listener
272 // Used in Cancellations to remove DNS requests associated with a
273 // particular hostname and nsIDNSListener
274 bool EqualsAsyncListener(nsIDNSListener
*aListener
);
276 size_t SizeOfIncludingThis(mozilla::MallocSizeOf
) const;
278 nsRefPtr
<nsHostResolver
> mResolver
;
279 nsCString mHost
; // hostname we're resolving
280 nsCOMPtr
<nsIDNSListener
> mListener
;
286 nsDNSAsyncRequest::OnLookupComplete(nsHostResolver
*resolver
,
287 nsHostRecord
*hostRecord
,
290 // need to have an owning ref when we issue the callback to enable
291 // the caller to be able to addref/release multiple times without
292 // destroying the record prematurely.
293 nsCOMPtr
<nsIDNSRecord
> rec
;
294 if (NS_SUCCEEDED(status
)) {
295 NS_ASSERTION(hostRecord
, "no host record");
296 rec
= new nsDNSRecord(hostRecord
);
298 status
= NS_ERROR_OUT_OF_MEMORY
;
301 MOZ_EVENT_TRACER_DONE(this, "net::dns::lookup");
303 mListener
->OnLookupComplete(this, rec
, status
);
306 // release the reference to ourselves that was added before we were
307 // handed off to the host resolver.
312 nsDNSAsyncRequest::EqualsAsyncListener(nsIDNSListener
*aListener
)
314 nsCOMPtr
<nsIDNSListenerProxy
> wrapper
= do_QueryInterface(mListener
);
316 nsCOMPtr
<nsIDNSListener
> originalListener
;
317 wrapper
->GetOriginalListener(getter_AddRefs(originalListener
));
318 return aListener
== originalListener
;
320 return (aListener
== mListener
);
324 nsDNSAsyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const
326 size_t n
= mallocSizeOf(this);
328 // The following fields aren't measured.
329 // - mHost, because it's a non-owning pointer
330 // - mResolver, because it's a non-owning pointer
331 // - mListener, because it's a non-owning pointer
336 NS_IMPL_ISUPPORTS(nsDNSAsyncRequest
, nsICancelable
)
339 nsDNSAsyncRequest::Cancel(nsresult reason
)
341 NS_ENSURE_ARG(NS_FAILED(reason
));
342 mResolver
->DetachCallback(mHost
.get(), mFlags
, mAF
, this, reason
);
346 //-----------------------------------------------------------------------------
348 class nsDNSSyncRequest
: public nsResolveHostCallback
351 explicit nsDNSSyncRequest(PRMonitor
*mon
)
355 virtual ~nsDNSSyncRequest() {}
357 void OnLookupComplete(nsHostResolver
*, nsHostRecord
*, nsresult
);
358 bool EqualsAsyncListener(nsIDNSListener
*aListener
);
359 size_t SizeOfIncludingThis(mozilla::MallocSizeOf
) const;
363 nsRefPtr
<nsHostRecord
> mHostRecord
;
370 nsDNSSyncRequest::OnLookupComplete(nsHostResolver
*resolver
,
371 nsHostRecord
*hostRecord
,
374 // store results, and wake up nsDNSService::Resolve to process results.
375 PR_EnterMonitor(mMonitor
);
378 mHostRecord
= hostRecord
;
380 PR_ExitMonitor(mMonitor
);
384 nsDNSSyncRequest::EqualsAsyncListener(nsIDNSListener
*aListener
)
386 // Sync request: no listener to compare
391 nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const
393 size_t n
= mallocSizeOf(this);
395 // The following fields aren't measured.
396 // - mHostRecord, because it's a non-owning pointer
398 // Measurement of the following members may be added later if DMD finds it
405 class NotifyDNSResolution
: public nsRunnable
408 NotifyDNSResolution(nsMainThreadPtrHandle
<nsIObserverService
> &aObs
,
409 const nsACString
&aHostname
)
411 , mHostname(aHostname
)
418 MOZ_ASSERT(NS_IsMainThread());
419 mObs
->NotifyObservers(nullptr,
420 "dns-resolution-request",
421 NS_ConvertUTF8toUTF16(mHostname
).get());
426 nsMainThreadPtrHandle
<nsIObserverService
> mObs
;
430 //-----------------------------------------------------------------------------
432 nsDNSService::nsDNSService()
433 : mLock("nsDNSServer.mLock")
439 nsDNSService::~nsDNSService()
443 NS_IMPL_ISUPPORTS(nsDNSService
, nsIDNSService
, nsPIDNSService
, nsIObserver
,
446 /******************************************************************************
448 * singleton instance ctor/dtor methods
449 ******************************************************************************/
450 static nsDNSService
*gDNSService
;
453 nsDNSService::GetXPCOMSingleton()
455 if (IsNeckoChild()) {
456 return ChildDNSService::GetSingleton();
459 return GetSingleton();
463 nsDNSService::GetSingleton()
465 NS_ASSERTION(!IsNeckoChild(), "not a parent process");
468 NS_ADDREF(gDNSService
);
472 gDNSService
= new nsDNSService();
474 NS_ADDREF(gDNSService
);
475 if (NS_FAILED(gDNSService
->Init())) {
476 NS_RELEASE(gDNSService
);
488 NS_ENSURE_TRUE(!mResolver
, NS_ERROR_ALREADY_INITIALIZED
);
491 uint32_t maxCacheEntries
= 400;
492 uint32_t maxCacheLifetime
= 120; // seconds
493 uint32_t lifetimeGracePeriod
= 60; // seconds
494 bool disableIPv6
= false;
495 bool disablePrefetch
= false;
496 int proxyType
= nsIProtocolProxyService::PROXYCONFIG_DIRECT
;
497 bool notifyResolution
= false;
499 nsAdoptingCString ipv4OnlyDomains
;
500 nsAdoptingCString localDomains
;
503 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
506 if (NS_SUCCEEDED(prefs
->GetIntPref(kPrefDnsCacheEntries
, &val
)))
507 maxCacheEntries
= (uint32_t) val
;
508 if (NS_SUCCEEDED(prefs
->GetIntPref(kPrefDnsCacheExpiration
, &val
)))
509 maxCacheLifetime
= val
;
510 if (NS_SUCCEEDED(prefs
->GetIntPref(kPrefDnsCacheGrace
, &val
)))
511 lifetimeGracePeriod
= val
;
513 // ASSUMPTION: pref branch does not modify out params on failure
514 prefs
->GetBoolPref(kPrefDisableIPv6
, &disableIPv6
);
515 prefs
->GetCharPref(kPrefIPv4OnlyDomains
, getter_Copies(ipv4OnlyDomains
));
516 prefs
->GetCharPref(kPrefDnsLocalDomains
, getter_Copies(localDomains
));
517 prefs
->GetBoolPref(kPrefDisablePrefetch
, &disablePrefetch
);
519 // If a manual proxy is in use, disable prefetch implicitly
520 prefs
->GetIntPref("network.proxy.type", &proxyType
);
521 prefs
->GetBoolPref(kPrefDnsNotifyResolution
, ¬ifyResolution
);
527 // register as prefs observer
529 prefs
->AddObserver(kPrefDnsCacheEntries
, this, false);
530 prefs
->AddObserver(kPrefDnsCacheExpiration
, this, false);
531 prefs
->AddObserver(kPrefDnsCacheGrace
, this, false);
532 prefs
->AddObserver(kPrefIPv4OnlyDomains
, this, false);
533 prefs
->AddObserver(kPrefDnsLocalDomains
, this, false);
534 prefs
->AddObserver(kPrefDisableIPv6
, this, false);
535 prefs
->AddObserver(kPrefDisablePrefetch
, this, false);
536 prefs
->AddObserver(kPrefDnsNotifyResolution
, this, false);
538 // Monitor these to see if there is a change in proxy configuration
539 // If a manual proxy is in use, disable prefetch implicitly
540 prefs
->AddObserver("network.proxy.type", this, false);
544 nsCOMPtr
<nsIObserverService
> observerService
=
545 do_GetService("@mozilla.org/observer-service;1", &rv
);
546 if (NS_SUCCEEDED(rv
)) {
547 observerService
->AddObserver(this, "last-pb-context-exited", false);
551 nsDNSPrefetch::Initialize(this);
553 // Don't initialize the resolver if we're in offline mode.
554 // Later on, the IO service will reinitialize us when going online.
555 if (gIOService
->IsOffline() && !gIOService
->IsComingOnline())
558 nsCOMPtr
<nsIIDNService
> idn
= do_GetService(NS_IDNSERVICE_CONTRACTID
);
560 nsCOMPtr
<nsIObserverService
> obs
=
561 do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
563 nsRefPtr
<nsHostResolver
> res
;
564 nsresult rv
= nsHostResolver::Create(maxCacheEntries
,
567 getter_AddRefs(res
));
568 if (NS_SUCCEEDED(rv
)) {
569 // now, set all of our member variables while holding the lock
570 MutexAutoLock
lock(mLock
);
573 mIPv4OnlyDomains
= ipv4OnlyDomains
; // exchanges buffer ownership
574 mDisableIPv6
= disableIPv6
;
576 // Disable prefetching either by explicit preference or if a manual proxy is configured
577 mDisablePrefetch
= disablePrefetch
|| (proxyType
== nsIProtocolProxyService::PROXYCONFIG_MANUAL
);
579 mLocalDomains
.Clear();
581 nsAdoptingString domains
;
582 domains
.AssignASCII(nsDependentCString(localDomains
).get());
583 nsCharSeparatedTokenizer
tokenizer(domains
, ',',
584 nsCharSeparatedTokenizerTemplate
<>::SEPARATOR_OPTIONAL
);
586 while (tokenizer
.hasMoreTokens()) {
587 const nsSubstring
& domain
= tokenizer
.nextToken();
588 mLocalDomains
.PutEntry(nsDependentCString(NS_ConvertUTF16toUTF8(domain
).get()));
591 mNotifyResolution
= notifyResolution
;
592 if (mNotifyResolution
) {
594 new nsMainThreadPtrHolder
<nsIObserverService
>(obs
);
598 RegisterWeakMemoryReporter(this);
604 nsDNSService::Shutdown()
606 UnregisterWeakMemoryReporter(this);
608 nsRefPtr
<nsHostResolver
> res
;
610 MutexAutoLock
lock(mLock
);
620 nsDNSService::GetOffline(bool *offline
)
627 nsDNSService::SetOffline(bool offline
)
634 nsDNSService::GetPrefetchEnabled(bool *outVal
)
636 *outVal
= !mDisablePrefetch
;
641 nsDNSService::SetPrefetchEnabled(bool inVal
)
643 mDisablePrefetch
= !inVal
;
649 nsDNSService::AsyncResolve(const nsACString
&hostname
,
651 nsIDNSListener
*listener
,
652 nsIEventTarget
*target_
,
653 nsICancelable
**result
)
655 // grab reference to global host resolver and IDN service. beware
656 // simultaneous shutdown!!
657 nsRefPtr
<nsHostResolver
> res
;
658 nsCOMPtr
<nsIIDNService
> idn
;
659 nsCOMPtr
<nsIEventTarget
> target
= target_
;
660 bool localDomain
= false;
662 MutexAutoLock
lock(mLock
);
664 if (mDisablePrefetch
&& (flags
& RESOLVE_SPECULATE
))
665 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
669 localDomain
= mLocalDomains
.GetEntry(hostname
);
672 if (mNotifyResolution
) {
673 NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService
,
678 return NS_ERROR_OFFLINE
;
681 flags
|= RESOLVE_OFFLINE
;
683 const nsACString
*hostPtr
= &hostname
;
685 nsAutoCString
strLocalhost(NS_LITERAL_CSTRING("localhost"));
687 hostPtr
= &strLocalhost
;
691 nsAutoCString hostACE
;
692 if (idn
&& !IsASCII(*hostPtr
)) {
693 if (IsUTF8(*hostPtr
) &&
694 NS_SUCCEEDED(idn
->ConvertUTF8toACE(*hostPtr
, hostACE
))) {
697 return NS_ERROR_FAILURE
;
701 // make sure JS callers get notification on the main thread
702 nsCOMPtr
<nsIXPConnectWrappedJS
> wrappedListener
= do_QueryInterface(listener
);
703 if (wrappedListener
&& !target
) {
704 nsCOMPtr
<nsIThread
> mainThread
;
705 NS_GetMainThread(getter_AddRefs(mainThread
));
706 target
= do_QueryInterface(mainThread
);
710 listener
= new DNSListenerProxy(listener
, target
);
713 uint16_t af
= GetAFForLookup(*hostPtr
, flags
);
715 nsDNSAsyncRequest
*req
=
716 new nsDNSAsyncRequest(res
, *hostPtr
, listener
, flags
, af
);
718 return NS_ERROR_OUT_OF_MEMORY
;
719 NS_ADDREF(*result
= req
);
721 MOZ_EVENT_TRACER_NAME_OBJECT(req
, hostname
.BeginReading());
722 MOZ_EVENT_TRACER_WAIT(req
, "net::dns::lookup");
724 // addref for resolver; will be released when OnLookupComplete is called.
726 rv
= res
->ResolveHost(req
->mHost
.get(), flags
, af
, req
);
735 nsDNSService::CancelAsyncResolve(const nsACString
&aHostname
,
737 nsIDNSListener
*aListener
,
740 // grab reference to global host resolver and IDN service. beware
741 // simultaneous shutdown!!
742 nsRefPtr
<nsHostResolver
> res
;
743 nsCOMPtr
<nsIIDNService
> idn
;
745 MutexAutoLock
lock(mLock
);
747 if (mDisablePrefetch
&& (aFlags
& RESOLVE_SPECULATE
))
748 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
754 return NS_ERROR_OFFLINE
;
756 nsCString
hostname(aHostname
);
758 nsAutoCString hostACE
;
759 if (idn
&& !IsASCII(aHostname
)) {
760 if (IsUTF8(aHostname
) &&
761 NS_SUCCEEDED(idn
->ConvertUTF8toACE(aHostname
, hostACE
))) {
764 return NS_ERROR_FAILURE
;
768 uint16_t af
= GetAFForLookup(hostname
, aFlags
);
770 res
->CancelAsyncRequest(hostname
.get(), aFlags
, af
, aListener
, aReason
);
775 nsDNSService::Resolve(const nsACString
&hostname
,
777 nsIDNSRecord
**result
)
779 // grab reference to global host resolver and IDN service. beware
780 // simultaneous shutdown!!
781 nsRefPtr
<nsHostResolver
> res
;
782 nsCOMPtr
<nsIIDNService
> idn
;
783 bool localDomain
= false;
785 MutexAutoLock
lock(mLock
);
788 localDomain
= mLocalDomains
.GetEntry(hostname
);
791 if (mNotifyResolution
) {
792 NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService
,
796 NS_ENSURE_TRUE(res
, NS_ERROR_OFFLINE
);
799 flags
|= RESOLVE_OFFLINE
;
801 const nsACString
*hostPtr
= &hostname
;
803 nsAutoCString
strLocalhost(NS_LITERAL_CSTRING("localhost"));
805 hostPtr
= &strLocalhost
;
809 nsAutoCString hostACE
;
810 if (idn
&& !IsASCII(*hostPtr
)) {
811 if (IsUTF8(*hostPtr
) &&
812 NS_SUCCEEDED(idn
->ConvertUTF8toACE(*hostPtr
, hostACE
))) {
815 return NS_ERROR_FAILURE
;
820 // sync resolve: since the host resolver only works asynchronously, we need
821 // to use a mutex and a condvar to wait for the result. however, since the
822 // result may be in the resolvers cache, we might get called back recursively
823 // on the same thread. so, our mutex needs to be re-entrant. in other words,
824 // we need to use a monitor! ;-)
827 PRMonitor
*mon
= PR_NewMonitor();
829 return NS_ERROR_OUT_OF_MEMORY
;
831 PR_EnterMonitor(mon
);
832 nsDNSSyncRequest
syncReq(mon
);
834 uint16_t af
= GetAFForLookup(*hostPtr
, flags
);
836 rv
= res
->ResolveHost(PromiseFlatCString(*hostPtr
).get(), flags
, af
, &syncReq
);
837 if (NS_SUCCEEDED(rv
)) {
839 while (!syncReq
.mDone
)
840 PR_Wait(mon
, PR_INTERVAL_NO_TIMEOUT
);
842 if (NS_FAILED(syncReq
.mStatus
))
843 rv
= syncReq
.mStatus
;
845 NS_ASSERTION(syncReq
.mHostRecord
, "no host record");
846 nsDNSRecord
*rec
= new nsDNSRecord(syncReq
.mHostRecord
);
848 rv
= NS_ERROR_OUT_OF_MEMORY
;
850 NS_ADDREF(*result
= rec
);
855 PR_DestroyMonitor(mon
);
860 nsDNSService::GetMyHostName(nsACString
&result
)
863 if (PR_GetSystemInfo(PR_SI_HOSTNAME
, name
, sizeof(name
)) == PR_SUCCESS
) {
867 return NS_ERROR_FAILURE
;
871 nsDNSService::Observe(nsISupports
*subject
, const char *topic
, const char16_t
*data
)
873 // we are only getting called if a preference has changed.
874 NS_ASSERTION(strcmp(topic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
) == 0 ||
875 strcmp(topic
, "last-pb-context-exited") == 0,
876 "unexpected observe call");
879 // Shutdown and this function are both only called on the UI thread, so we don't
880 // have to worry about mResolver being cleared out from under us.
882 // NOTE Shutting down and reinitializing the service like this is obviously
883 // suboptimal if Observe gets called several times in a row, but we don't
884 // expect that to be the case.
895 nsDNSService::GetAFForLookup(const nsACString
&host
, uint32_t flags
)
897 if (mDisableIPv6
|| (flags
& RESOLVE_DISABLE_IPV6
))
900 MutexAutoLock
lock(mLock
);
902 uint16_t af
= PR_AF_UNSPEC
;
904 if (!mIPv4OnlyDomains
.IsEmpty()) {
905 const char *domain
, *domainEnd
, *end
;
906 uint32_t hostLen
, domainLen
;
908 // see if host is in one of the IPv4-only domains
909 domain
= mIPv4OnlyDomains
.BeginReading();
910 domainEnd
= mIPv4OnlyDomains
.EndReading();
912 nsACString::const_iterator hostStart
;
913 host
.BeginReading(hostStart
);
914 hostLen
= host
.Length();
917 // skip any whitespace
918 while (*domain
== ' ' || *domain
== '\t')
921 // find end of this domain in the string
922 end
= strchr(domain
, ',');
926 // to see if the hostname is in the domain, check if the domain
927 // matches the end of the hostname.
928 domainLen
= end
- domain
;
929 if (domainLen
&& hostLen
>= domainLen
) {
930 const char *hostTail
= hostStart
.get() + hostLen
- domainLen
;
931 if (PL_strncasecmp(domain
, hostTail
, domainLen
) == 0) {
932 // now, make sure either that the hostname is a direct match or
933 // that the hostname begins with a dot.
934 if (hostLen
== domainLen
||
935 *hostTail
== '.' || *(hostTail
- 1) == '.') {
946 if ((af
!= PR_AF_INET
) && (flags
& RESOLVE_DISABLE_IPV4
))
953 nsDNSService::GetDNSCacheEntries(nsTArray
<mozilla::net::DNSCacheEntries
> *args
)
955 NS_ENSURE_TRUE(mResolver
, NS_ERROR_NOT_INITIALIZED
);
956 mResolver
->GetDNSCacheEntries(args
);
961 nsDNSService::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const
963 // Measurement of the following members may be added later if DMD finds it
968 size_t n
= mallocSizeOf(this);
969 n
+= mResolver
->SizeOfIncludingThis(mallocSizeOf
);
970 n
+= mIPv4OnlyDomains
.SizeOfExcludingThisMustBeUnshared(mallocSizeOf
);
971 n
+= mLocalDomains
.SizeOfExcludingThis(mallocSizeOf
);
975 MOZ_DEFINE_MALLOC_SIZE_OF(DNSServiceMallocSizeOf
)
978 nsDNSService::CollectReports(nsIHandleReportCallback
* aHandleReport
,
979 nsISupports
* aData
, bool aAnonymize
)
981 return MOZ_COLLECT_REPORT(
982 "explicit/network/dns-service", KIND_HEAP
, UNITS_BYTES
,
983 SizeOfIncludingThis(DNSServiceMallocSizeOf
),
984 "Memory used for the DNS service.");