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"
33 #include "nsIObserverService.h"
34 #include "nsINetworkLinkService.h"
36 #include "mozilla/Attributes.h"
37 #include "mozilla/VisualEventTracer.h"
38 #include "mozilla/net/NeckoCommon.h"
39 #include "mozilla/net/ChildDNSService.h"
40 #include "mozilla/net/DNSListenerProxy.h"
41 #include "mozilla/Services.h"
43 using namespace mozilla
;
44 using namespace mozilla::net
;
46 static const char kPrefDnsCacheEntries
[] = "network.dnsCacheEntries";
47 static const char kPrefDnsCacheExpiration
[] = "network.dnsCacheExpiration";
48 static const char kPrefDnsCacheGrace
[] = "network.dnsCacheExpirationGracePeriod";
49 static const char kPrefIPv4OnlyDomains
[] = "network.dns.ipv4OnlyDomains";
50 static const char kPrefDisableIPv6
[] = "network.dns.disableIPv6";
51 static const char kPrefDisablePrefetch
[] = "network.dns.disablePrefetch";
52 static const char kPrefDnsLocalDomains
[] = "network.dns.localDomains";
53 static const char kPrefDnsNotifyResolution
[] = "network.dns.notifyResolution";
55 //-----------------------------------------------------------------------------
57 class nsDNSRecord
: public nsIDNSRecord
60 NS_DECL_THREADSAFE_ISUPPORTS
63 explicit nsDNSRecord(nsHostRecord
*hostRecord
)
64 : mHostRecord(hostRecord
)
70 virtual ~nsDNSRecord() {}
72 nsRefPtr
<nsHostRecord
> mHostRecord
;
73 NetAddrElement
*mIter
;
74 int mIterGenCnt
; // the generation count of
75 // mHostRecord->addr_info when we
80 NS_IMPL_ISUPPORTS(nsDNSRecord
, nsIDNSRecord
)
83 nsDNSRecord::GetCanonicalName(nsACString
&result
)
85 // this method should only be called if we have a CNAME
86 NS_ENSURE_TRUE(mHostRecord
->flags
& nsHostResolver::RES_CANON_NAME
,
87 NS_ERROR_NOT_AVAILABLE
);
89 // if the record is for an IP address literal, then the canonical
90 // host name is the IP address literal.
93 MutexAutoLock
lock(mHostRecord
->addr_info_lock
);
94 if (mHostRecord
->addr_info
)
95 cname
= mHostRecord
->addr_info
->mCanonicalName
?
96 mHostRecord
->addr_info
->mCanonicalName
:
97 mHostRecord
->addr_info
->mHostName
;
99 cname
= mHostRecord
->host
;
100 result
.Assign(cname
);
106 nsDNSRecord::GetNextAddr(uint16_t port
, NetAddr
*addr
)
109 return NS_ERROR_NOT_AVAILABLE
;
112 mHostRecord
->addr_info_lock
.Lock();
113 if (mHostRecord
->addr_info
) {
114 if (mIterGenCnt
!= mHostRecord
->addr_info_gencnt
) {
115 // mHostRecord->addr_info has changed, restart the iteration.
117 mIterGenCnt
= mHostRecord
->addr_info_gencnt
;
120 bool startedFresh
= !mIter
;
124 mIter
= mHostRecord
->addr_info
->mAddresses
.getFirst();
126 mIter
= mIter
->getNext();
129 while (mIter
&& mHostRecord
->Blacklisted(&mIter
->mAddress
));
131 if (!mIter
&& startedFresh
) {
132 // If everything was blacklisted we want to reset the blacklist (and
133 // likely relearn it) and return the first address. That is better
135 mHostRecord
->ResetBlacklist();
136 mIter
= mHostRecord
->addr_info
->mAddresses
.getFirst();
140 memcpy(addr
, &mIter
->mAddress
, sizeof(NetAddr
));
143 mHostRecord
->addr_info_lock
.Unlock();
147 return NS_ERROR_NOT_AVAILABLE
;
151 mHostRecord
->addr_info_lock
.Unlock();
153 if (!mHostRecord
->addr
) {
154 // Both mHostRecord->addr_info and mHostRecord->addr are null.
155 // This can happen if mHostRecord->addr_info expired and the
156 // attempt to reresolve it failed.
157 return NS_ERROR_NOT_AVAILABLE
;
159 memcpy(addr
, mHostRecord
->addr
, sizeof(NetAddr
));
165 if (addr
->raw
.family
== AF_INET
) {
166 addr
->inet
.port
= port
;
168 else if (addr
->raw
.family
== AF_INET6
) {
169 addr
->inet6
.port
= port
;
176 nsDNSRecord::GetScriptableNextAddr(uint16_t port
, nsINetAddr
* *result
)
179 nsresult rv
= GetNextAddr(port
, &addr
);
180 if (NS_FAILED(rv
)) return rv
;
182 NS_ADDREF(*result
= new nsNetAddr(&addr
));
188 nsDNSRecord::GetNextAddrAsString(nsACString
&result
)
191 nsresult rv
= GetNextAddr(0, &addr
);
192 if (NS_FAILED(rv
)) return rv
;
194 char buf
[kIPv6CStrBufSize
];
195 if (NetAddrToString(&addr
, buf
, sizeof(buf
))) {
199 NS_ERROR("NetAddrToString failed unexpectedly");
200 return NS_ERROR_FAILURE
; // conversion failed for some reason
204 nsDNSRecord::HasMore(bool *result
)
211 NetAddrElement
*iterCopy
= mIter
;
212 int iterGenCntCopy
= mIterGenCnt
;
215 *result
= NS_SUCCEEDED(GetNextAddr(0, &addr
));
218 mIterGenCnt
= iterGenCntCopy
;
225 nsDNSRecord::Rewind()
234 nsDNSRecord::ReportUnusable(uint16_t aPort
)
236 // right now we don't use the port in the blacklist
238 MutexAutoLock
lock(mHostRecord
->addr_info_lock
);
240 // Check that we are using a real addr_info (as opposed to a single
241 // constant address), and that the generation count is valid. Otherwise,
242 // ignore the report.
244 if (mHostRecord
->addr_info
&&
245 mIterGenCnt
== mHostRecord
->addr_info_gencnt
&&
247 mHostRecord
->ReportUnusable(&mIter
->mAddress
);
253 //-----------------------------------------------------------------------------
255 class nsDNSAsyncRequest MOZ_FINAL
: public nsResolveHostCallback
256 , public nsICancelable
258 ~nsDNSAsyncRequest() {}
261 NS_DECL_THREADSAFE_ISUPPORTS
262 NS_DECL_NSICANCELABLE
264 nsDNSAsyncRequest(nsHostResolver
*res
,
265 const nsACString
&host
,
266 nsIDNSListener
*listener
,
269 const nsACString
&netInterface
)
272 , mListener(listener
)
275 , mNetworkInterface(netInterface
) {}
277 void OnLookupComplete(nsHostResolver
*, nsHostRecord
*, nsresult
) MOZ_OVERRIDE
;
278 // Returns TRUE if the DNS listener arg is the same as the member listener
279 // Used in Cancellations to remove DNS requests associated with a
280 // particular hostname and nsIDNSListener
281 bool EqualsAsyncListener(nsIDNSListener
*aListener
) MOZ_OVERRIDE
;
283 size_t SizeOfIncludingThis(mozilla::MallocSizeOf
) const MOZ_OVERRIDE
;
285 nsRefPtr
<nsHostResolver
> mResolver
;
286 nsCString mHost
; // hostname we're resolving
287 nsCOMPtr
<nsIDNSListener
> mListener
;
290 nsCString mNetworkInterface
;
294 nsDNSAsyncRequest::OnLookupComplete(nsHostResolver
*resolver
,
295 nsHostRecord
*hostRecord
,
298 // need to have an owning ref when we issue the callback to enable
299 // the caller to be able to addref/release multiple times without
300 // destroying the record prematurely.
301 nsCOMPtr
<nsIDNSRecord
> rec
;
302 if (NS_SUCCEEDED(status
)) {
303 NS_ASSERTION(hostRecord
, "no host record");
304 rec
= new nsDNSRecord(hostRecord
);
306 status
= NS_ERROR_OUT_OF_MEMORY
;
309 MOZ_EVENT_TRACER_DONE(this, "net::dns::lookup");
311 mListener
->OnLookupComplete(this, rec
, status
);
314 // release the reference to ourselves that was added before we were
315 // handed off to the host resolver.
320 nsDNSAsyncRequest::EqualsAsyncListener(nsIDNSListener
*aListener
)
322 nsCOMPtr
<nsIDNSListenerProxy
> wrapper
= do_QueryInterface(mListener
);
324 nsCOMPtr
<nsIDNSListener
> originalListener
;
325 wrapper
->GetOriginalListener(getter_AddRefs(originalListener
));
326 return aListener
== originalListener
;
328 return (aListener
== mListener
);
332 nsDNSAsyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const
334 size_t n
= mallocSizeOf(this);
336 // The following fields aren't measured.
337 // - mHost, because it's a non-owning pointer
338 // - mResolver, because it's a non-owning pointer
339 // - mListener, because it's a non-owning pointer
344 NS_IMPL_ISUPPORTS(nsDNSAsyncRequest
, nsICancelable
)
347 nsDNSAsyncRequest::Cancel(nsresult reason
)
349 NS_ENSURE_ARG(NS_FAILED(reason
));
350 mResolver
->DetachCallback(mHost
.get(), mFlags
, mAF
, mNetworkInterface
.get(),
355 //-----------------------------------------------------------------------------
357 class nsDNSSyncRequest
: public nsResolveHostCallback
360 explicit nsDNSSyncRequest(PRMonitor
*mon
)
364 virtual ~nsDNSSyncRequest() {}
366 void OnLookupComplete(nsHostResolver
*, nsHostRecord
*, nsresult
);
367 bool EqualsAsyncListener(nsIDNSListener
*aListener
);
368 size_t SizeOfIncludingThis(mozilla::MallocSizeOf
) const;
372 nsRefPtr
<nsHostRecord
> mHostRecord
;
379 nsDNSSyncRequest::OnLookupComplete(nsHostResolver
*resolver
,
380 nsHostRecord
*hostRecord
,
383 // store results, and wake up nsDNSService::Resolve to process results.
384 PR_EnterMonitor(mMonitor
);
387 mHostRecord
= hostRecord
;
389 PR_ExitMonitor(mMonitor
);
393 nsDNSSyncRequest::EqualsAsyncListener(nsIDNSListener
*aListener
)
395 // Sync request: no listener to compare
400 nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const
402 size_t n
= mallocSizeOf(this);
404 // The following fields aren't measured.
405 // - mHostRecord, because it's a non-owning pointer
407 // Measurement of the following members may be added later if DMD finds it
414 class NotifyDNSResolution
: public nsRunnable
417 NotifyDNSResolution(nsMainThreadPtrHandle
<nsIObserverService
> &aObs
,
418 const nsACString
&aHostname
)
420 , mHostname(aHostname
)
427 MOZ_ASSERT(NS_IsMainThread());
428 mObs
->NotifyObservers(nullptr,
429 "dns-resolution-request",
430 NS_ConvertUTF8toUTF16(mHostname
).get());
435 nsMainThreadPtrHandle
<nsIObserverService
> mObs
;
439 //-----------------------------------------------------------------------------
441 nsDNSService::nsDNSService()
442 : mLock("nsDNSServer.mLock")
448 nsDNSService::~nsDNSService()
452 NS_IMPL_ISUPPORTS(nsDNSService
, nsIDNSService
, nsPIDNSService
, nsIObserver
,
455 /******************************************************************************
457 * singleton instance ctor/dtor methods
458 ******************************************************************************/
459 static nsDNSService
*gDNSService
;
462 nsDNSService::GetXPCOMSingleton()
464 if (IsNeckoChild()) {
465 return ChildDNSService::GetSingleton();
468 return GetSingleton();
472 nsDNSService::GetSingleton()
474 NS_ASSERTION(!IsNeckoChild(), "not a parent process");
477 NS_ADDREF(gDNSService
);
481 gDNSService
= new nsDNSService();
483 NS_ADDREF(gDNSService
);
484 if (NS_FAILED(gDNSService
->Init())) {
485 NS_RELEASE(gDNSService
);
497 NS_ENSURE_TRUE(!mResolver
, NS_ERROR_ALREADY_INITIALIZED
);
500 uint32_t maxCacheEntries
= 400;
501 uint32_t defaultCacheLifetime
= 120; // seconds
502 uint32_t defaultGracePeriod
= 60; // seconds
503 bool disableIPv6
= false;
504 bool disablePrefetch
= false;
505 int proxyType
= nsIProtocolProxyService::PROXYCONFIG_DIRECT
;
506 bool notifyResolution
= false;
508 nsAdoptingCString ipv4OnlyDomains
;
509 nsAdoptingCString localDomains
;
512 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
515 if (NS_SUCCEEDED(prefs
->GetIntPref(kPrefDnsCacheEntries
, &val
)))
516 maxCacheEntries
= (uint32_t) val
;
517 if (NS_SUCCEEDED(prefs
->GetIntPref(kPrefDnsCacheExpiration
, &val
)))
518 defaultCacheLifetime
= val
;
519 if (NS_SUCCEEDED(prefs
->GetIntPref(kPrefDnsCacheGrace
, &val
)))
520 defaultGracePeriod
= val
;
522 // ASSUMPTION: pref branch does not modify out params on failure
523 prefs
->GetBoolPref(kPrefDisableIPv6
, &disableIPv6
);
524 prefs
->GetCharPref(kPrefIPv4OnlyDomains
, getter_Copies(ipv4OnlyDomains
));
525 prefs
->GetCharPref(kPrefDnsLocalDomains
, getter_Copies(localDomains
));
526 prefs
->GetBoolPref(kPrefDisablePrefetch
, &disablePrefetch
);
528 // If a manual proxy is in use, disable prefetch implicitly
529 prefs
->GetIntPref("network.proxy.type", &proxyType
);
530 prefs
->GetBoolPref(kPrefDnsNotifyResolution
, ¬ifyResolution
);
536 // register as prefs observer
538 prefs
->AddObserver(kPrefDnsCacheEntries
, this, false);
539 prefs
->AddObserver(kPrefDnsCacheExpiration
, this, false);
540 prefs
->AddObserver(kPrefDnsCacheGrace
, this, false);
541 prefs
->AddObserver(kPrefIPv4OnlyDomains
, this, false);
542 prefs
->AddObserver(kPrefDnsLocalDomains
, this, false);
543 prefs
->AddObserver(kPrefDisableIPv6
, this, false);
544 prefs
->AddObserver(kPrefDisablePrefetch
, this, false);
545 prefs
->AddObserver(kPrefDnsNotifyResolution
, this, false);
547 // Monitor these to see if there is a change in proxy configuration
548 // If a manual proxy is in use, disable prefetch implicitly
549 prefs
->AddObserver("network.proxy.type", this, false);
552 nsCOMPtr
<nsIObserverService
> observerService
=
553 mozilla::services::GetObserverService();
554 if (observerService
) {
555 observerService
->AddObserver(this, "last-pb-context-exited", false);
556 observerService
->AddObserver(this, NS_NETWORK_LINK_TOPIC
, false);
561 nsDNSPrefetch::Initialize(this);
563 // Don't initialize the resolver if we're in offline mode.
564 // Later on, the IO service will reinitialize us when going online.
565 if (gIOService
->IsOffline() && !gIOService
->IsComingOnline())
568 nsCOMPtr
<nsIIDNService
> idn
= do_GetService(NS_IDNSERVICE_CONTRACTID
);
570 nsCOMPtr
<nsIObserverService
> obs
=
571 do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
573 nsRefPtr
<nsHostResolver
> res
;
574 nsresult rv
= nsHostResolver::Create(maxCacheEntries
,
575 defaultCacheLifetime
,
577 getter_AddRefs(res
));
578 if (NS_SUCCEEDED(rv
)) {
579 // now, set all of our member variables while holding the lock
580 MutexAutoLock
lock(mLock
);
583 mIPv4OnlyDomains
= ipv4OnlyDomains
; // exchanges buffer ownership
584 mDisableIPv6
= disableIPv6
;
586 // Disable prefetching either by explicit preference or if a manual proxy is configured
587 mDisablePrefetch
= disablePrefetch
|| (proxyType
== nsIProtocolProxyService::PROXYCONFIG_MANUAL
);
589 mLocalDomains
.Clear();
591 nsCCharSeparatedTokenizer
tokenizer(localDomains
, ',',
592 nsCCharSeparatedTokenizer::SEPARATOR_OPTIONAL
);
594 while (tokenizer
.hasMoreTokens()) {
595 mLocalDomains
.PutEntry(tokenizer
.nextToken());
598 mNotifyResolution
= notifyResolution
;
599 if (mNotifyResolution
) {
601 new nsMainThreadPtrHolder
<nsIObserverService
>(obs
);
605 RegisterWeakMemoryReporter(this);
611 nsDNSService::Shutdown()
613 UnregisterWeakMemoryReporter(this);
615 nsRefPtr
<nsHostResolver
> res
;
617 MutexAutoLock
lock(mLock
);
627 nsDNSService::GetOffline(bool *offline
)
634 nsDNSService::SetOffline(bool offline
)
641 nsDNSService::GetPrefetchEnabled(bool *outVal
)
643 *outVal
= !mDisablePrefetch
;
648 nsDNSService::SetPrefetchEnabled(bool inVal
)
650 mDisablePrefetch
= !inVal
;
654 static inline bool PreprocessHostname(bool aLocalDomain
,
655 const nsACString
&aInput
,
660 aACE
.AssignLiteral("localhost");
664 if (!aIDN
|| IsASCII(aInput
)) {
669 return IsUTF8(aInput
) && NS_SUCCEEDED(aIDN
->ConvertUTF8toACE(aInput
, aACE
));
673 nsDNSService::AsyncResolve(const nsACString
&aHostname
,
675 nsIDNSListener
*listener
,
676 nsIEventTarget
*target_
,
677 nsICancelable
**result
)
679 return AsyncResolveExtended(aHostname
, flags
, EmptyCString(), listener
, target_
,
684 nsDNSService::AsyncResolveExtended(const nsACString
&aHostname
,
686 const nsACString
&aNetworkInterface
,
687 nsIDNSListener
*listener
,
688 nsIEventTarget
*target_
,
689 nsICancelable
**result
)
691 // grab reference to global host resolver and IDN service. beware
692 // simultaneous shutdown!!
693 nsRefPtr
<nsHostResolver
> res
;
694 nsCOMPtr
<nsIIDNService
> idn
;
695 nsCOMPtr
<nsIEventTarget
> target
= target_
;
696 bool localDomain
= false;
698 MutexAutoLock
lock(mLock
);
700 if (mDisablePrefetch
&& (flags
& RESOLVE_SPECULATE
))
701 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
705 localDomain
= mLocalDomains
.GetEntry(aHostname
);
708 if (mNotifyResolution
) {
709 NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService
,
714 return NS_ERROR_OFFLINE
;
717 flags
|= RESOLVE_OFFLINE
;
720 if (!PreprocessHostname(localDomain
, aHostname
, idn
, hostname
))
721 return NS_ERROR_FAILURE
;
723 // make sure JS callers get notification on the main thread
724 nsCOMPtr
<nsIXPConnectWrappedJS
> wrappedListener
= do_QueryInterface(listener
);
725 if (wrappedListener
&& !target
) {
726 nsCOMPtr
<nsIThread
> mainThread
;
727 NS_GetMainThread(getter_AddRefs(mainThread
));
728 target
= do_QueryInterface(mainThread
);
732 listener
= new DNSListenerProxy(listener
, target
);
735 uint16_t af
= GetAFForLookup(hostname
, flags
);
737 nsDNSAsyncRequest
*req
=
738 new nsDNSAsyncRequest(res
, hostname
, listener
, flags
, af
,
741 return NS_ERROR_OUT_OF_MEMORY
;
742 NS_ADDREF(*result
= req
);
744 MOZ_EVENT_TRACER_NAME_OBJECT(req
, aHostname
.BeginReading());
745 MOZ_EVENT_TRACER_WAIT(req
, "net::dns::lookup");
747 // addref for resolver; will be released when OnLookupComplete is called.
749 nsresult rv
= res
->ResolveHost(req
->mHost
.get(), flags
, af
,
750 req
->mNetworkInterface
.get(),
760 nsDNSService::CancelAsyncResolve(const nsACString
&aHostname
,
762 nsIDNSListener
*aListener
,
765 return CancelAsyncResolveExtended(aHostname
, aFlags
, EmptyCString(), aListener
,
770 nsDNSService::CancelAsyncResolveExtended(const nsACString
&aHostname
,
772 const nsACString
&aNetworkInterface
,
773 nsIDNSListener
*aListener
,
776 // grab reference to global host resolver and IDN service. beware
777 // simultaneous shutdown!!
778 nsRefPtr
<nsHostResolver
> res
;
779 nsCOMPtr
<nsIIDNService
> idn
;
780 bool localDomain
= false;
782 MutexAutoLock
lock(mLock
);
784 if (mDisablePrefetch
&& (aFlags
& RESOLVE_SPECULATE
))
785 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
789 localDomain
= mLocalDomains
.GetEntry(aHostname
);
792 return NS_ERROR_OFFLINE
;
795 if (!PreprocessHostname(localDomain
, aHostname
, idn
, hostname
))
796 return NS_ERROR_FAILURE
;
798 uint16_t af
= GetAFForLookup(hostname
, aFlags
);
800 res
->CancelAsyncRequest(hostname
.get(), aFlags
, af
,
801 nsPromiseFlatCString(aNetworkInterface
).get(), aListener
,
807 nsDNSService::Resolve(const nsACString
&aHostname
,
809 nsIDNSRecord
**result
)
811 // grab reference to global host resolver and IDN service. beware
812 // simultaneous shutdown!!
813 nsRefPtr
<nsHostResolver
> res
;
814 nsCOMPtr
<nsIIDNService
> idn
;
815 bool localDomain
= false;
817 MutexAutoLock
lock(mLock
);
820 localDomain
= mLocalDomains
.GetEntry(aHostname
);
823 if (mNotifyResolution
) {
824 NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService
,
828 NS_ENSURE_TRUE(res
, NS_ERROR_OFFLINE
);
831 flags
|= RESOLVE_OFFLINE
;
834 if (!PreprocessHostname(localDomain
, aHostname
, idn
, hostname
))
835 return NS_ERROR_FAILURE
;
838 // sync resolve: since the host resolver only works asynchronously, we need
839 // to use a mutex and a condvar to wait for the result. however, since the
840 // result may be in the resolvers cache, we might get called back recursively
841 // on the same thread. so, our mutex needs to be re-entrant. in other words,
842 // we need to use a monitor! ;-)
845 PRMonitor
*mon
= PR_NewMonitor();
847 return NS_ERROR_OUT_OF_MEMORY
;
849 PR_EnterMonitor(mon
);
850 nsDNSSyncRequest
syncReq(mon
);
852 uint16_t af
= GetAFForLookup(hostname
, flags
);
854 nsresult rv
= res
->ResolveHost(hostname
.get(), flags
, af
, "", &syncReq
);
855 if (NS_SUCCEEDED(rv
)) {
857 while (!syncReq
.mDone
)
858 PR_Wait(mon
, PR_INTERVAL_NO_TIMEOUT
);
860 if (NS_FAILED(syncReq
.mStatus
))
861 rv
= syncReq
.mStatus
;
863 NS_ASSERTION(syncReq
.mHostRecord
, "no host record");
864 nsDNSRecord
*rec
= new nsDNSRecord(syncReq
.mHostRecord
);
866 rv
= NS_ERROR_OUT_OF_MEMORY
;
868 NS_ADDREF(*result
= rec
);
873 PR_DestroyMonitor(mon
);
878 nsDNSService::GetMyHostName(nsACString
&result
)
881 if (PR_GetSystemInfo(PR_SI_HOSTNAME
, name
, sizeof(name
)) == PR_SUCCESS
) {
885 return NS_ERROR_FAILURE
;
889 nsDNSService::Observe(nsISupports
*subject
, const char *topic
, const char16_t
*data
)
891 // We are only getting called if a preference has changed or there's a
892 // network link event.
893 NS_ASSERTION(strcmp(topic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
) == 0 ||
894 strcmp(topic
, "last-pb-context-exited") == 0 ||
895 strcmp(topic
, NS_NETWORK_LINK_TOPIC
) == 0,
896 "unexpected observe call");
898 if (!strcmp(topic
, NS_NETWORK_LINK_TOPIC
)) {
899 nsAutoCString converted
= NS_ConvertUTF16toUTF8(data
);
900 if (mResolver
&& !strcmp(converted
.get(), NS_NETWORK_LINK_DATA_CHANGED
)) {
901 mResolver
->FlushCache();
907 // Shutdown and this function are both only called on the UI thread, so we don't
908 // have to worry about mResolver being cleared out from under us.
910 // NOTE Shutting down and reinitializing the service like this is obviously
911 // suboptimal if Observe gets called several times in a row, but we don't
912 // expect that to be the case.
923 nsDNSService::GetAFForLookup(const nsACString
&host
, uint32_t flags
)
925 if (mDisableIPv6
|| (flags
& RESOLVE_DISABLE_IPV6
))
928 MutexAutoLock
lock(mLock
);
930 uint16_t af
= PR_AF_UNSPEC
;
932 if (!mIPv4OnlyDomains
.IsEmpty()) {
933 const char *domain
, *domainEnd
, *end
;
934 uint32_t hostLen
, domainLen
;
936 // see if host is in one of the IPv4-only domains
937 domain
= mIPv4OnlyDomains
.BeginReading();
938 domainEnd
= mIPv4OnlyDomains
.EndReading();
940 nsACString::const_iterator hostStart
;
941 host
.BeginReading(hostStart
);
942 hostLen
= host
.Length();
945 // skip any whitespace
946 while (*domain
== ' ' || *domain
== '\t')
949 // find end of this domain in the string
950 end
= strchr(domain
, ',');
954 // to see if the hostname is in the domain, check if the domain
955 // matches the end of the hostname.
956 domainLen
= end
- domain
;
957 if (domainLen
&& hostLen
>= domainLen
) {
958 const char *hostTail
= hostStart
.get() + hostLen
- domainLen
;
959 if (PL_strncasecmp(domain
, hostTail
, domainLen
) == 0) {
960 // now, make sure either that the hostname is a direct match or
961 // that the hostname begins with a dot.
962 if (hostLen
== domainLen
||
963 *hostTail
== '.' || *(hostTail
- 1) == '.') {
974 if ((af
!= PR_AF_INET
) && (flags
& RESOLVE_DISABLE_IPV4
))
981 nsDNSService::GetDNSCacheEntries(nsTArray
<mozilla::net::DNSCacheEntries
> *args
)
983 NS_ENSURE_TRUE(mResolver
, NS_ERROR_NOT_INITIALIZED
);
984 mResolver
->GetDNSCacheEntries(args
);
989 nsDNSService::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const
991 // Measurement of the following members may be added later if DMD finds it
996 size_t n
= mallocSizeOf(this);
997 n
+= mResolver
->SizeOfIncludingThis(mallocSizeOf
);
998 n
+= mIPv4OnlyDomains
.SizeOfExcludingThisMustBeUnshared(mallocSizeOf
);
999 n
+= mLocalDomains
.SizeOfExcludingThis(mallocSizeOf
);
1003 MOZ_DEFINE_MALLOC_SIZE_OF(DNSServiceMallocSizeOf
)
1006 nsDNSService::CollectReports(nsIHandleReportCallback
* aHandleReport
,
1007 nsISupports
* aData
, bool aAnonymize
)
1009 return MOZ_COLLECT_REPORT(
1010 "explicit/network/dns-service", KIND_HEAP
, UNITS_BYTES
,
1011 SizeOfIncludingThis(DNSServiceMallocSizeOf
),
1012 "Memory used for the DNS service.");